[gegl] ctx: synchronize with upstream



commit 4b492a2ee6b088475ca853d9b8f7bb2a108032e7
Author: Øyvind Kolås <pippin gimp org>
Date:   Thu Jun 16 16:44:51 2022 +0200

    ctx: synchronize with upstream

 operations/common/ctx/ctx.h | 13711 +++++++++++++++++++++++++++---------------
 1 file changed, 8952 insertions(+), 4759 deletions(-)
---
diff --git a/operations/common/ctx/ctx.h b/operations/common/ctx/ctx.h
index 0e1375a81..a5af7093b 100644
--- a/operations/common/ctx/ctx.h
+++ b/operations/common/ctx/ctx.h
@@ -1,4 +1,4 @@
-/* ctx git commit: 9332e7c2 */
+/* ctx git commit: 7b477b2c */
 /* 
  * ctx.h is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -13,9 +13,9 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with ctx; if not, see <https://www.gnu.org/licenses/>.
  *
- * 2012, 2015, 2019, 2020 Øyvind Kolås <pippin gimp org>
+ * 2012, 2015, 2019, 2020, 2021, 2022 Øyvind Kolås <pippin gimp org>
  *
- * ctx is a single header 2d vector graphics processing framework.
+ * ctx is a 2D vector graphics processing processing framework.
  *
  * To use ctx in a project, do the following:
  *
@@ -123,28 +123,36 @@ int  ctx_append_drawlist    (Ctx *ctx, void *data, int length);
 void  ctx_drawlist_clear (Ctx *ctx);
 
 
+const char *ctx_get_font_name (Ctx *ctx, int no);
+
+/* by default both are 0.0 which makes wrapping disabled
+ */
+void ctx_wrap_left (Ctx *ctx, float x);
+void ctx_wrap_right (Ctx *ctx, float x);
+void ctx_line_height (Ctx *ctx, float x);
+
+
 /**
- * ctx_free:
+ * ctx_destroy:
  * @ctx: a ctx context
  */
-void ctx_free (Ctx *ctx);
+void ctx_destroy (Ctx *ctx);
 
 /**
- * ctx_reset:
+ * ctx_start_frame:
  *
- * Prepare for rendering a new frame, this clears the drawlist and initializes
+ * Prepare for rendering a new frame, clears internal drawlist and initializes
  * the state.
  *
  */
-void ctx_reset          (Ctx *ctx);
+void ctx_start_frame    (Ctx *ctx);
 
 /**
- * ctx_flush:
+ * ctx_end_frame:
  *
- * We're done rendering a frame, this does nothing on a context created for a framebuffer, there
- * the drawing commands are immediate.
+ * We're done rendering a frame, this does nothing on a context created for a framebuffer, where drawing 
commands are immediate.
  */
-void ctx_flush          (Ctx *ctx);
+void ctx_end_frame      (Ctx *ctx);
 
 
 /**
@@ -435,7 +443,7 @@ typedef struct _CtxGlyph CtxGlyph;
 CtxGlyph *ctx_glyph_allocate     (int n_glyphs);
 /**
  */
-void      gtx_glyph_free         (CtxGlyph   *glyphs);
+void      ctx_glyph_free         (CtxGlyph   *glyphs);
 /**
  */
 int       ctx_glyph              (Ctx        *ctx, uint32_t unichar, int stroke);
@@ -464,6 +472,8 @@ void ctx_view_box         (Ctx *ctx,
                            float x0, float y0,
                            float w, float h);
 
+void ctx_new_page         (Ctx *ctx);
+
 /**
  * ctx_set_pixel_u8:
  *
@@ -562,6 +572,8 @@ void ctx_define_texture (Ctx *ctx,
                          void       *data,
                          char       *ret_eid);
 
+void ctx_drop_eid (Ctx *ctx, const char *eid);
+
 /* ctx_source_transform:
  */
 void
@@ -586,6 +598,11 @@ float ctx_get_font_size        (Ctx *ctx);
 float ctx_get_miter_limit      (Ctx *ctx);
 int   ctx_get_image_smoothing   (Ctx *ctx);
 float ctx_get_line_dash_offset (Ctx *ctx);
+
+float ctx_get_wrap_left        (Ctx *ctx);
+float ctx_get_wrap_right       (Ctx *ctx);
+float ctx_get_line_height      (Ctx *ctx);
+
 const char *ctx_get_font       (Ctx *ctx);
 float ctx_get_line_width       (Ctx *ctx);
 void  ctx_current_point        (Ctx *ctx, float *x, float *y);
@@ -608,18 +625,45 @@ enum _CtxPixelFormat
   CTX_FORMAT_BGRA8,  // 5
   CTX_FORMAT_RGB565, // 6
   CTX_FORMAT_RGB565_BYTESWAPPED, // 7
-  CTX_FORMAT_RGB332, // 8
+  CTX_FORMAT_RGB332, // 8 // matching flags
   CTX_FORMAT_RGBAF,  // 9
   CTX_FORMAT_GRAYF,  // 10
   CTX_FORMAT_GRAYAF, // 11
-  CTX_FORMAT_GRAY1,  //12 MONO
-  CTX_FORMAT_GRAY2,  //13 DUO
-  CTX_FORMAT_GRAY4,  //14
-  CTX_FORMAT_CMYK8,  //15
-  CTX_FORMAT_CMYKA8, //16 
-  CTX_FORMAT_CMYKAF, //17
-  CTX_FORMAT_YUV420, //18
-  CTX_FORMAT_RGBA8_SEPARATE_ALPHA, // 19
+  CTX_FORMAT_GRAY1,  // 12
+  CTX_FORMAT_CMYK8,  // 13
+  CTX_FORMAT_CMYKAF, // 14
+  CTX_FORMAT_CMYKA8, // 15 
+  CTX_FORMAT_GRAY2,  // 16 // matching flags
+  CTX_FORMAT_YUV420, // 17
+  CTX_FORMAT_GRAY4=32, // to match flags
+  CTX_FORMAT_CBRLE_1,   // CBRLE constant bitrate runlength encoded 1 bpp
+  CTX_FORMAT_CBRLE_2,   // these formats are used internally with the CBRLE
+  CTX_FORMAT_CBRLE_3,   // flag passed to the cb backend. (should be exteneded
+  CTX_FORMAT_CBRLE_4,   // to also apply to the tiled backends).
+  CTX_FORMAT_CBRLE_5,   //
+  CTX_FORMAT_CBRLE_6,   // When used in other backends they determine automatically
+  CTX_FORMAT_CBRLE_7,   // which specific CBRLE format to use, based on available
+  CTX_FORMAT_CBRLE_8,   // memory budget.
+  CTX_FORMAT_CBRLE_9,   // 
+  CTX_FORMAT_CBRLE_10,  // The specific formats are also used for testing and
+  CTX_FORMAT_CBRLE_11,  // improving the visual quality vs performance loss
+  CTX_FORMAT_CBRLE_12,  // when lossy.
+  CTX_FORMAT_CBRLE_13,  //
+  CTX_FORMAT_CBRLE_14,  // 
+  CTX_FORMAT_CBRLE_15,  //
+  CTX_FORMAT_CBRLE_16,  // 
+  CTX_FORMAT_CBRLE_17,  //  
+  CTX_FORMAT_CBRLE_18,  //  
+  CTX_FORMAT_CBRLE_19,  //  
+  CTX_FORMAT_CBRLE_20,  //  
+  CTX_FORMAT_CBRLE_21,  //  
+  CTX_FORMAT_CBRLE_22,  //  
+  CTX_FORMAT_CBRLE_23,  //  
+  CTX_FORMAT_CBRLE_24,  //  
+  CTX_FORMAT_CBRLE_32,  //  
+  CTX_FORMAT_CBRLE,     // 
+  CTX_FORMAT_BGRA8Z,    // 
+  CTX_FORMAT_RGBA8_SEPARATE_ALPHA, //
 };
 typedef enum   _CtxPixelFormat CtxPixelFormat;
 
@@ -683,13 +727,13 @@ typedef struct _CtxDrawlist CtxDrawlist;
 typedef void (*CtxFullCb) (CtxDrawlist *drawlist, void *data);
 
 int ctx_pixel_format_bits_per_pixel (CtxPixelFormat format); // bits per pixel
-int ctx_pixel_format_get_stride (CtxPixelFormat format, int width);
-int ctx_pixel_format_components (CtxPixelFormat format);
+int ctx_pixel_format_get_stride     (CtxPixelFormat format, int width);
+int ctx_pixel_format_components     (CtxPixelFormat format);
 
-void _ctx_set_store_clear (Ctx *ctx);
+void _ctx_set_store_clear    (Ctx *ctx);
 void _ctx_set_transformation (Ctx *ctx, int transformation);
 
-Ctx *ctx_hasher_new (int width, int height, int cols, int rows);
+Ctx *ctx_hasher_new          (int width, int height, int cols, int rows, CtxDrawlist *drawlist);
 uint32_t ctx_hasher_get_hash (Ctx *ctx, int col, int row);
 
 int ctx_utf8_strlen (const char *s);
@@ -735,10 +779,10 @@ int ctx_utf8_strlen (const char *s);
 #endif
 
 #if CTX_SDL
-#define ctx_mutex_t            SDL_mutex
-#define ctx_create_mutex()     SDL_CreateMutex()
-#define ctx_lock_mutex(a)      SDL_LockMutex(a)
-#define ctx_unlock_mutex(a)    SDL_UnlockMutex(a)
+#define ctx_mutex_t           SDL_mutex
+#define ctx_create_mutex()    SDL_CreateMutex()
+#define ctx_lock_mutex(a)     SDL_LockMutex(a)
+#define ctx_unlock_mutex(a)   SDL_UnlockMutex(a)
 #else
 #define ctx_mutex_t           int
 #define ctx_create_mutex()    NULL
@@ -747,36 +791,42 @@ int ctx_utf8_strlen (const char *s);
 #endif
 
 
-typedef enum CtxCbFlags {
-  CTX_CB_DEFAULTS   = 0,
-  CTX_CB_GRAY       = 1 << 0,
-  CTX_CB_HASH_CACHE = 1 << 1,
-  CTX_CB_332        = 1 << 2, // might do a 332 render
-                               // that is tear-free but slower
-                               // before queueing slotted redraws
-                               // of higher quality tiles
-                               // this is a pre-amble to eink modes
-                               //
-  CTX_CB_CYCLE_BUF  = 1 << 4, // if set then we free buffers after each
-                               // use, higher risk of memory fragmentation
-                               // but making each frame blit a memory use peak
-
-  CTX_CB_DAMAGE_CONTROL = 1 << 5,
-  CTX_CB_SHOW_FPS   = 1 << 6,
-  CTX_CB_AUTO_332   = 1 << 7,
-} CtxCbFlags;
+/* these are configuration flags for a ctx renderer, not all
+ * flags are applicable for all rendereres, the cb backend
+ * has the widest support currently.
+ */
+typedef enum CtxFlags {
+  //CTX_FLAG_DEFAULTS   = 0,
+  CTX_FLAG_GRAY8        = 1 << 0, // use GRAY8, implies LOWFI
+  CTX_FLAG_HASH_CACHE   = 1 << 1, // use a hashcache to determine which parts to redraw, implied by LOWFI
+  CTX_FLAG_LOWFI        = 1 << 2, // use lower res and color fidelity preview renders
+  CTX_FLAG_RGB332       = 1 << 3, // 8bit indexed with fixed palette, implies lowfi
+  CTX_FLAG_GRAY2        = 1 << 4, // 4 level grayscale, implies lowfi
+  CTX_FLAG_GRAY4        = 1 << 5, // 16 level grayscale, implies lowfi
+  //CTX_FLAG_DAMAGE_CONTROL = 1 << 6,
+  CTX_FLAG_SHOW_FPS     = 1 << 7, // possibly show fps in titlebar or printed to a log
+  CTX_FLAG_KEEP_DATA    = 1 << 8, // keep existing fb-data instead of doing an initial clear
+  CTX_FLAG_INTRA_UPDATE = 1 << 9,
+  CTX_FLAG_STAY_LOW     = 1 << 10,  // stay with the color fidelity drop in lowfi
+  CTX_FLAG_CBRLE        = 1 << 11   // use possibly lossy RLE encoded scanlines with constant bitrate
+} CtxFlags;
 
 
 Ctx *ctx_new_cb (int width, int height, CtxPixelFormat format,
                  void (*set_pixels) (Ctx *ctx, void *user_data, 
-                                     int x, int y, int w, int h, void *buf),
-                 void (*update_fb) (Ctx *ctx, void *user_data),
-                 void *user_data,
+                                     int x, int y, int w, int h, void *buf,
+                                     int buf_size),
+                 void *set_pixels_user_data,
+                 int (*update_fb) (Ctx *ctx, void *user_data),
+                 void *update_fb_user_data,
                  int   memory_budget,
                  void *scratch_fb,
                  int flags);
 void ctx_cb_set_flags (Ctx *ctx, int flags);
 int ctx_cb_get_flags  (Ctx *ctx);
+void ctx_cb_set_memory_budget (Ctx *ctx, int memory_budget);
+void
+ctx_cb_extent (Ctx *ctx, float *x0, float *y0, float *x1, float *y1);
 
 #if CTX_TFT_ESPI
 Ctx *ctx_new_tft (TFT_eSPI *tft, int memory_budget, void *scratch_fb, int flags);
@@ -800,7 +850,6 @@ void  ctx_render_cairo  (Ctx *ctx, cairo_t *cr);
 Ctx * ctx_new_for_cairo (cairo_t *cr);
 #endif
 
-/* free with free() */
 char *ctx_render_string (Ctx *ctx, int longform, int *retlen);
 
 void ctx_render_stream  (Ctx *ctx, FILE *stream, int formatter);
@@ -841,7 +890,6 @@ typedef enum
   CTX_COMPOSITE_DESTINATION_OUT  = 288,
   CTX_COMPOSITE_DESTINATION_ATOP = 320,
   CTX_COMPOSITE_XOR              = 352,
-
   CTX_COMPOSITE_ALL              = (32+64+128+256)
 #else
   CTX_COMPOSITE_SOURCE_OVER      =0,
@@ -996,11 +1044,13 @@ void  ctx_text          (Ctx        *ctx,
 void  ctx_text_stroke   (Ctx        *ctx,
                          const char *string);
 
+// XXX do not use?
 void  ctx_fill_text     (Ctx        *ctx,
                          const char *string,
                          float       x,
                          float       y);
 
+// XXX do not use?
 void  ctx_stroke_text   (Ctx        *ctx,
                          const char *string,
                          float       x,
@@ -1065,7 +1115,7 @@ float ctx_get_float (Ctx *ctx, uint32_t hash);
 void ctx_set_float (Ctx *ctx, uint32_t hash, float value);
 
 unsigned long ctx_ticks (void);
-void ctx_flush (Ctx *ctx);
+void ctx_end_frame (Ctx *ctx);
 
 void ctx_set_clipboard (Ctx *ctx, const char *text);
 char *ctx_get_clipboard (Ctx *ctx);
@@ -1126,6 +1176,8 @@ typedef enum _CtxEventType CtxEventType;
 #define CTX_CLICK   CTX_PRESS   // SHOULD HAVE MORE LOGIC
 typedef struct _CtxClient CtxClient;
 
+
+
 struct _CtxEvent {
   CtxEventType  type;
   uint32_t time;
@@ -1262,8 +1314,6 @@ int ctx_key_up    (Ctx *ctx, unsigned int keyval,
                    const char *string, uint32_t time);
 int ctx_key_press (Ctx *ctx, unsigned int keyval,
                    const char *string, uint32_t time);
-
-
 int ctx_scrolled  (Ctx *ctx, float x, float y, CtxScrollDirection scroll_direction, uint32_t time);
 void ctx_incoming_message (Ctx *ctx, const char *message, long time);
 int ctx_pointer_motion    (Ctx *ctx, float x, float y, int device_no, uint32_t time);
@@ -1272,6 +1322,169 @@ int ctx_pointer_press     (Ctx *ctx, float x, float y, int device_no, uint32_t t
 int ctx_pointer_drop      (Ctx *ctx, float x, float y, int device_no, uint32_t time,
                            char *string);
 
+
+
+int   ctx_client_resize        (Ctx *ctx, int id, int width, int height);
+void  ctx_client_set_font_size (Ctx *ctx, int id, float font_size);
+float ctx_client_get_font_size (Ctx *ctx, int id);
+void  ctx_client_maximize      (Ctx *ctx, int id);
+
+
+#if 1 // CTX_VT
+
+typedef struct _VT VT;
+void vt_feed_keystring    (VT *vt, CtxEvent *event, const char *str);
+void vt_paste             (VT *vt, const char *str);
+char *vt_get_selection    (VT *vt);
+long vt_rev               (VT *vt);
+int  vt_has_blink         (VT *vt);
+int ctx_vt_had_alt_screen (VT *vt);
+
+int ctx_clients_handle_events (Ctx *ctx);
+
+typedef struct _CtxList CtxList;
+CtxList *ctx_clients (Ctx *ctx);
+
+void ctx_set_fullscreen (Ctx *ctx, int val);
+int ctx_get_fullscreen (Ctx *ctx);
+
+typedef struct _CtxBuffer CtxBuffer;
+CtxBuffer *ctx_buffer_new_for_data (void *data, int width, int height,
+                                    int stride,
+                                    CtxPixelFormat pixel_format,
+                                    void (*freefunc) (void *pixels, void *user_data),
+                                    void *user_data);
+
+typedef enum CtxBackendType {
+  CTX_BACKEND_NONE,
+  CTX_BACKEND_CTX,
+  CTX_BACKEND_RASTERIZER,
+  CTX_BACKEND_HASHER,
+  CTX_BACKEND_HEADLESS,
+  CTX_BACKEND_TERM,
+  CTX_BACKEND_FB,
+  CTX_BACKEND_KMS,
+  CTX_BACKEND_TERMIMG,
+  CTX_BACKEND_CAIRO,
+  CTX_BACKEND_SDL,
+  CTX_BACKEND_DRAWLIST,
+} CtxBackendType;
+
+CtxBackendType ctx_backend_type (Ctx *ctx);
+
+static inline int ctx_backend_is_tiled (Ctx *ctx)
+{
+  switch (ctx_backend_type (ctx))
+  {
+    case CTX_BACKEND_FB:
+    case CTX_BACKEND_SDL:
+    case CTX_BACKEND_KMS:
+    case CTX_BACKEND_HEADLESS:
+      return 1;
+    default:
+      return 0;
+  }
+}
+
+#endif
+
+typedef enum CtxClientFlags {
+  ITK_CLIENT_UI_RESIZABLE = 1<<0,
+  ITK_CLIENT_CAN_LAUNCH   = 1<<1,
+  ITK_CLIENT_MAXIMIZED    = 1<<2,
+  ITK_CLIENT_ICONIFIED    = 1<<3,
+  ITK_CLIENT_SHADED       = 1<<4,
+  ITK_CLIENT_TITLEBAR     = 1<<5,
+  ITK_CLIENT_LAYER2       = 1<<6,  // used for having a second set
+                                   // to draw - useful for splitting
+                                   // scrolled and HUD items
+                                   // with HUD being LAYER2
+                                  
+  ITK_CLIENT_KEEP_ALIVE   = 1<<7,  // do not automatically
+  ITK_CLIENT_FINISHED     = 1<<8,  // do not automatically
+                                   // remove after process quits
+  ITK_CLIENT_PRELOAD      = 1<<9
+} CtxClientFlags;
+typedef void (*CtxClientFinalize)(CtxClient *client, void *user_data);
+
+int ctx_client_id (CtxClient *client);
+int ctx_client_flags (CtxClient *client);
+VT *ctx_client_vt (CtxClient *client);
+void ctx_client_add_event (CtxClient *client, CtxEvent *event);
+const char *ctx_client_title (CtxClient *client);
+CtxClient *ctx_client_find (Ctx *ctx, const char *label); // XXX really unstable api?
+
+
+void *ctx_client_userdata (CtxClient *client);
+
+void ctx_client_quit (CtxClient *client);
+CtxClient *vt_get_client (VT *vt);
+CtxClient *ctx_client_new (Ctx *ctx,
+                           const char *commandline,
+                           int x, int y, int width, int height,
+                           float font_size,
+                           CtxClientFlags flags,
+                           void *user_data,
+                           CtxClientFinalize client_finalize);
+
+CtxClient *ctx_client_new_argv (Ctx *ctx, char **argv, int x, int y, int width, int height, float font_size, 
CtxClientFlags flags, void *user_data,
+                CtxClientFinalize client_finalize);
+int ctx_clients_need_redraw (Ctx *ctx);
+
+CtxClient *ctx_client_new_thread (Ctx *ctx, void (*start_routine)(Ctx *ctx, void *user_data),
+                                  int x, int y, int width, int height, float font_size, CtxClientFlags 
flags, void *user_data, CtxClientFinalize finalize);
+
+extern float ctx_shape_cache_rate;
+extern int _ctx_max_threads;
+
+CtxEvent *ctx_event_copy (CtxEvent *event);
+
+void  ctx_client_move         (Ctx *ctx, int id, int x, int y);
+void  ctx_client_shade_toggle (Ctx *ctx, int id);
+float ctx_client_min_y_pos    (Ctx *ctx);
+float ctx_client_max_y_pos    (Ctx *ctx);
+void ctx_client_paste (Ctx *ctx, int id, const char *str);
+char  *ctx_client_get_selection        (Ctx *ctx, int id);
+
+void  ctx_client_rev_inc      (CtxClient *client);
+long  ctx_client_rev          (CtxClient *client);
+
+int   ctx_clients_active      (Ctx *ctx);
+
+CtxClient *ctx_client_by_id (Ctx *ctx, int id);
+
+int ctx_clients_draw (Ctx *ctx, int layer2);
+
+void ctx_client_feed_keystring (CtxClient *client, CtxEvent *event, const char *str);
+// need not be public?
+void ctx_client_register_events (CtxClient *client, Ctx *ctx, double x0, double y0);
+
+void ctx_client_remove (Ctx *ctx, CtxClient *client);
+
+int  ctx_client_height           (Ctx *ctx, int id);
+int  ctx_client_x                (Ctx *ctx, int id);
+int  ctx_client_y                (Ctx *ctx, int id);
+void ctx_client_raise_top        (Ctx *ctx, int id);
+void ctx_client_lower_bottom     (Ctx *ctx, int id);
+void ctx_client_iconify          (Ctx *ctx, int id);
+int  ctx_client_is_iconified     (Ctx *ctx, int id);
+void ctx_client_uniconify        (Ctx *ctx, int id);
+void ctx_client_maximize         (Ctx *ctx, int id);
+int  ctx_client_is_maximized     (Ctx *ctx, int id);
+void ctx_client_unmaximize       (Ctx *ctx, int id);
+void ctx_client_maximized_toggle (Ctx *ctx, int id);
+void ctx_client_shade            (Ctx *ctx, int id);
+int  ctx_client_is_shaded        (Ctx *ctx, int id);
+void ctx_client_unshade          (Ctx *ctx, int id);
+void ctx_client_toggle_maximized (Ctx *ctx, int id);
+void ctx_client_shade_toggle     (Ctx *ctx, int id);
+void ctx_client_move             (Ctx *ctx, int id, int x, int y);
+int  ctx_client_resize           (Ctx *ctx, int id, int width, int height);
+void ctx_client_set_opacity      (Ctx *ctx, int id, float opacity);
+float ctx_client_get_opacity     (Ctx *ctx, int id);
+void ctx_client_set_title        (Ctx *ctx, int id, const char *title);
+const char *ctx_client_get_title (Ctx *ctx, int id);
+
 typedef enum
 {
   CTX_CONT             = '\0', // - contains args from preceding entry
@@ -1311,12 +1524,14 @@ typedef enum
   CTX_REL_QUAD_TO_REL_QUAD_TO   = '8', // cx1 x1 cy1 y1 cx1 x2 cy1 y1 -- s8
   CTX_REL_QUAD_TO_S16           = '9', // cx1 cy1 x y                 - s16
                    //     :    UNUSED
-  CTX_FLUSH            = ';',
+  CTX_END_FRAME        = ';',
                    //     <    UNUSED
                    //     =    UNUSED/RESERVED
                    //     >    UNUSED
                    //     ?    UNUSED
 
+  CTX_DEFINE_FONT      = 15,
+
   CTX_DEFINE_GLYPH     = '@', // unichar width - u32
   CTX_ARC_TO           = 'A', // x1 y1 x2 y2 radius
   CTX_ARC              = 'B', // x y radius angle1 angle2 direction
@@ -1338,7 +1553,7 @@ typedef enum
   CTX_VIEW_BOX         = 'R', // x y width height
   CTX_SMOOTH_TO        = 'S', // cx cy x y
   CTX_SMOOTHQ_TO       = 'T', // x y
-  CTX_RESET            = 'U', //
+  CTX_START_FRAME      = 'U', // XXX does this belong here?
   CTX_VER_LINE_TO      = 'V', // y
   CTX_APPLY_TRANSFORM  = 'W', // a b c d e f g h i j - for set_transform combine with identity
   CTX_EXIT             = 'X', //
@@ -1423,7 +1638,11 @@ typedef enum
   CTX_IMAGE_SMOOTHING  = 144, // kS
   CTX_LINE_DASH_OFFSET = 145, // kD lineDashOffset
 
+
   CTX_EXTEND           = 146, // ke u32 extend mode, default=0
+  CTX_WRAP_LEFT        = 147, // kL
+  CTX_WRAP_RIGHT       = 148, // kR
+  CTX_LINE_HEIGHT      = 149, // kH
                               //
   CTX_STROKE_RECT      = 200, // strokeRect - only exist in long form
   CTX_FILL_RECT        = 201, // fillRect   - only exist in long form
@@ -1473,7 +1692,8 @@ struct
     struct
     {
       uint8_t code;
-      float pad;
+      uint32_t next_active_mask; // the tilehasher active flags for next
+                                 // drawing command
       float pad2;
       uint8_t code_data;
       uint32_t stringlen;
@@ -1991,8 +2211,8 @@ struct _CtxBackend
 {
   Ctx                      *ctx;
   void  (*process)         (Ctx *ctx, CtxCommand *entry);
-  void  (*reset)           (Ctx *ctx);
-  void  (*flush)           (Ctx *ctx);
+  void  (*start_frame)     (Ctx *ctx);
+  void  (*end_frame)       (Ctx *ctx);
 
   void  (*set_windowtitle) (Ctx *ctx, const char *text);
 
@@ -2002,15 +2222,21 @@ struct _CtxBackend
   void  (*get_event_fds)   (Ctx *ctx, int *fd, int *count);
   char *(*get_clipboard)   (Ctx *ctx);
   void  (*set_clipboard)   (Ctx *ctx, const char *text);
-  void (*free)             (void *backend); /* the free pointers are abused as the differentiatior
+  void  (*destroy)         (void *backend); /* the free pointers are abused as the differentiatior
                                                between different backends   */
+  CtxFlags                  flags;
   void                     *user_data; // not used by ctx core
 };
 
 typedef struct _CtxIterator CtxIterator;
 
-CtxIterator *
+void
+ctx_logo (Ctx *ctx, float x, float y, float dim);
+
+/* to be freed with ctx_free */
+CtxDrawlist *
 ctx_current_path (Ctx *ctx);
+
 void
 ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2);
 CtxCommand *ctx_iterator_next (CtxIterator *iterator);
@@ -2067,14 +2293,6 @@ typedef enum
   // RGB  device and  RGB  ?
 } CtxColorModel;
 
-enum _CtxAntialias
-{
-  CTX_ANTIALIAS_DEFAULT, //
-  CTX_ANTIALIAS_NONE, // non-antialiased
-  CTX_ANTIALIAS_FAST, // aa 3    // deprected or is default equal to this now?
-  CTX_ANTIALIAS_GOOD, // aa 5    // this should perhaps still be 5?
-};
-typedef enum _CtxAntialias CtxAntialias;
 
 enum _CtxCursor
 {
@@ -2108,8 +2326,6 @@ void ctx_listen_set_cursor (Ctx      *ctx,
  */
 void         ctx_set_cursor (Ctx *ctx, CtxCursor cursor);
 CtxCursor    ctx_get_cursor (Ctx *ctx);
-void         ctx_set_antialias (Ctx *ctx, CtxAntialias antialias);
-CtxAntialias ctx_get_antialias (Ctx *ctx);
 void         ctx_set_render_threads   (Ctx *ctx, int n_threads);
 int          ctx_get_render_threads   (Ctx *ctx);
 
@@ -2161,9 +2377,6 @@ void ctx_colorspace (Ctx           *ctx,
 
 
 
-
-
-
 void
 ctx_parser_set_size (CtxParser *parser,
                      int        width,
@@ -2183,12 +2396,12 @@ ctx_get_contents2 (const char     *path,
                    long           *length,
                    long            max_len);
 
-void ctx_parser_free (CtxParser *parser);
+void ctx_parser_destroy (CtxParser *parser);
 typedef struct _CtxSHA1 CtxSHA1;
 
 void
 ctx_bin2base64 (const void *bin,
-                int         bin_length,
+                size_t      bin_length,
                 char       *ascii);
 int
 ctx_base642bin (const char    *ascii,
@@ -2234,75 +2447,15 @@ typedef enum {
   CTX_MEDIA_TYPE_APPLICATION,
 } CtxMediaTypeClass;
 
+int ctx_media_type_is_text (const char *media_type);
 CtxMediaTypeClass ctx_media_type_class (const char *media_type);
 
 
 float ctx_term_get_cell_width (Ctx *ctx);
 float ctx_term_get_cell_height (Ctx *ctx);
 
-
-void ctx_logo (Ctx *ctx, float x, float y, float dim);
-
-
-
-#if 1 // CTX_VT
-
-typedef struct _VT VT;
-void vt_feed_keystring    (VT *vt, CtxEvent *event, const char *str);
-void vt_paste             (VT *vt, const char *str);
-char *vt_get_selection    (VT *vt);
-long vt_rev               (VT *vt);
-int  vt_has_blink         (VT *vt);
-int ctx_vt_had_alt_screen (VT *vt);
-
-int ctx_clients_handle_events (Ctx *ctx);
-
-typedef struct _CtxList CtxList;
-CtxList *ctx_clients (Ctx *ctx);
-
-void ctx_set_fullscreen (Ctx *ctx, int val);
-int ctx_get_fullscreen (Ctx *ctx);
-
-typedef struct _CtxBuffer CtxBuffer;
-CtxBuffer *ctx_buffer_new_for_data (void *data, int width, int height,
-                                    int stride,
-                                    CtxPixelFormat pixel_format,
-                                    void (*freefunc) (void *pixels, void *user_data),
-                                    void *user_data);
-
-typedef enum CtxBackendType {
-  CTX_BACKEND_NONE,
-  CTX_BACKEND_CTX,
-  CTX_BACKEND_RASTERIZER,
-  CTX_BACKEND_HASHER,
-  CTX_BACKEND_HEADLESS,
-  CTX_BACKEND_TERM,
-  CTX_BACKEND_FB,
-  CTX_BACKEND_KMS,
-  CTX_BACKEND_TERMIMG,
-  CTX_BACKEND_CAIRO,
-  CTX_BACKEND_SDL,
-  CTX_BACKEND_DRAWLIST,
-} CtxBackendType;
-
-CtxBackendType ctx_backend_type (Ctx *ctx);
-
-static inline int ctx_backend_is_tiled (Ctx *ctx)
-{
-  switch (ctx_backend_type (ctx))
-  {
-    case CTX_BACKEND_FB:
-    case CTX_BACKEND_SDL:
-    case CTX_BACKEND_KMS:
-    case CTX_BACKEND_HEADLESS:
-      return 1;
-    default:
-      return 0;
-  }
-}
-
-#endif
-
+Ctx * ctx_new_pdf (const char *path, float width, float height);
+void ctx_render_pdf (Ctx *ctx, const char *path);
 
 #ifndef CTX_CODEC_CHAR
 //#define CTX_CODEC_CHAR '\035'
@@ -2368,6 +2521,8 @@ void        ctx_string_insert_unichar (CtxString *string, int pos, uint32_t unic
 void        ctx_string_replace_unichar (CtxString *string, int pos, uint32_t unichar);
 void        ctx_string_remove         (CtxString *string, int pos);
 char       *ctx_strdup_printf         (const char *format, ...);
+void        ctx_string_append_int     (CtxString *string, int val);
+void        ctx_string_append_float   (CtxString *string, float val);
 
 #ifndef TRUE
 #define TRUE 1
@@ -2381,2041 +2536,2006 @@ char       *ctx_strdup_printf         (const char *format, ...);
 #define _CTX_INTERNAL_FONT_
 
 #ifndef CTX_FONT_ascii
-/* this is a ctx encoded font based on DejaVuSans.ttf */
-/* CTX_SUBDIV:8  CTX_BAKE_FONT_SIZE:160 */
-/* glyphs covered: 
-
+/* glyph index: 
  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi
   jklmnopqrstuvwxyz{|}~  */
 static const struct __attribute__ ((packed)) {uint8_t code; uint32_t a; uint32_t b;}
 ctx_font_ascii[]={
-{'@', 0x00000020, 0x00002bb0},/*                 x-advance: 43.687500 */
-{'@', 0x00000021, 0x00003719},/*        !        x-advance: 55.097656 */
-{'M', 0x41a5e7f2, 0xc1886037},
-{'l', 0x4159fc90, 0x00000000},
-{'4', 0x00880000, 0x0000ff94},
-{'6', 0xff780000, 0xfd670000},
-{'l', 0x4159fc90, 0x00000000},
-{'l', 0x00000000, 0x422fd6c4},
-{'l', 0xbfabcfe0, 0x41bfad86},
-{'l', 0xc12df5b2, 0x00000000},
-{'l', 0xbfb46710, 0xc1bfad86},
-{'l', 0x00000000, 0xc22fd6c4},
-{'@', 0x00000022, 0x00003f38},/*        "        x-advance: 63.218750 */
-{'M', 0x41c50c07, 0xc2c86716},
-{'l', 0x00000000, 0x4214fe48},
-{'4', 0x0000ffa5, 0xfed70000},
-{'6', 0x0000005b, 0x000000ca},
-{'l', 0x00000000, 0x4214fe48},
-{'l', 0xc1368ce4, 0x00000000},
-{'l', 0x00000000, 0xc214fe48},
-{'l', 0x41368ce4, 0x00000000},
-{'@', 0x00000023, 0x0000732a},/*        #        x-advance: 115.164062 */
-{'M', 0x428c8973, 0xc271e113},
-{'l', 0xc19c3dda, 0x00000000},
-{'4', 0x00b3ffd3, 0x0000009d},
-{'6', 0xff4d002c, 0xfecfffb0},
-{'l', 0xc0df5b10, 0x41ded19c},
-{'l', 0x419cc74c, 0x00000000},
-{'l', 0x40e180e0, 0xc1ded19c},
-{'l', 0x412bcfe8, 0x00000000},
-{'l', 0xc0dd3540, 0x41ded19c},
-{'l', 0x41a78448, 0x00000000},
-{'l', 0x00000000, 0x41255e7c},
-{'l', 0xc1bc74d4, 0x00000000},
-{'l', 0xc0b01b80, 0x41b35430},
-{'l', 0x41aabd00, 0x00000000},
-{'l', 0x00000000, 0x41244b9a},
-{'l', 0xc1bfad88, 0x00000000},
-{'l', 0xc0df5b10, 0x41de4829},
-{'l', 0xc12bcfe4, 0x00000000},
-{'l', 0x40dd3540, 0xc1de4829},
-{'l', 0xc19d50c0, 0x00000000},
-{'l', 0xc0dd3540, 0x41de4829},
-{'l', 0xc12ce2ca, 0x00000000},
-{'l', 0x40df5b10, 0xc1de4829},
-{'l', 0xc1a920a5, 0x00000000},
-{'l', 0x00000000, 0xc1244b9a},
-{'l', 0x41bcfe48, 0x00000000},
-{'l', 0x40b46718, 0xc1b35430},
-{'l', 0xc1ace2cb, 0x00000000},
-{'l', 0x00000000, 0xc1255e7c},
-{'l', 0x41c1d353, 0x00000000},
-{'l', 0x40db0f78, 0xc1ded19c},
-{'l', 0x412df5b0, 0x00000000},
-{'@', 0x00000024, 0x00005773},/*        $        x-advance: 87.449219 */
-{'M', 0x4239c595, 0x41a19c59},
-{'4', 0x0000ffcb, 0xff5f0000},
-{'q', 0xc0e180d8, 0xbe09731d},
-{0, 0xc16180dc, 0xbfce2cac},
-{'9', 0xfff4ffc8, 0xffdcff8f},
-{'l', 0x00000000, 0xc14149e1},
-{'q', 0x40db0f76, 0x4089731e},
-{0, 0x415d3543, 0x40d05278},
-{'9', 0x00110038, 0x00110073},
-{'l', 0x00000000, 0xc1f4d50c},
-{'q', 0xc16d50c2, 0xc01aa180},
-{0, 0xc1ace2cb, 0xc10301b8},
-{'q', 0xc0d6c3de, 0xc0b8b2b0},
-{0, 0xc0d6c3de, 0xc17d6c3c},
-{'q', 0x00000000, 0xc12f0898},
-{0, 0x40ea180e, 0xc189fc90},
-{'9', 0xffce003a, 0xffc700a8},
-{'4', 0xff820000, 0x00000035},
-{'l', 0x00000000, 0x417920a8},
-{'8', 0x0a600231, 0x165b082e},
-{'l', 0x00000000, 0x413beb60},
-{'8', 0xdea5ead4, 0xf2a0f4d2},
-{'l', 0x00000000, 0x41e54302},
-{'q', 0x4173c228, 0x401655f0},
-{0, 0x41b35432, 0x41063a6c},
-{'q', 0x40e5cc70, 0x40c149e0},
-{0, 0x40e5cc70, 0x4184149e},
-{'q', 0x00000000, 0x413579fc},
-{0, 0xc0f4d510, 0x418f5b0f},
-{'9', 0x0034ffc4, 0x003cff51},
-{'6', 0x00a20000, 0xfdc1ffcb},
-{'l', 0x00000000, 0xc1dc2258},
-{'8', 0x23a106c2, 0x4be01ce0},
-{'8', 0x471e2e00, 0x2561191e},
-{'m', 0x40d6c3d8, 0x414e2cac},
-{'l', 0x00000000, 0x41e87bb4},
-{'8', 0xda66f744, 0xb322e322},
-{'8', 0xb5dfd100, 0xd898e5e0},
-{'@', 0x00000025, 0x0000829a},/*        %        x-advance: 130.601562 */
-{'M', 0x42c7dda3, 0xc2306037},
-{'8', 0x27b700d2, 0x6ee627e6},
-{'8', 0x6e1a4500, 0x2749271a},
-{'8', 0xd947002d, 0x921ad81a},
-{'8', 0x92e6ba00, 0xd8b9d8e6},
-{'m', 0x00000000, 0xc1086034},
-{'q', 0x4129aa18, 0x00000000},
-{0, 0x4186c3dc, 0x40ec3dd8},
-{'q', 0x40c7bb50, 0x40ec3dd8},
-{0, 0x40c7bb50, 0x419f768c},
-{'q', 0x00000000, 0x4148ce2d},
-{0, 0xc0c9e120, 0x419f768d},
-{'q', 0xc0c7bb40, 0x40ea180d},
-{0, 0xc1863a68, 0x40ea180d},
-{'q', 0xc12bcfe8, 0x34000000},
-{0, 0xc187d6c4, 0xc0ea180d},
-{'q', 0xc0c7bb40, 0xc0ec3dda},
-{0, 0xc0c7bb40, 0xc19f768d},
-{'q', 0x00000000, 0xc149e114},
-{0, 0x40c7bb40, 0xc19f768c},
-{'9', 0xffc50032, 0xffc50087},
-{'m', 0xc28a8603, 0xc2237d6c},
-{'8', 0x28b700d2, 0x6de627e6},
-{'8', 0x6e1a4600, 0x2749271a},
-{'8', 0xd949002e, 0x921ad91a},
-{'8', 0x93e6bb00, 0xd8b7d8e6},
-{'m', 0x42726a86, 0xc1086038},
-{'l', 0x412bcfe0, 0x00000000},
-{'4', 0x033ffe0b, 0x0000ffab},
-{'6', 0xfcc101f5, 0x0000fe1c},
-{'q', 0x4129aa14, 0x00000000},
-{0, 0x41874d50, 0x40ec3de0},
-{'q', 0x40c9e110, 0x40ea1800},
-{0, 0x40c9e110, 0x419eed18},
-{'q', 0x00000000, 0x414af3f8},
-{0, 0xc0c9e110, 0x41a00000},
-{'q', 0xc0c7bb48, 0x40ea1808},
-{0, 0xc1874d51, 0x40ea1808},
-{'q', 0xc12abcfe, 0x00000000},
-{0, 0xc1874d51, 0xc0ea1808},
-{'q', 0xc0c59579, 0xc0ec3dd8},
-{0, 0xc0c59579, 0xc1a00000},
-{'q', 0x00000000, 0xc147bb48},
-{0, 0x40c7bb47, 0xc19eed18},
-{'q', 0x40c7bb46, 0xc0ec3de0},
-{0, 0x4186c3de, 0xc0ec3de0},
-{'@', 0x00000026, 0x00006b2e},/*        &        x-advance: 107.179688 */
-{'M', 0x4205b0f7, 0xc257920a},
-{'8', 0x56b92bd0, 0x5aea2aea},
-{'q', 0x00000000, 0x411cc74e},
-{0, 0x40e3a6a8, 0x41827845},
-{'q', 0x40e3a6a8, 0x40d05278},
-{0, 0x418ed19c, 0x40d05278},
-{'8', 0xf05f0033, 0xcd53ef2c},
-{'6', 0xfeddfee4, 0xffc4004b},
-{'l', 0x42086037, 0x420b98e9},
-{'q', 0x407d6c40, 0xc0bf2410},
-{0, 0x40c59570, 0xc14c06e0},
-{'9', 0xffca0011, 0xff8d0014},
-{'l', 0x4147bb40, 0x00000000},
-{'q', 0xbf4e2c80, 0x410dbeb8},
-{0, 0xc0897310, 0x418c225c},
-{'9', 0x0045ffe5, 0x0088ffb3},
-{'4', 0x00990095, 0x0000ff79},
-{'l', 0xc1198e98, 0xc11dda33},
-{'q', 0xc0df5b10, 0x40bf2414},
-{0, 0xc16a1810, 0x410ed19c},
-{'q', 0xc0f4d510, 0x4038b2ae},
-{0, 0xc1838b2c, 0x4038b2ae},
-{'q', 0xc181655e, 0x34000000},
-{0, 0xc1d38b2a, 0xc1131d35},
-{'q', 0xc1244b99, 0xc114301c},
-{0, 0xc1244b99, 0xc1bd87bb},
-{'q', 0x00000000, 0xc109731e},
-{0, 0x408fe482, 0xc180dbeb},
-{'q', 0x408fe484, 0xc0f2af40},
-{0, 0x4157d6c4, 0xc163a6a8},
-{'8', 0xbdd9dfe7, 0xbef3dff3},
-{'q', 0x00000000, 0xc12df5b0},
-{0, 0x40ee63a4, 0xc18b98e8},
-{'q', 0x40ee63a8, 0xc0d49e10},
-{0, 0x419e63a6, 0xc0d49e10},
-{'8', 0x0958002c, 0x1c5a092c},
-{'l', 0x00000000, 0x41436fb0},
-{'8', 0xdaa7e7d2, 0xf3b2f3d6},
-{'8', 0x1ea500c8, 0x4cde1dde},
-{'8', 0x370f1b00, 0x4d401b10},
-{'@', 0x00000027, 0x000025c9},/*        '        x-advance: 37.785156 */
-{'M', 0x41c50c07, 0xc2c86716},
-{'l', 0x00000000, 0x4214fe48},
-{'l', 0xc1368ce3, 0x00000000},
-{'l', 0x00000000, 0xc214fe48},
-{'l', 0x41368ce3, 0x00000000},
-{'@', 0x00000028, 0x0000359f},/*        (        x-advance: 53.621094 */
-{'M', 0x422a7844, 0xc2d09732},
-{'q', 0xc10fe480, 0x4176fae0},
-{0, 0xc155b0f6, 0x41f44b9c},
-{'q', 0xc08b98e8, 0x41719c54},
-{0, 0xc08b98e8, 0x41f4d50a},
-{'q', 0x00000000, 0x41780dbe},
-{0, 0x408b98e8, 0x41f5e7f2},
-{'9', 0x00790023, 0x00f4006a},
-{'l', 0xc12bcfe2, 0x00000000},
-{'q', 0xc12112e6, 0xc17c5958},
-{0, 0xc1719c5a, 0xc1f80dbf},
-{'q', 0xc09eed18, 0xc173c224},
-{0, 0xc09eed18, 0xc1f225cc},
-{'q', 0x00000000, 0xc16f768c},
-{0, 0x409eed18, 0xc1f112e6},
-{'q', 0x409eed1c, 0xc172af40},
-{0, 0x41719c5a, 0xc1f80dc0},
-{'l', 0x412bcfe2, 0x00000000},
-{'@', 0x00000029, 0x0000359f},/*        )        x-advance: 53.621094 */
-{'M', 0x41301b7d, 0xc2d09732},
-{'l', 0x412bcfe5, 0x00000000},
-{'q', 0x412112e6, 0x417d6c40},
-{0, 0x41708972, 0x41f80dc0},
-{'q', 0x40a112e8, 0x4172af40},
-{0, 0x40a112e8, 0x41f112e6},
-{'q', 0x00000000, 0x41708974},
-{0, 0xc0a112e8, 0x41f225cc},
-{'9', 0x0079ffd9, 0x00f8ff88},
-{'l', 0xc12bcfe5, 0x00000000},
-{'q', 0x410ed19d, 0xc175e7f3},
-{0, 0x41549e11, 0xc1f44b99},
-{'q', 0x408dbeb4, 0xc173c226},
-{0, 0x408dbeb4, 0xc1f5e7f2},
-{'q', 0x00000000, 0xc1780dc0},
-{0, 0xc08dbeb4, 0xc1f4d50a},
-{'q', 0xc08b98e8, 0xc1719c58},
-{0, 0xc1549e11, 0xc1f44b9c},
-{'@', 0x0000002a, 0x000044b9},/*        *        x-advance: 68.722656 */
-{'M', 0x42814302, 0xc2a761ef},
-{'l', 0xc1c0c070, 0x41505278},
-{'l', 0x41c0c070, 0x41516560},
-{'l', 0xc07920b0, 0x40d27848},
-{'l', 0xc1b46716, 0xc159fc94},
-{'l', 0x00000000, 0x41ca6a88},
-{'l', 0xc0f4d50c, 0x00000000},
-{'l', 0x00000000, 0xc1ca6a88},
-{'l', 0xc1b46716, 0x4159fc94},
-{'l', 0xc07920a8, 0xc0d27848},
-{'l', 0x41c0c06e, 0xc1516560},
-{'l', 0xc1c0c06e, 0xc1505278},
-{'l', 0x407920a4, 0xc0d49e10},
-{'l', 0x41b46716, 0x4159fc90},
-{'l', 0x36000000, 0xc1ca6a84},
-{'l', 0x40f4d50c, 0x00000000},
-{'l', 0x00000000, 0x41ca6a84},
-{'l', 0x41b46716, 0xc159fc90},
-{'l', 0x407920b0, 0x40d49e10},
-{'@', 0x0000002b, 0x0000732a},/*        +        x-advance: 115.164062 */
-{'M', 0x427ce2ca, 0xc2ac5957},
-{'l', 0x00000000, 0x421587ba},
-{'l', 0x421587bc, 0x00000000},
-{'l', 0x00000000, 0x41368ce4},
-{'l', 0xc21587bc, 0x00000000},
-{'l', 0x00000000, 0x421587bb},
-{'l', 0xc1346714, 0x00000000},
-{'l', 0x00000000, 0xc21587bb},
-{'l', 0xc21587bb, 0x00000000},
-{'l', 0xb5800000, 0xc1368ce4},
-{'l', 0x421587bb, 0x00000000},
-{'l', 0x00000000, 0xc21587ba},
-{'l', 0x41346714, 0x00000000},
-{'@', 0x0000002c, 0x00002bb0},/*        ,        x-advance: 43.687500 */
-{'M', 0x4180dbeb, 0xc1886037},
-{'l', 0x416293c2, 0x00000000},
-{'l', 0x00000000, 0x4138b2b0},
-{'l', 0xc1301b7c, 0x41abcfe4},
-{'l', 0xc10a8604, 0x00000000},
-{'l', 0x40b01b7c, 0xc1abcfe4},
-{'l', 0x00000000, 0xc138b2b0},
-{'@', 0x0000002d, 0x00003198},/*        -        x-advance: 49.593750 */
-{'M', 0x40d6c3dd, 0xc22c9e11},
-{'l', 0x4210b2af, 0x00000000},
-{'l', 0x00000000, 0x41301b7c},
-{'l', 0xc210b2af, 0x00000000},
-{'l', 0xb5c00000, 0xc1301b7c},
-{'[', 0x0047002d, 0x00000508},
-{'[', 0x004a002d, 0x000007a6},
-{'[', 0x004f002d, 0x000003d3},
-{'[', 0x0051002d, 0x00000508},
-{'[', 0x006f002d, 0x0000028c},
-{'@', 0x0000002e, 0x00002bb0},/*        .        x-advance: 43.687500 */
-{'M', 0x416b2af4, 0xc1886037},
-{'l', 0x416293c2, 0x00000000},
-{'l', 0x00000000, 0x41886037},
-{'l', 0xc16293c2, 0x00000000},
-{'l', 0x00000000, 0xc1886037},
-{'@', 0x0000002f, 0x00002e4f},/*        /        x-advance: 46.308594 */
-{'M', 0x420b98e9, 0xc2c86716},
-{'l', 0x41368ce4, 0x00000000},
-{'l', 0xc20b98e9, 0x42e1e7f2},
-{'l', 0xc1368ce4, 0xb5800000},
-{'l', 0x420b98e9, 0xc2e1e7f2},
-{'@', 0x00000030, 0x00005773},/*        0        x-advance: 87.449219 */
-{'M', 0x422ec3dd, 0xc2b68ce3},
-{'q', 0xc1278448, 0x00000000},
-{0, 0xc17c5956, 0x41255e80},
-{'q', 0xc0a7844c, 0x41244b98},
-{0, 0xc0a7844c, 0x41f7844c},
-{'q', 0x00000000, 0x41a4d50c},
-{0, 0x40a7844c, 0x41f7844c},
-{'q', 0x40a9aa1c, 0x41244b98},
-{0, 0x417c5956, 0x41244b98},
-{'q', 0x41289734, 0x00000000},
-{0, 0x417c5958, 0xc1244b98},
-{'q', 0x40a9aa18, 0xc1255e80},
-{0, 0x40a9aa18, 0xc1f7844c},
-{'q', 0x00000000, 0xc1a55e80},
-{0, 0xc0a9aa18, 0xc1f7844c},
-{'9', 0xffaeffd7, 0xffaeff82},
-{'m', 0x00000000, 0xc12bcfe0},
-{'q', 0x4186c3de, 0x00000000},
-{0, 0x41cda33a, 0x4155b0f8},
-{'q', 0x410ed198, 0x41549e10},
-{0, 0x410ed198, 0x421aa180},
-{'q', 0x00000000, 0x41ca6a86},
-{0, 0xc10ed198, 0x421aa181},
-{'q', 0xc10dbeb8, 0x41549e11},
-{0, 0xc1cda33a, 0x41549e11},
-{'q', 0xc186c3dd, 0xb4c00000},
-{0, 0xc1ce2cab, 0xc1549e11},
-{'q', 0xc10dbeb5, 0xc155b0f8},
-{0, 0xc10dbeb5, 0xc21aa181},
-{'q', 0x00000000, 0xc1caf3f8},
-{0, 0x410dbeb5, 0xc21aa180},
-{'q', 0x410ed19c, 0xc155b0f8},
-{0, 0x41ce2cab, 0xc155b0f8},
-{'@', 0x00000031, 0x00005773},/*        1        x-advance: 87.449219 */
-{'M', 0x41886037, 0xc1368ce3},
-{'l', 0x41b12e63, 0x00000000},
-{'l', 0x00000000, 0xc298e2cb},
-{'l', 0xc1c0c06e, 0x409aa180},
-{'l', 0x35800000, 0xc1459578},
-{'l', 0x41bfad88, 0xc09aa180},
-{'l', 0x4158e9a8, 0x00000000},
-{'l', 0x00000000, 0x42b1957a},
-{'l', 0x41b12e64, 0xb6400000},
-{'l', 0x00000000, 0x41368ce3},
-{'l', 0xc266df5a, 0x00000000},
-{'l', 0xb6000000, 0xc1368ce3},
-{'@', 0x00000032, 0x00005773},/*        2        x-advance: 87.449219 */
-{'M', 0x41d301b8, 0xc1368ce3},
-{'l', 0x423d4302, 0x00000000},
-{'4', 0x005b0000, 0x0000fe04},
-{'l', 0xb6000000, 0xc1368ce3},
-{'q', 0x40f6fad8, 0xc0ff920a},
-{0, 0x41a80dbe, 0xc1ab4670},
-{'q', 0x4155b0f6, 0xc157d6c4},
-{0, 0x41863a6b, 0xc18b0f76},
-{'8', 0x9e48c634, 0xb114d814},
-{'q', 0x00000000, 0xc0ff9210},
-{0, 0xc0b46718, 0xc1505278},
-{'q', 0xc0b24148, 0xc0a112f0},
-{0, 0xc1690528, 0xc0a112f0},
-{'q', 0xc0cc06e0, 0x00000000},
-{0, 0xc157d6c2, 0x400dbec0},
-{'9', 0x0011ffc8, 0x0035ff88},
-{'l', 0x00000000, 0xc15b0f78},
-{'q', 0x410301b8, 0xc0527840},
-{0, 0x4174d50c, 0xc09eed20},
-{'q', 0x40e3a6a8, 0xbfd6c3c0},
-{0, 0x41505278, 0xbfd6c3c0},
-{'q', 0x417920a4, 0x00000000},
-{0, 0x41c6a860, 0x40f920a0},
-{'q', 0x41143018, 0x40f920b0},
-{0, 0x41143018, 0x41a67168},
-{'8', 0x5dee3100, 0x68bd2cee},
-{'q', 0xbfd6c3e0, 0x3ff920c0},
-{0, 0xc12abd00, 0x41346718},
-{'q', 0xc10fe480, 0x4114301c},
-{0, 0xc1caf3f8, 0x41cfc904},
-{'@', 0x00000033, 0x00005773},/*        3        x-advance: 87.449219 */
-{'M', 0x425f1656, 0xc2581b7d},
-{'q', 0x411bb468, 0x40052780},
-{0, 0x4172af40, 0x410a8604},
-{'q', 0x40b01b80, 0x40d27840},
-{0, 0x40b01b80, 0x4181eed1},
-{'q', 0x00000000, 0x416d50c0},
-{0, 0xc12338b8, 0x41b79fc8},
-{'q', 0xc12338b0, 0x4101eed3},
-{0, 0xc1e7f240, 0x4101eed3},
-{'8', 0xf79800ce, 0xe292f6cb},
-{'l', 0x00000000, 0xc151655e},
-{'q', 0x40b46716, 0x40527844},
-{0, 0x4145957b, 0x409eed18},
-{'q', 0x40d6c3dc, 0x3fd6c3e0},
-{0, 0x41606df6, 0x3fd6c3e0},
-{'q', 0x414c06dc, 0x00000000},
-{0, 0x419b2af2, 0xc0a112e6},
-{'q', 0x40d6c3e0, 0xc0a112e6},
-{0, 0x40d6c3e0, 0xc16a180d},
-{'q', 0x00000000, 0xc10dbeb6},
-{0, 0xc0c7bb48, 0xc15d3542},
-{'9', 0xffd8ffcf, 0xffd8ff77},
-{'4', 0x0000ffa3, 0xffa70000},
-{'l', 0x41436fae, 0x00000000},
-{'q', 0x41200000, 0x00000000},
-{0, 0x4174d50c, 0xc07d6c40},
-{'8', 0xa42ae02a, 0xa2d4c300},
-{'q', 0xc0adf5b0, 0xc0852790},
-{0, 0xc17a338c, 0xc0852790},
-{'q', 0xc0b24148, 0x00000000},
-{0, 0xc13f2414, 0x3f9aa180},
-{'9', 0x0009ffcd, 0x001eff90},
-{'l', 0x00000000, 0xc14149e0},
-{'q', 0x40f6fad8, 0xc0097320},
-{0, 0x4166df5a, 0xc04e2cc0},
-{'q', 0x40d8e9ac, 0xbf897300},
-{0, 0x414c06de, 0xbf897300},
-{'q', 0x4176fad8, 0x00000000},
-{0, 0x41c36fae, 0x40e180e0},
-{'q', 0x410fe480, 0x40df5b10},
-{0, 0x410fe480, 0x419768cc},
-{'q', 0x00000000, 0x41052788},
-{0, 0xc0987bb0, 0x416180dc},
-{'q', 0xc0987bb0, 0x40b68ce8},
-{0, 0xc158e9a8, 0x40fd6c40},
-{'@', 0x00000034, 0x00005773},/*        4        x-advance: 87.449219 */
-{'M', 0x424fc905, 0xc2b0c74d},
-{'4', 0x01abfeef, 0x00000111},
-{'6', 0xfe550000, 0xffa2ffe4},
-{'l', 0x41886038, 0x00000000},
-{'l', 0x00000000, 0x42829aa2},
-{'l', 0x4164b990, 0xb6800000},
-{'l', 0x00000000, 0x41346714},
-{'l', 0xc164b990, 0x00000000},
-{'l', 0x00000000, 0x41bcfe48},
-{'l', 0xc157d6c4, 0x00000000},
-{'l', 0x00000000, 0xc1bcfe48},
-{'l', 0xc234f089, 0x00000000},
-{'l', 0xb5c00000, 0xc151655c},
-{'l', 0x4226b61e, 0xc27df5b1},
-{'@', 0x00000035, 0x00005773},/*        5        x-advance: 87.449219 */
-{'M', 0x416d50c0, 0xc2c86716},
-{'l', 0x4254e2ca, 0x00000000},
-{'4', 0x005b0000, 0x0000feba},
-{'l', 0x00000000, 0x41c48294},
-{'8', 0xf52ff817, 0xfc2ffc17},
-{'q', 0x41863a6a, 0x00000000},
-{0, 0x41d49e10, 0x41131d34},
-{'q', 0x411cc750, 0x41131d34},
-{0, 0x411cc750, 0x41c731d2},
-{'q', 0x00000000, 0x4181655f},
-{0, 0xc12112e8, 0x41c957a0},
-{'q', 0xc12112e4, 0x410ed19d},
-{0, 0xc1e31d34, 0x410ed19d},
-{'8', 0xf89900ce, 0xe795f8cc},
-{'l', 0x00000000, 0xc159fc90},
-{'8', 0x27631a30, 0x0c6c0c33},
-{'q', 0x4139c598, 0x00000000},
-{0, 0x41931d36, 0xc0c36fae},
-{'q', 0x40d8e9a8, 0xc0c36fae},
-{0, 0x40d8e9a8, 0xc1849e12},
-{'q', 0x00000000, 0xc1278448},
-{0, 0xc0d8e9a8, 0xc1849e10},
-{'q', 0xc0d8e9a8, 0xc0c36fb0},
-{0, 0xc1931d36, 0xc0c36fb0},
-{'8', 0x09aa00d5, 0x1ea809d6},
-{'l', 0x00000000, 0xc249579f},
-{'@', 0x00000036, 0x00005773},/*        6        x-advance: 87.449219 */
-{'M', 0x423579fc, 0xc25e036f},
-{'q', 0xc1120a4c, 0x00000000},
-{0, 0xc167f240, 0x40c7bb40},
-{'q', 0xc0a9aa18, 0x40c7bb48},
-{0, 0xc0a9aa18, 0x4188e9aa},
-{'q', 0x00000000, 0x412ce2cc},
-{0, 0x40a9aa18, 0x4188e9aa},
-{'q', 0x40abcfe8, 0x40c7bb48},
-{0, 0x4167f240, 0x40c7bb48},
-{'q', 0x41120a50, 0x00000000},
-{0, 0x4166df5c, 0xc0c7bb46},
-{'q', 0x40abcfe8, 0xc0c9e112},
-{0, 0x40abcfe8, 0xc188e9aa},
-{'q', 0x00000000, 0xc12df5b0},
-{0, 0xc0abcfe8, 0xc188e9aa},
-{'9', 0xffcfffd6, 0xffcfff8d},
-{'m', 0x41d74d50, 0xc229eed1},
-{'l', 0x00000000, 0x41459578},
-{'8', 0xe3aeedd8, 0xf6aef6d7},
-{'q', 0xc156c3e0, 0x00000000},
-{0, 0xc1a44b99, 0x4110f768},
-{'q', 0xc0e180dc, 0x4110f768},
-{0, 0xc100dbec, 0x41db0f78},
-{'8', 0xb94fd21f, 0xe769e72f},
-{'q', 0x41719c58, 0x00000000},
-{0, 0x41be9aa2, 0x41131d34},
-{'q', 0x410cabd0, 0x41120a50},
-{0, 0x410cabd0, 0x41c731d2},
-{'q', 0x00000000, 0x4176fada},
-{0, 0xc1120a50, 0x41c61eee},
-{'q', 0xc1120a50, 0x41154301},
-{0, 0xc1c25cc8, 0x41154301},
-{'q', 0xc18b0f76, 0xb4c00000},
-{0, 0xc1d49e10, 0xc1549e11},
-{'q', 0xc1131d36, 0xc155b0f8},
-{0, 0xc1131d36, 0xc21aa181},
-{'q', 0x00000000, 0xc1be112c},
-{0, 0x41346716, 0xc21768ce},
-{'q', 0x41346718, 0xc16293c0},
-{0, 0x41f225cc, 0xc16293c0},
-{'8', 0x08520028, 0x18560829},
-{'@', 0x00000037, 0x00005773},/*        7        x-advance: 87.449219 */
-{'M', 0x41346716, 0xc2c86716},
-{'l', 0x4280dbeb, 0x00000000},
-{'l', 0x00000000, 0x40b8b2b0},
-{'l', 0xc21180dc, 0x42bcdbeb},
-{'l', 0xc16293c2, 0x00000000},
-{'l', 0x4208e9aa, 0xc2b1957a},
-{'l', 0xc2407bb4, 0x00000000},
-{'l', 0xb6000000, 0xc1368ce0},
-{'@', 0x00000038, 0x00005773},/*        8        x-advance: 87.449219 */
-{'M', 0x422ec3dd, 0xc23e55e8},
-{'q', 0xc11aa180, 0x00000000},
-{0, 0xc173c224, 0x40a55e80},
-{'q', 0xc0b01b7c, 0x40a55e80},
-{0, 0xc0b01b7c, 0x4163a6a8},
-{'q', 0x00000000, 0x4110f76a},
-{0, 0x40b01b7c, 0x4163a6a9},
-{'q', 0x40b24148, 0x40a55e7e},
-{0, 0x4173c224, 0x40a55e7e},
-{'q', 0x411aa184, 0x00000000},
-{0, 0x4173c228, 0xc0a55e7e},
-{'q', 0x40b24148, 0xc0a7844a},
-{0, 0x40b24148, 0xc163a6a9},
-{'q', 0x00000000, 0xc110f768},
-{0, 0xc0b24148, 0xc163a6a8},
-{'9', 0xffd7ffd4, 0xffd7ff87},
-{'m', 0xc158e9a8, 0xc0b8b2b0},
-{'q', 0xc10b98ea, 0xc0097310},
-{0, 0xc159fc90, 0xc101eed0},
-{'q', 0xc09aa182, 0xc0bf2410},
-{0, 0xc09aa182, 0xc1690528},
-{'q', 0x00000000, 0xc14036f8},
-{0, 0x41086037, 0xc197f240},
-{'q', 0x4109731e, 0xc0df5b10},
-{0, 0x41bbeb61, 0xc0df5b10},
-{'q', 0x416f7690, 0x00000000},
-{0, 0x41bbeb62, 0x40df5b10},
-{'q', 0x41086038, 0x40df5b10},
-{0, 0x41086038, 0x4197f240},
-{'q', 0x00000000, 0x41097320},
-{0, 0xc09cc750, 0x41690528},
-{'q', 0xc09aa180, 0x40bf2418},
-{0, 0xc157d6c4, 0x4101eed0},
-{'q', 0x411cc74c, 0x40120a50},
-{0, 0x4173c224, 0x410ed1a0},
-{'q', 0x40b01b80, 0x40d49e10},
-{0, 0x40b01b80, 0x4181eed0},
-{'q', 0x00000000, 0x41690528},
-{0, 0xc10ed198, 0x41b2cabd},
-{'q', 0xc10dbeb8, 0x40f920a5},
-{0, 0xc1cb7d6e, 0x40f920a5},
-{'q', 0xc1849e10, 0x34000000},
-{0, 0xc1cc06de, 0xc0f920a4},
-{'q', 0xc10dbeb7, 0xc0f920a5},
-{0, 0xc10dbeb7, 0xc1b2cabd},
-{'q', 0x00000000, 0xc1198e98},
-{0, 0x40b01b7e, 0xc181eed0},
-{'9', 0xffcb002c, 0xffb9007a},
-{'m', 0xc09eed1c, 0xc1ab4670},
-{'8', 0x61263e00, 0x226d2227},
-{'8', 0xde6c0045, 0x9f27de27},
-{'8', 0x9fd9c200, 0xde94ded9},
-{'8', 0x229300ba, 0x61da22da},
-{'@', 0x00000039, 0x00005773},/*        9        x-advance: 87.449219 */
-{'M', 0x41719c59, 0xc0052784},
-{'l', 0x00000000, 0xc145957a},
-{'8', 0x1d521328, 0x0a520a29},
-{'q', 0x4156c3dc, 0x00000000},
-{0, 0x41a3c226, 0xc10fe482},
-{'q', 0x40e3a6a8, 0xc110f768},
-{0, 0x4101eed4, 0xc1db98ea},
-{'8', 0x46b22ee1, 0x189718d1},
-{'q', 0xc1708974, 0x00000000},
-{0, 0xc1be9aa2, 0xc110f768},
-{'q', 0xc10b98e9, 0xc1120a50},
-{0, 0xc10b98e9, 0xc1c731d4},
-{'q', 0x00000000, 0xc176fad8},
-{0, 0x41120a4f, 0xc1c61eec},
-{'q', 0x41120a4e, 0xc1154300},
-{0, 0x41c25cc7, 0xc1154300},
-{'q', 0x418b0f76, 0x00000000},
-{0, 0x41d4149c, 0x4155b0f8},
-{'q', 0x41131d38, 0x41549e10},
-{0, 0x41131d38, 0x421aa180},
-{'q', 0x00000000, 0x41bd87bc},
-{0, 0xc1346718, 0x421768ce},
-{'q', 0xc133542c, 0x416180dd},
-{0, 0xc1f19c58, 0x416180dd},
-{'8', 0xf8ae00d8, 0xe8aaf8d7},
-{'m', 0x41d7d6c4, 0xc229eed2},
-{'q', 0x41120a50, 0x00000000},
-{0, 0x4166df5c, 0xc0c7bb40},
-{'q', 0x40abcfe0, 0xc0c7bb48},
-{0, 0x40abcfe0, 0xc188e9ac},
-{'q', 0x00000000, 0xc12ce2c8},
-{0, 0xc0abcfe0, 0xc1886034},
-{'q', 0xc0a9aa18, 0xc0c9e120},
-{0, 0xc166df5c, 0xc0c9e120},
-{'q', 0xc1120a50, 0x00000000},
-{0, 0xc167f240, 0x40c9e120},
-{'q', 0xc0a9aa18, 0x40c7bb40},
-{0, 0xc0a9aa18, 0x41886034},
-{'q', 0x00000000, 0x412df5b4},
-{0, 0x40a9aa18, 0x4188e9ac},
-{'q', 0x40abcfe0, 0x40c7bb40},
-{0, 0x4167f240, 0x40c7bb40},
-{'@', 0x0000003a, 0x00002e4f},/*        :        x-advance: 46.308594 */
-{'M', 0x4180dbeb, 0xc1886037},
-{'l', 0x416293c2, 0x00000000},
-{'4', 0x00880000, 0x0000ff8f},
-{'6', 0xff780000, 0xfe500000},
-{'l', 0x416293c2, 0x00000000},
-{'l', 0x00000000, 0x41886036},
-{'l', 0xc16293c2, 0x00000000},
-{'l', 0x00000000, 0xc1886036},
-{'@', 0x0000003b, 0x00002e4f},/*        ;        x-advance: 46.308594 */
-{'M', 0x4180dbeb, 0xc28e25cc},
-{'l', 0x416293c2, 0x00000000},
-{'4', 0x00880000, 0x0000ff8f},
-{'6', 0xff780000, 0x01b00000},
-{'l', 0x416293c2, 0x36000000},
-{'l', 0x00000000, 0x4138b2b0},
-{'l', 0xc1301b7c, 0x41abcfe4},
-{'l', 0xc10a8604, 0x00000000},
-{'l', 0x40b01b7c, 0xc1abcfe4},
-{'l', 0x00000000, 0xc138b2b0},
-{'@', 0x0000003c, 0x0000732a},/*        <        x-advance: 115.164062 */
-{'M', 0x42c93543, 0xc2874d51},
-{'l', 0xc28a8604, 0x41c50c08},
-{'l', 0x428a8604, 0x41c3f921},
-{'l', 0x00000000, 0x41436fac},
-{'l', 0xc2ac149e, 0xc1f9aa17},
-{'l', 0xb5800000, 0xc132414c},
-{'l', 0x42ac149e, 0xc1f9aa16},
-{'l', 0x00000000, 0x41436fa8},
-{'@', 0x0000003d, 0x0000732a},/*        =        x-advance: 115.164062 */
-{'M', 0x41690527, 0xc279aa18},
-{'l', 0x42ac149e, 0x00000000},
-{'4', 0x005a0000, 0x0000fd50},
-{'6', 0xffa60000, 0x00db0000},
-{'l', 0x42ac149e, 0x00000000},
-{'l', 0x00000000, 0x41368ce4},
-{'l', 0xc2ac149e, 0x00000000},
-{'l', 0xb5800000, 0xc1368ce4},
-{'@', 0x0000003e, 0x0000732a},/*        >        x-advance: 115.164062 */
-{'M', 0x41690527, 0xc2874d51},
-{'l', 0x00000000, 0xc1436fa8},
-{'l', 0x42ac149e, 0x41f9aa16},
-{'l', 0x00000000, 0x4132414c},
-{'l', 0xc2ac149e, 0x41f9aa17},
-{'l', 0xb5800000, 0xc1436fac},
-{'l', 0x428a414a, 0xc1c3f921},
-{'l', 0xc28a414a, 0xc1c50c08},
-{'@', 0x0000003f, 0x000048f3},/*        ?        x-advance: 72.949219 */
-{'M', 0x41d1eed1, 0xc1886037},
-{'l', 0x4159fc92, 0x00000000},
-{'4', 0x00880000, 0x0000ff94},
-{'6', 0xff780000, 0xffb20069},
-{'4', 0x0000ff9a, 0xffae0000},
-{'8', 0xa70fca00, 0xaf3fde0f},
-{'l', 0x40c149e0, 0xc0bf2418},
-{'8', 0xcb2ce41e, 0xcd0de70d},
-{'8', 0xb3ddd100, 0xe3a4e3de},
-{'8', 0x12a600d6, 0x369d12d1},
-{'l', 0x00000000, 0xc149e110},
-{'8', 0xd366e232, 0xf16bf134},
-{'q', 0x41459578, 0x00000000},
-{0, 0x419e63a6, 0x40d05270},
-{'q', 0x40f08970, 0x40d05280},
-{0, 0x40f08970, 0x41897320},
-{'8', 0x4ded2800, 0x52bd24ed},
-{'l', 0xc0bcfe48, 0x40b8b2b0},
-{'8', 0x27dd19e7, 0x1bf20df6},
-{'8', 0x1bfc0bfd, 0x2cff10ff},
-{'l', 0x00000000, 0x410414a0},
-{'@', 0x00000040, 0x00008973},/*        @        x-advance: 137.449219 */
-{'M', 0x424c9052, 0xc210293c},
-{'q', 0x00000000, 0x41198e9a},
-{0, 0x40987bb8, 0x41719c5a},
-{'8', 0x2b682b26, 0xd4670042},
-{'q', 0x40987bc0, 0xc0b01b80},
-{0, 0x40987bc0, 0xc1708974},
-{'q', 0x00000000, 0xc11655e8},
-{0, 0xc09aa180, 0xc16e63a4},
-{'8', 0xd498d4da, 0x2c9900c0},
-{'9', 0x002cffda, 0x0077ffda},
-{'m', 0x42124f08, 0x41a08973},
-{'8', 0x3db629e0, 0x13a013d7},
-{'q', 0xc138b2b0, 0x00000000},
-{0, 0xc19655e8, 0xc1052784},
-{'q', 0xc0e5cc78, 0xc1063a6a},
-{0, 0xc0e5cc78, 0xc1ae7f24},
-{'q', 0x00000000, 0xc156c3dc},
-{0, 0x40e7f240, 0xc1ae7f24},
-{'q', 0x40e7f240, 0xc1063a68},
-{0, 0x4195cc76, 0xc1063a68},
-{'8', 0x14610037, 0x3c491329},
-{'4', 0xffba0000, 0x0000004c},
-{'l', 0x00000000, 0x4245957a},
-{'q', 0x411cc748, 0xbfbcfe40},
-{0, 0x4174d508, 0xc10ed19a},
-{'q', 0x40b24150, 0xc0f08974},
-{0, 0x40b24150, 0xc19b2af3},
-{'8', 0x95efc700, 0xa3cdcef0},
-{'q', 0xc0df5b10, 0xc10cabd0},
-{0, 0xc1886038, 0xc156c3e0},
-{'q', 0xc1200000, 0xc09655e0},
-{0, 0xc1ae7f24, 0xc09655e0},
-{'q', 0xc104149c, 0x00000000},
-{0, 0xc17d6c3c, 0x400dbea0},
-{'q', 0xc0f2af40, 0x40097320},
-{0, 0xc1606df4, 0x40ce2cb0},
-{'q', 0xc1289734, 0x40db0f80},
-{0, 0xc184149f, 0x418fe482},
-{'q', 0xc0bcfe48, 0x41312e64},
-{0, 0xc0bcfe48, 0x41c036fc},
-{'q', 0x00000000, 0x412abcfc},
-{0, 0x4074d510, 0x419fffff},
-{'q', 0x407920a0, 0x41154302},
-{0, 0x4133542e, 0x41838b2b},
-{'q', 0x40e180e0, 0x40df5b0f},
-{0, 0x41827846, 0x412abcfe},
-{'q', 0x41143018, 0x4067f240},
-{0, 0x419e63a6, 0x4067f240},
-{'q', 0x410a8600, 0x00000000},
-{0, 0x4187d6c4, 0xc038b2ac},
-{'9', 0xffe90043, 0xffbd007a},
-{'l', 0x40c149e0, 0x40ee63a6},
-{'q', 0xc1063a68, 0x40d0527a},
-{0, 0xc19293c0, 0x41200001},
-{'q', 0xc11dda38, 0x405b0f70},
-{0, 0xc1a08974, 0x405b0f70},
-{'q', 0xc146a860, 0x00000000},
-{0, 0xc1bb61ee, 0xc08b98e8},
-{'q', 0xc1301b80, 0xc08dbeb6},
-{0, 0xc19cc74e, 0xc14d19c6},
-{'q', 0xc109731e, 0xc1063a6a},
-{0, 0xc151655e, 0xc19b2af4},
-{'q', 0xc08fe482, 0xc1312e62},
-{0, 0xc08fe482, 0xc1be112d},
-{'q', 0x00000000, 0xc1436fb0},
-{0, 0x40920a4e, 0xc1ba4f08},
-{'q', 0x40920a50, 0xc1312e64},
-{0, 0x41505278, 0xc19bb466},
-{'q', 0x410a8604, 0xc1086038},
-{0, 0x41a00000, 0xc1505278},
-{'q', 0x413579fc, 0xc0920a50},
-{0, 0x41c036fc, 0xc0920a50},
-{'q', 0x4163a6a8, 0x00000000},
-{0, 0x41d301b4, 0x40bad870},
-{'q', 0x41436fb0, 0x40bad880},
-{0, 0x41a3c228, 0x41849e14},
-{'q', 0x40a112e0, 0x40d27840},
-{0, 0x40f4d510, 0x4164b98c},
-{'q', 0x402bcfe0, 0x40f6fad8},
-{0, 0x402bcfe0, 0x417f9208},
-{'q', 0x00000000, 0x418d3543},
-{0, 0xc12abd00, 0x41ded19d},
-{'q', 0xc12abd00, 0x412338b2},
-{0, 0xc1ebb468, 0x4129aa17},
-{'l', 0x00000000, 0xc1255e7f},
-{'@', 0x00000041, 0x00005e06},/*        A        x-advance: 94.023438 */
-{'M', 0x423beb62, 0xc2adb0f7},
-{'4', 0x018eff6d, 0x00000126},
-{'6', 0xfe72ff6d, 0xff96ffc3},
-{'l', 0x4175e7f4, 0x00000000},
-{'l', 0x4218c06d, 0x42c86716},
-{'l', 0xc16180d8, 0x00000000},
-{'l', 0xc1120a50, 0xc1cda338},
-{'l', 0xc234abd0, 0x00000000},
-{'l', 0xc1120a4e, 0x41cda338},
-{'l', 0xc164b98e, 0x00000000},
-{'l', 0x42190527, 0xc2c86716},
-{'[', 0x00410041, 0x000003d3},
-{'@', 0x00000042, 0x00005e4b},/*        B        x-advance: 94.292969 */
-{'M', 0x41d86037, 0xc23f68ce},
-{'4', 0x01250000, 0x000000ad},
-{'q', 0x412f0894, 0x00000000},
-{0, 0x4181655c, 0xc08fe482},
-{'8', 0x912adc2a, 0x92d6b500},
-{'9', 0xffddffd7, 0xffddff7f},
-{'6', 0x0000ff53, 0xfeb70000},
-{'4', 0x00f10000, 0x000000a0},
-{'q', 0x411eed18, 0x00000000},
-{0, 0x416c3dd8, 0xc06c3de0},
-{'8', 0xa527e227, 0xa6d9c400},
-{'9', 0xffe2ffda, 0xffe2ff8a},
-{'6', 0x0000ff60, 0xffa7ff94},
-{'l', 0x420a8603, 0x00000000},
-{'q', 0x41780dc0, 0x00000000},
-{0, 0x41bf2414, 0x40ce2cb0},
-{'q', 0x41063a68, 0x40ce2ca0},
-{0, 0x41063a68, 0x419293c0},
-{'q', 0x00000000, 0x41131d38},
-{0, 0xc0897310, 0x416a1810},
-{'q', 0xc0897320, 0x40adf5b0},
-{0, 0xc149e114, 0x40d8e9a8},
-{'q', 0x411ffffc, 0x40097320},
-{0, 0x41780dbc, 0x410fe480},
-{'q', 0x40b24150, 0x40d8e9b0},
-{0, 0x40b24150, 0x4187d6c5},
-{'q', 0x00000000, 0x4156c3dd},
-{0, 0xc1120a50, 0x41a5e7f2},
-{'9', 0x003affb7, 0x003aff31},
-{'l', 0xc20fe482, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x00000043, 0x00005ff9},/*        C        x-advance: 95.972656 */
-{'M', 0x42b10c07, 0xc2b8f769},
-{'l', 0x00000000, 0x4164b990},
-{'q', 0xc0db0f80, 0xc0cc06e0},
-{0, 0xc16a1810, 0xc1187bb0},
-{'q', 0xc0f6fae0, 0xc049e120},
-{0, 0xc1838b2c, 0xc049e120},
-{'q', 0xc189731c, 0x00000000},
-{0, 0xc1d27843, 0x41289730},
-{'q', 0xc1120a50, 0x41278450},
-{0, 0xc1120a50, 0x41f2af40},
-{'q', 0x00000000, 0x419e63a7},
-{0, 0x41120a50, 0x41f2af40},
-{'q', 0x41120a4e, 0x4127844b},
-{0, 0x41d27843, 0x4127844b},
-{'q', 0x410b98e8, 0x00000000},
-{0, 0x41838b2c, 0xc049e114},
-{'9', 0xffe7003e, 0xffb40075},
-{'l', 0x00000000, 0x416293c2},
-{'q', 0xc0e3a6b0, 0x409aa180},
-{0, 0xc1719c60, 0x40e7f241},
-{'q', 0xc0fd6c30, 0x401aa180},
-{0, 0xc1863a68, 0x401aa180},
-{'q', 0xc1b60370, 0x34000000},
-{0, 0xc20f5b10, 0xc15e4828},
-{'q', 0xc151655c, 0xc15f5b10},
-{0, 0xc151655c, 0xc21836fb},
-{'q', 0x00000000, 0xc1c149e0},
-{0, 0x4151655e, 0xc21836fa},
-{'q', 0x4151655e, 0xc15f5b10},
-{0, 0x420f5b10, 0xc15f5b10},
-{'q', 0x410fe480, 0x00000000},
-{0, 0x41874d50, 0x401aa180},
-{'q', 0x40ff9210, 0x401655e0},
-{0, 0x416f7690, 0x40e3a6a0},
-{'@', 0x00000044, 0x000069d6},/*        D        x-advance: 105.835938 */
-{'M', 0x41d86037, 0xc2b21eed},
-{'4', 0x026f0000, 0x00000083},
-{'q', 0x41a5e7f2, 0x00000000},
-{0, 0x41f2af3e, 0xc11655e8},
-{'q', 0x411aa180, 0xc11655e8},
-{0, 0x411aa180, 0xc1ed50bf},
-{'q', 0x00000000, 0xc1a112e8},
-{0, 0xc11aa180, 0xc1ebb468},
-{'9', 0xffb5ffb4, 0xffb5ff0e},
-{'6', 0x0000ff7d, 0xffa7ff94},
-{'l', 0x41ded19c, 0x00000000},
-{'q', 0x41e90526, 0x00000000},
-{0, 0x422b01b7, 0x41425cc8},
-{'q', 0x4159fc90, 0x414149e0},
-{0, 0x4159fc90, 0x421768ce},
-{'q', 0x00000000, 0x41cf3f91},
-{0, 0xc15b0f78, 0x421836fa},
-{'9', 0x0061ff93, 0x0061feab},
-{'l', 0xc1ded19c, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x00000045, 0x000056d8},/*        E        x-advance: 86.843750 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'l', 0x427d6c3d, 0x00000000},
-{'l', 0x00000000, 0x41368ce0},
-{'l', 0xc24731d2, 0x00000000},
-{'l', 0xb6000000, 0x41ed50c2},
-{'l', 0x423edf5a, 0x00000000},
-{'l', 0x00000000, 0x41368ce0},
-{'l', 0xc23edf5a, 0x00000000},
-{'l', 0xb6000000, 0x42113c22},
-{'l', 0x424c06de, 0x35800000},
-{'l', 0x00000000, 0x41368ce3},
-{'l', 0xc28120a4, 0x00000000},
-{'l', 0xb6800000, 0xc2c86716},
-{'@', 0x00000046, 0x00004f0f},/*        F        x-advance: 79.058594 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'l', 0x426655e7, 0x00000000},
-{'l', 0x00000000, 0x41368ce0},
-{'l', 0xc2301b7c, 0x00000000},
-{'l', 0xb6000000, 0x41ec3dda},
-{'l', 0x421eed18, 0x00000000},
-{'l', 0x00000000, 0x41368ce4},
-{'l', 0xc21eed18, 0x00000000},
-{'l', 0xb6000000, 0x423f68ce},
-{'l', 0xc158e9aa, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x00000047, 0x00006a82},/*        G        x-advance: 106.507812 */
-{'M', 0x42a39fc9, 0xc164b98e},
-{'l', 0x00000000, 0xc1d74d51},
-{'l', 0xc1b12e64, 0x00000000},
-{'4', 0xffa70000, 0x0000011c},
-{'l', 0x00000000, 0x422c149e},
-{'q', 0xc0fb4670, 0x40b24146},
-{0, 0xc18a8600, 0x41074d4f},
-{'q', 0xc11768d0, 0x40346716},
-{0, 0xc1a19c5a, 0x40346716},
-{'q', 0xc1bbeb62, 0x34000000},
-{0, 0xc2131d36, 0xc15b0f76},
-{'q', 0xc1538b28, 0xc15c225c},
-{0, 0xc1538b28, 0xc2190528},
-{'q', 0x00000000, 0xc1c48294},
-{0, 0x41538b2a, 0xc2190526},
-{'q', 0x41549e12, 0xc15c2260},
-{0, 0x42131d36, 0xc15c2260},
-{'q', 0x411cc748, 0x00000000},
-{0, 0x4194b98c, 0x401aa180},
-{'9', 0x00130046, 0x00380082},
-{'l', 0x00000000, 0x4166df60},
-{'q', 0xc0f08970, 0xc0cc06e0},
-{0, 0xc17f9208, 0xc1198e98},
-{'q', 0xc1074d50, 0xc04e2cc0},
-{0, 0xc18e482a, 0xc04e2cc0},
-{'q', 0xc1931d34, 0x00000000},
-{0, 0xc1dd3542, 0x41244b98},
-{'q', 0xc1131d36, 0x41244b98},
-{0, 0xc1131d36, 0x41f4d50c},
-{'q', 0x00000000, 0x41a225cd},
-{0, 0x41131d36, 0x41f44b99},
-{'q', 0x4114301c, 0x41244b99},
-{0, 0x41dd3542, 0x41244b99},
-{'8', 0xf7660039, 0xe151f62d},
-{'@', 0x00000048, 0x0000675b},/*        H        x-advance: 103.355469 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'l', 0x4158e9aa, 0x00000000},
-{'l', 0x00000000, 0x42244b99},
-{'l', 0x42450c06, 0x00000000},
-{'l', 0x00000000, 0xc2244b99},
-{'l', 0x4158e9a8, 0x00000000},
-{'l', 0x00000000, 0x42c86716},
-{'l', 0xc158e9a8, 0x00000000},
-{'l', 0x00000000, 0xc23edf5b},
-{'l', 0xc2450c06, 0x00000000},
-{'l', 0xb6000000, 0x423edf5b},
-{'l', 0xc158e9aa, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x00000049, 0x00002889},/*        I        x-advance: 40.535156 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'l', 0x4158e9aa, 0x00000000},
-{'l', 0x00000000, 0x42c86716},
-{'l', 0xc158e9aa, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x0000004a, 0x00002889},/*        J        x-advance: 40.535156 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'4', 0x0000006c, 0x02e90000},
-{'q', 0x00000000, 0x4190f769},
-{0, 0xc0dd3544, 0x41d27845},
-{'9', 0x0041ffca, 0x0041ff50},
-{'4', 0x0000ffd7, 0xffa50000},
-{'l', 0x40874d50, 0x00000000},
-{'q', 0x410fe482, 0x00000000},
-{0, 0x414af3f9, 0xc0a112e6},
-{'q', 0x406c3ddc, 0xc0a112e5},
-{0, 0x406c3ddc, 0xc1906df5},
-{'l', 0x00000000, 0xc2ba7165},
-{'@', 0x0000004b, 0x00005a22},/*        K        x-advance: 90.132812 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'l', 0x4158e9aa, 0x00000000},
-{'l', 0x00000000, 0x4229655e},
-{'l', 0x4233dda2, 0xc229655e},
-{'l', 0x418b98ec, 0x00000000},
-{'l', 0xc246ed1a, 0x423ad87b},
-{'l', 0x42552784, 0x4255f5b1},
-{'l', 0xc18ed19c, 0x00000000},
-{'l', 0xc2407bb4, 0xc2410527},
-{'l', 0xb6000000, 0x42410527},
-{'l', 0xc158e9aa, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x0000004c, 0x00004c93},/*        L        x-advance: 76.574219 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'l', 0x4158e9aa, 0x00000000},
-{'l', 0x00000000, 0x42b1957a},
-{'l', 0x42432af4, 0xb6400000},
-{'l', 0x00000000, 0x41368ce3},
-{'l', 0xc279655f, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'[', 0x0041004c, 0x00000327},
-{'@', 0x0000004d, 0x00007697},/*        M        x-advance: 118.589844 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'l', 0x41a19c58, 0x00000000},
-{'l', 0x41cc9054, 0x42886036},
-{'l', 0x41cda336, 0xc2886036},
-{'l', 0x41a19c5c, 0x00000000},
-{'l', 0x00000000, 0x42c86716},
-{'l', 0xc1538b30, 0x00000000},
-{'l', 0x00000000, 0xc2aff920},
-{'l', 0xc1ceb61c, 0x4289731c},
-{'l', 0xc159fc94, 0x36800000},
-{'l', 0xc1ceb61e, 0xc289731c},
-{'l', 0x00000000, 0x42aff920},
-{'l', 0xc1527844, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x0000004e, 0x000066d1},/*        N        x-advance: 102.816406 */
-{'M', 0x4157d6c4, 0xc2c86716},
-{'l', 0x41920a4f, 0x00000000},
-{'l', 0x4231b7d6, 0x42a7a6a8},
-{'l', 0x00000000, 0xc2a7a6a8},
-{'l', 0x41527848, 0x00000000},
-{'l', 0x00000000, 0x42c86716},
-{'l', 0xc1920a50, 0x00000000},
-{'l', 0xc231b7d6, 0xc2a7a6a8},
-{'l', 0x00000000, 0x42a7a6a8},
-{'l', 0xc1527844, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x0000004f, 0x00006c30},/*        O        x-advance: 108.187500 */
-{'M', 0x4258a4f0, 0xc2b6036f},
-{'q', 0xc16c3dd8, 0x00000000},
-{0, 0xc1bbeb61, 0x41301b78},
-{'q', 0xc10a8604, 0x41301b80},
-{0, 0xc10a8604, 0x41f00000},
-{'q', 0x00000000, 0x419768cf},
-{0, 0x410a8604, 0x41ef768d},
-{'q', 0x410b98ea, 0x41301b7d},
-{0, 0x41bbeb61, 0x41301b7d},
-{'q', 0x416c3dd8, 0x00000000},
-{0, 0x41bad87c, 0xc1301b7d},
-{'q', 0x410a8600, 0xc1301b7c},
-{0, 0x410a8600, 0xc1ef768d},
-{'q', 0x00000000, 0xc197f240},
-{0, 0xc10a8600, 0xc1f00000},
-{'9', 0xffa8ffbc, 0xffa8ff46},
-{'m', 0x00000000, 0xc1301b80},
-{'q', 0x41a89730, 0x00000000},
-{0, 0x4206c3de, 0x416293c0},
-{'q', 0x4149e110, 0x416180e0},
-{0, 0x4149e110, 0x421768ce},
-{'q', 0x00000000, 0x41bd87bc},
-{0, 0xc149e110, 0x421768ce},
-{'q', 0xc149e118, 0x416180dd},
-{0, 0xc206c3de, 0x416180dd},
-{'q', 0xc1a920a4, 0xb4c00000},
-{0, 0xc2074d50, 0xc16180dc},
-{'q', 0xc149e114, 0xc16180db},
-{0, 0xc149e114, 0xc21768ce},
-{'q', 0x00000000, 0xc1be112c},
-{0, 0x4149e112, 0xc21768ce},
-{'q', 0x414af3fa, 0xc16293c0},
-{0, 0x42074d50, 0xc16293c0},
-{'[', 0x002d004f, 0x000003d3},
-{'@', 0x00000050, 0x000052e2},/*        P        x-advance: 82.882812 */
-{'M', 0x41d86037, 0xc2b21eed},
-{'4', 0x012d0000, 0x00000088},
-{'q', 0x411768cc, 0x00000000},
-{0, 0x416a180c, 0xc09cc750},
-{'8', 0x9129d929, 0x91d7b900},
-{'9', 0xffd9ffd7, 0xffd9ff8b},
-{'6', 0x0000ff78, 0xffa7ff94},
-{'l', 0x41f4d50c, 0x00000000},
-{'q', 0x4186c3dc, 0x00000000},
-{0, 0x41cb7d6a, 0x40f4d510},
-{'q', 0x410a8608, 0x40f2af40},
-{0, 0x410a8608, 0x41b24148},
-{'q', 0x00000000, 0x416d50c0},
-{0, 0xc10a8608, 0x41b35430},
-{'9', 0x003cffbc, 0x003cff35},
-{'l', 0xc1886037, 0x00000000},
-{'l', 0x00000000, 0x422112e6},
-{'l', 0xc158e9aa, 0x00000000},
-{'l', 0x00000000, 0xc2c86716},
-{'@', 0x00000051, 0x00006c30},/*        Q        x-advance: 108.187500 */
-{'M', 0x4258a4f0, 0xc2b6036f},
-{'q', 0xc16c3dd8, 0x00000000},
-{0, 0xc1bbeb61, 0x41301b78},
-{'q', 0xc10a8604, 0x41301b80},
-{0, 0xc10a8604, 0x41f00000},
-{'q', 0x00000000, 0x419768cf},
-{0, 0x410a8604, 0x41ef768d},
-{'q', 0x410b98ea, 0x41301b7d},
-{0, 0x41bbeb61, 0x41301b7d},
-{'q', 0x416c3dd8, 0x00000000},
-{0, 0x41bad87c, 0xc1301b7d},
-{'q', 0x410a8600, 0xc1301b7c},
-{0, 0x410a8600, 0xc1ef768d},
-{'q', 0x00000000, 0xc197f240},
-{0, 0xc10a8600, 0xc1f00000},
-{'9', 0xffa8ffbc, 0xffa8ff46},
-{'m', 0x4197f240, 0x42b263a6},
-{'4', 0x009c008e, 0x0000ff7d},
-{'l', 0xc16d50bc, 0xc1805278},
-{'8', 0x01e501ef, 0x00ef00f7},
-{'q', 0xc1a920a4, 0x00000000},
-{0, 0xc2074d50, 0xc16180dc},
-{'q', 0xc149e114, 0xc16293c1},
-{0, 0xc149e114, 0xc21768ce},
-{'q', 0x00000000, 0xc1be112c},
-{0, 0x4149e112, 0xc21768ce},
-{'q', 0x414af3fa, 0xc16293c0},
-{0, 0x42074d50, 0xc16293c0},
-{'q', 0x41a89730, 0x00000000},
-{0, 0x4206c3de, 0x416293c0},
-{'q', 0x4149e110, 0x416180e0},
-{0, 0x4149e110, 0x421768ce},
-{'q', 0x00000000, 0x418b98ea},
-{0, 0xc0e180e0, 0x41eeed1a},
-{'q', 0xc0df5b10, 0x4146a860},
-{0, 0xc1a225cc, 0x419293c2},
-{'[', 0x002d0051, 0x000003d3},
-{'@', 0x00000052, 0x00005f80},/*        R        x-advance: 95.500000 */
-{'M', 0x427406df, 0xc23beb62},
-{'8', 0x32430b22, 0x6a422621},
-{'4', 0x00db006e, 0x0000ff8c},
-{'l', 0xc14d19c8, 0xc1cda338},
-{'8', 0x96b3b0d9, 0xe69be6db},
-{'l', 0xc16c3dda, 0x00000000},
-{'l', 0x00000000, 0x4229655e},
-{'4', 0x0000ff94, 0xfcdf0000},
-{'l', 0x41f4d50c, 0x00000000},
-{'q', 0x4189731c, 0x00000000},
-{0, 0x41cd19c6, 0x40e5cc70},
-{'q', 0x41074d50, 0x40e5cc80},
-{0, 0x41074d50, 0x41ad6c40},
-{'q', 0x00000000, 0x411768cc},
-{0, 0xc08dbec0, 0x417b4670},
-{'9', 0x0031ffde, 0x0045ff9a},
-{'m', 0xc207d6c4, 0xc2285278},
-{'4', 0x011c0000, 0x00000088},
-{'q', 0x411cc74c, 0x00000000},
-{0, 0x416c3dd8, 0xc08fe480},
-{'8', 0x9628dc28, 0x97d8ba00},
-{'q', 0xc09eed18, 0xc08fe480},
-{0, 0xc16c3dd8, 0xc08fe480},
-{'l', 0xc1886037, 0x00000000},
-{'@', 0x00000053, 0x0000573f},/*        S        x-advance: 87.246094 */
-{'M', 0x42931d35, 0xc2c1d354},
-{'l', 0x00000000, 0x41538b28},
-{'q', 0xc0f6fad0, 0xc06c3dc0},
-{0, 0xc1690528, 0xc0b01b70},
-{'q', 0xc0db0f70, 0xbfe7f240},
-{0, 0xc1538b28, 0xbfe7f240},
-{'q', 0xc1312e64, 0x00000000},
-{0, 0xc188e9ab, 0x40897310},
-{'8', 0x61d122d1, 0x501f3500},
-{'9', 0x001a0020, 0x002b0079},
-{'l', 0x410301b8, 0x3fd6c3e0},
-{'q', 0x4172af40, 0x4038b2b0},
-{0, 0x41b2cabc, 0x412338b0},
-{'q', 0x40e7f240, 0x40e7f240},
-{0, 0x40e7f240, 0x419bb467},
-{'q', 0x00000000, 0x41690528},
-{0, 0xc11cc750, 0x41b0a4f0},
-{'q', 0xc11bb464, 0x40f08975},
-{0, 0xc1e4b98c, 0x40f08975},
-{'q', 0xc0e3a6a8, 0x34000000},
-{0, 0xc172af40, 0xbfce2cab},
-{'9', 0xfff4ffc1, 0xffdaff7c},
-{'l', 0x00000000, 0xc15f5b0f},
-{'q', 0x4104149e, 0x4094301c},
-{0, 0x4181655e, 0x40df5b0e},
-{'q', 0x40fd6c3c, 0x401655e8},
-{0, 0x417920a6, 0x401655e8},
-{'q', 0x4139c594, 0x00000000},
-{0, 0x418f5b0e, 0xc0920a4e},
-{'8', 0x9832dc32, 0xa4dcc500},
-{'9', 0xffdfffdd, 0xffcfff8a},
-{'l', 0xc10414a0, 0xbfce2cc0},
-{'q', 0xc172af3e, 0xc04149e0},
-{0, 0xc1af920a, 0xc11768cc},
-{'q', 0xc0d8e9a6, 0xc0ce2cb0},
-{0, 0xc0d8e9a6, 0xc18f5b0e},
-{'q', 0x00000000, 0xc1549e18},
-{0, 0x41154301, 0xc1a7844c},
-{'q', 0x411655e8, 0xc0f4d510},
-{0, 0x41ceb61f, 0xc0f4d510},
-{'q', 0x40e180d8, 0x00000000},
-{0, 0x4165cc74, 0x3fa338c0},
-{'q', 0x40ea1808, 0x3fa338c0},
-{0, 0x416f768c, 0x4074d500},
-{'[', 0x00410053, 0x0000028c},
-{'@', 0x00000054, 0x000053f5},/*        T        x-advance: 83.957031 */
-{'M', 0xbece2cac, 0xc2c86716},
-{'l', 0x42a987bb, 0x00000000},
-{'l', 0x00000000, 0x41368ce0},
-{'l', 0xc20e4828, 0x00000000},
-{'l', 0x00000000, 0x42b1957a},
-{'l', 0xc159fc90, 0x00000000},
-{'l', 0x00000000, 0xc2b1957a},
-{'l', 0xc20e4829, 0x00000000},
-{'l', 0xb5b00000, 0xc1368ce0},
-{'@', 0x00000055, 0x0000649a},/*        U        x-advance: 100.601562 */
-{'M', 0x413f2414, 0xc2c86716},
-{'4', 0x0000006c, 0x01e60000},
-{'q', 0x00000000, 0x4180dbeb},
-{0, 0x40bad87c, 0x41b9c595},
-{'q', 0x40bad87c, 0x40e180da},
-{0, 0x419768cd, 0x40e180da},
-{'q', 0x41505278, 0x00000000},
-{0, 0x4196df5a, 0xc0e180da},
-{'9', 0xffc8002e, 0xff47002e},
-{'4', 0xfe1a0000, 0x0000006c},
-{'l', 0x00000000, 0x427a338b},
-{'q', 0x00000000, 0x419cc74d},
-{0, 0xc11bb468, 0x41ecc74c},
-{'q', 0xc11aa180, 0x41200001},
-{0, 0xc1e4b98e, 0x41200001},
-{'q', 0xc197f240, 0xb4c00000},
-{0, 0xc1e5cc74, 0xc1200000},
-{'q', 0xc11aa180, 0xc11fffff},
-{0, 0xc11aa180, 0xc1ecc74c},
-{'l', 0x00000000, 0xc27a338b},
-{'@', 0x00000056, 0x00005e06},/*        V        x-advance: 94.023438 */
-{'M', 0x421d50c0, 0x00000000},
-{'l', 0xc2190527, 0xc2c86716},
-{'l', 0x416293c1, 0x00000000},
-{'l', 0x41fdf5b2, 0x42a8b98e},
-{'l', 0x41fe7f24, 0xc2a8b98e},
-{'l', 0x416180d8, 0x00000000},
-{'l', 0xc218c06d, 0x42c86716},
-{'l', 0xc175e7f4, 0x00000000},
-{'@', 0x00000057, 0x000087e7},/*        W        x-advance: 135.902344 */
-{'M', 0x40920a4f, 0xc2c86716},
-{'l', 0x415b0f76, 0x00000000},
-{'l', 0x41a89731, 0x42a9655e},
-{'l', 0x41a80dbe, 0xc2a9655e},
-{'l', 0x4173c224, 0x00000000},
-{'l', 0x41a89734, 0x42a9655e},
-{'l', 0x41a80dbc, 0xc2a9655e},
-{'l', 0x415c2260, 0x00000000},
-{'l', 0xc1c957a0, 0x42c86716},
-{'l', 0xc1886038, 0x00000000},
-{'l', 0xc1a920a4, 0xc2adf5b1},
-{'l', 0xc1aabcfe, 0x42adf5b1},
-{'l', 0xc1886036, 0x00000000},
-{'l', 0xc1c8ce2c, 0xc2c86716},
-{'@', 0x00000058, 0x00005e29},/*        X        x-advance: 94.160156 */
-{'M', 0x410a8603, 0xc2c86716},
-{'l', 0x41690527, 0x00000000},
-{'l', 0x41c731d3, 0x4214fe48},
-{'l', 0x41c844b8, 0xc214fe48},
-{'l', 0x41690528, 0x00000000},
-{'l', 0xc200dbeb, 0x42407bb4},
-{'l', 0x4209731d, 0x42505278},
-{'l', 0xc1690528, 0x00000000},
-{'l', 0xc1e180da, 0xc22a7844},
-{'l', 0xc1e31d35, 0x422a7844},
-{'l', 0xc16a180e, 0x00000000},
-{'l', 0x420f1656, 0xc255f5b1},
-{'l', 0xc1f9aa18, 0xc23ad87b},
-{'@', 0x00000059, 0x000053f5},/*        Y        x-advance: 83.957031 */
-{'M', 0xbe89731d, 0xc2c86716},
-{'l', 0x41690527, 0x00000000},
-{'l', 0x41de4829, 0x4224d50c},
-{'l', 0x41dcabd0, 0xc224d50c},
-{'l', 0x41690528, 0x00000000},
-{'l', 0xc20dbeb6, 0x4251eed1},
-{'l', 0x00000000, 0x423edf5b},
-{'l', 0xc159fc90, 0x00000000},
-{'l', 0x00000000, 0xc23edf5b},
-{'l', 0xc20dbeb6, 0xc251eed1},
-{'@', 0x0000005a, 0x00005e29},/*        Z        x-advance: 94.160156 */
-{'M', 0x40f6fad8, 0xc2c86716},
-{'l', 0x429d731c, 0x00000000},
-{'l', 0x00000000, 0x41255e80},
-{'l', 0xc27d6c3c, 0x429ce9aa},
-{'l', 0x4281cc74, 0xb6400000},
-{'l', 0x00000000, 0x41368ce3},
-{'l', 0xc2a39fc8, 0x00000000},
-{'l', 0xb6400000, 0xc1255e7f},
-{'l', 0x427d6c3d, 0xc29ce9aa},
-{'l', 0xc2773f91, 0x00000000},
-{'l', 0x00000000, 0xc1368ce0},
-{'@', 0x0000005b, 0x0000359f},/*        [        x-advance: 53.621094 */
-{'M', 0x413cfe48, 0xc2d0dbeb},
-{'l', 0x41e3a6a8, 0x00000000},
-{'l', 0x00000000, 0x41198e98},
-{'l', 0xc180dbeb, 0x00000000},
-{'l', 0x00000000, 0x42ceb61f},
-{'l', 0x4180dbeb, 0xb5800000},
-{'l', 0x00000000, 0x41198e9b},
-{'l', 0xc1e3a6a8, 0x00000000},
-{'l', 0x00000000, 0xc2f519c5},
-{'@', 0x0000005c, 0x00002e4f},/*       \         x-advance: 46.308594 */
-{'M', 0x41368ce3, 0xc2c86716},
-{'l', 0x420b98e9, 0x42e1e7f2},
-{'l', 0xc1368ce4, 0xb5800000},
-{'l', 0xc20b98e9, 0xc2e1e7f2},
-{'l', 0x41368ce3, 0x00000000},
-{'@', 0x0000005d, 0x0000359f},/*        ]        x-advance: 53.621094 */
-{'M', 0x42273f92, 0xc2d0dbeb},
-{'l', 0x00000000, 0x42f519c5},
-{'l', 0xc1e3a6a8, 0x36000000},
-{'l', 0xb5800000, 0xc1198e9b},
-{'l', 0x41805278, 0x00000000},
-{'l', 0x00000000, 0xc2ceb61f},
-{'l', 0xc1805278, 0x00000000},
-{'l', 0xb5800000, 0xc1198e98},
-{'l', 0x41e3a6a8, 0x00000000},
-{'@', 0x0000005e, 0x0000732a},/*        ^        x-advance: 115.164062 */
-{'M', 0x42805278, 0xc2c86716},
-{'l', 0x4211c596, 0x421587bb},
-{'l', 0xc157d6c8, 0x00000000},
-{'l', 0xc1ec3dd8, 0xc1d4149e},
-{'l', 0xc1ec3ddb, 0x41d4149e},
-{'l', 0xc157d6c3, 0x00000000},
-{'l', 0x4211c595, 0xc21587bb},
-{'l', 0x41527844, 0x00000000},
-{'@', 0x0000005f, 0x000044b9},/*        _        x-advance: 68.722656 */
-{'M', 0x428c225d, 0x41b68ce3},
-{'l', 0x00000000, 0x41198e9a},
-{'l', 0xc28ed19d, 0x00000000},
-{'l', 0x36600000, 0xc1198e9a},
-{'l', 0x428ed19d, 0x00000000},
-{'@', 0x00000060, 0x000044b9},/*        `        x-advance: 68.722656 */
-{'M', 0x41c50c07, 0xc2dbdda3},
-{'l', 0x419768cd, 0x41c8ce2c},
-{'l', 0xc1244b98, 0x00000000},
-{'l', 0xc1af0896, 0xc1c8ce2c},
-{'l', 0x41538b2a, 0x00000000},
-{'@', 0x00000061, 0x0000543a},/*        a        x-advance: 84.226562 */
-{'M', 0x423c74d5, 0xc2172414},
-{'q', 0xc16f768c, 0x00000000},
-{0, 0xc1a5e7f2, 0x405b0f70},
-{'8', 0x5dd21bd2, 0x53223400},
-{'q', 0x408b98e8, 0x4074d50c},
-{0, 0x413cfe46, 0x4074d50c},
-{'q', 0x41244b9c, 0x00000000},
-{0, 0x41838b2c, 0xc0e7f242},
-{'9', 0xffc60031, 0xff650031},
-{'4', 0xffea0000, 0x0000ff9e},
-{'m', 0x41c50c06, 0xc0a338b8},
-{'4', 0x01570000, 0x0000ff9e},
-{'l', 0x00000000, 0xc1368ce3},
-{'q', 0xc0874d50, 0x40db0f77},
-{0, 0xc1289734, 0x412225cd},
-{'q', 0xc0c9e110, 0x404e2caa},
-{0, 0xc176fad8, 0x404e2caa},
-{'q', 0xc138b2ae, 0x34000000},
-{0, 0xc1931d34, 0xc0ce2cab},
-{'q', 0xc0d8e9ac, 0xc0d05278},
-{0, 0xc0d8e9ac, 0xc18b0f76},
-{'q', 0x00000000, 0xc14af3fc},
-{0, 0x41074d50, 0xc1990528},
-{'9', 0xffcd0044, 0xffcd00ca},
-{'4', 0x0000008a, 0xfff70000},
-{'q', 0x00000000, 0xc1086034},
-{0, 0xc0b46718, 0xc1527844},
-{'q', 0xc0b24148, 0xc09655e0},
-{0, 0xc17b4670, 0xc09655e0},
-{'8', 0x0c9c00cd, 0x25a30cd0},
-{'l', 0x00000000, 0xc1368ce4},
-{'8', 0xe169ec36, 0xf663f633},
-{'q', 0x41827844, 0x00000000},
-{0, 0x41c2e63a, 0x41074d50},
-{'q', 0x4100dbec, 0x41074d54},
-{0, 0x4100dbec, 0x41cd19c6},
-{'@', 0x00000062, 0x0000573f},/*        b        x-advance: 87.246094 */
-{'M', 0x4285d354, 0xc216112e},
-{'q', 0x00000000, 0xc159fc90},
-{0, 0xc0b46718, 0xc1aabcfe},
-{'q', 0xc0b24148, 0xc0f920a8},
-{0, 0xc175e7f0, 0xc0f920a8},
-{'q', 0xc11cc750, 0x00000000},
-{0, 0xc176fada, 0x40f920a8},
-{'q', 0xc0b24148, 0x40f6fad8},
-{0, 0xc0b24148, 0x41aabcfe},
-{'q', 0x00000000, 0x4159fc90},
-{0, 0x40b24148, 0x41ab4671},
-{'q', 0x40b46714, 0x40f6fad8},
-{0, 0x4176fada, 0x40f6fad8},
-{'q', 0x411cc74c, 0x00000000},
-{0, 0x4175e7f0, 0xc0f6fad8},
-{'9', 0xffc2002d, 0xff55002d},
-{'m', 0xc2280dbe, 0xc1d1eed2},
-{'q', 0x407920a0, 0xc0d6c3d8},
-{0, 0x411cc74c, 0xc11eed1c},
-{'q', 0x40bf2410, 0xc0527840},
-{0, 0x4163a6a8, 0xc0527840},
-{'q', 0x415b0f74, 0x00000000},
-{0, 0x41b1b7d6, 0x412df5b0},
-{'q', 0x41097320, 0x412df5b4},
-{0, 0x41097320, 0x41e4b990},
-{'q', 0x00000000, 0x418dbeb6},
-{0, 0xc1097320, 0x41e4b98e},
-{'q', 0xc1086038, 0x412df5b1},
-{0, 0xc1b1b7d6, 0x412df5b1},
-{'q', 0xc10414a0, 0xb4c00000},
-{0, 0xc163a6a8, 0xc04e2cad},
-{'9', 0xffe6ffd1, 0xffb0ffb2},
-{'l', 0x00000000, 0x41346716},
-{'l', 0xc146a860, 0x00000000},
-{'l', 0x00000000, 0xc2d0dbeb},
-{'l', 0x4146a860, 0x00000000},
-{'l', 0x00000000, 0x4222af3f},
-{'@', 0x00000063, 0x00004b92},/*        c        x-advance: 75.570312 */
-{'M', 0x4286180e, 0xc2909052},
-{'l', 0x00000000, 0x4138b2ac},
-{'8', 0xdeace9d7, 0xf5acf5d7},
-{'q', 0xc14036fc, 0x00000000},
-{0, 0xc1954302, 0x40f4d508},
-{'q', 0xc0d49e10, 0x40f2af40},
-{0, 0xc0d49e10, 0x41aabcfe},
-{'q', 0x00000000, 0x415c225c},
-{0, 0x40d49e10, 0x41ab4671},
-{'q', 0x40d49e10, 0x40f2af3e},
-{0, 0x41954302, 0x40f2af3e},
-{'8', 0xf554002a, 0xde54f52a},
-{'l', 0x00000000, 0x41368ce2},
-{'8', 0x1cab13d7, 0x09a309d4},
-{'q', 0xc187d6c4, 0x00000000},
-{0, 0xc1d7d6c4, 0xc12abcfe},
-{'q', 0xc1200000, 0xc12abcff},
-{0, 0xc1200000, 0xc1e655e8},
-{'q', 0xb5000000, 0xc1931d36},
-{0, 0x412112e6, 0xc1e768d0},
-{'q', 0x412225cc, 0xc1289730},
-{0, 0x41ddbeb5, 0xc1289730},
-{'8', 0x0959002d, 0x1b54092b},
-{'@', 0x00000064, 0x0000573f},/*        d        x-advance: 87.246094 */
-{'M', 0x4279aa18, 0xc27f0897},
-{'l', 0x00000000, 0xc222af3f},
-{'l', 0x41459578, 0x00000000},
-{'4', 0x03430000, 0x0000ff9e},
-{'l', 0x00000000, 0xc1346716},
-{'q', 0xc07920b0, 0x40d6c3dd},
-{0, 0xc11dda34, 0x41200000},
-{'q', 0xc0bcfe48, 0x404e2caa},
-{0, 0xc163a6a8, 0x404e2caa},
-{'q', 0xc159fc90, 0x34000000},
-{0, 0xc1b1b7d7, 0xc12df5b0},
-{'q', 0xc1086036, 0xc12df5b0},
-{0, 0xc1086036, 0xc1e4b98e},
-{'q', 0xb5000000, 0xc18dbeb6},
-{0, 0x41086036, 0xc1e4b990},
-{'q', 0x4109731e, 0xc12df5b0},
-{0, 0x41b1b7d7, 0xc12df5b0},
-{'q', 0x41052784, 0x00000000},
-{0, 0x4163a6a8, 0x40527840},
-{'9', 0x0019002f, 0x004f004e},
-{'m', 0xc2285278, 0x41d1eed2},
-{'q', 0xb6000000, 0x4159fc90},
-{0, 0x40b24148, 0x41ab4671},
-{'q', 0x40b46714, 0x40f6fad8},
-{0, 0x4176fad8, 0x40f6fad8},
-{'q', 0x411cc74c, 0x00000000},
-{0, 0x4176fad8, 0xc0f6fad8},
-{'q', 0x40b46718, 0xc0f920a4},
-{0, 0x40b46718, 0xc1ab4671},
-{'q', 0x00000000, 0xc159fc90},
-{0, 0xc0b46718, 0xc1aabcfe},
-{'q', 0xc0b46718, 0xc0f920a8},
-{0, 0xc176fad8, 0xc0f920a8},
-{'q', 0xc11cc74e, 0x00000000},
-{0, 0xc176fad8, 0x40f920a8},
-{'q', 0xc0b2414c, 0x40f6fad8},
-{0, 0xc0b2414c, 0x41aabcfe},
-{'@', 0x00000065, 0x00005490},/*        e        x-advance: 84.562500 */
-{'M', 0x429a7f24, 0xc222af3f},
-{'4', 0x00300000, 0x0000fe3a},
-{'q', 0x3f4e2ca0, 0x414c06de},
-{0, 0x40f4d508, 0x419bb466},
-{'q', 0x40dd3548, 0x40d49e12},
-{0, 0x41998e9a, 0x40d49e12},
-{'8', 0xf36e0038, 0xd76af335},
-{'l', 0x00000000, 0x413ad87b},
-{'q', 0xc0d49e10, 0x40346716},
-{0, 0xc159fc8c, 0x4089731d},
-{'q', 0xc0df5b10, 0x3fbcfe49},
-{0, 0xc16293c4, 0x3fbcfe49},
-{'q', 0xc18fe482, 0x00000000},
-{0, 0xc1e4301b, 0xc127844c},
-{'q', 0xc127844a, 0xc127844b},
-{0, 0xc127844a, 0xc1e293c2},
-{'q', 0xb5000000, 0xc193a6a8},
-{0, 0x411eed1a, 0xc1ea180e},
-{'q', 0x411ffffe, 0xc12df5b0},
-{0, 0x41d74d4f, 0xc12df5b0},
-{'q', 0x4172af40, 0x00000000},
-{0, 0x41bfad88, 0x411cc750},
-{'9', 0x004d0046, 0x00d40046},
-{'m', 0xc1459578, 0xc067f240},
-{'q', 0xbe097400, 0xc12225cc},
-{0, 0xc0b68ce8, 0xc1816560},
-{'q', 0xc0b01b80, 0xc0c149d8},
-{0, 0xc16a180c, 0xc0c149d8},
-{'q', 0xc1255e80, 0x00000000},
-{0, 0xc1849e12, 0x40bad878},
-{'q', 0xc0c59578, 0x40bad878},
-{0, 0xc0e3a6a8, 0x41838b2a},
-{'l', 0x42301b7e, 0xbd897200},
-{'@', 0x00000066, 0x00003063},/*        f        x-advance: 48.386719 */
-{'M', 0x424c06df, 0xc2d0dbeb},
-{'4', 0x00520000, 0x0000ffa2},
-{'8', 0x15b600cb, 0x4dec15ec},
-{'l', 0x00000000, 0x40d49e10},
-{'l', 0x41a2af40, 0x00000000},
-{'l', 0x00000000, 0x41198ea0},
-{'l', 0xc1a2af40, 0x00000000},
-{'l', 0x00000000, 0x42832414},
-{'l', 0xc146a85f, 0x00000000},
-{'l', 0x00000000, 0xc2832414},
-{'0', 0xb40000a2, 0xd700005e},
-{'q', 0x00000000, 0xc148ce30},
-{0, 0x40bad87a, 0xc1920a50},
-{'q', 0x40bad87c, 0xc0b8b2b0},
-{0, 0x4194301b, 0xc0b8b2b0},
-{'l', 0x413ad87c, 0x00000000},
-{'@', 0x00000067, 0x0000573f},/*        g        x-advance: 87.246094 */
-{'M', 0x4279aa18, 0xc219d354},
-{'q', 0x00000000, 0xc156c3dc},
-{0, 0xc0b24150, 0xc1a67166},
-{'q', 0xc0b01b78, 0xc0ec3dd8},
-{0, 0xc1780dbc, 0xc0ec3dd8},
-{'q', 0xc11eed1a, 0x00000000},
-{0, 0xc1780dbe, 0x40ec3dd8},
-{'q', 0xc0b01b80, 0x40ec3de0},
-{0, 0xc0b01b80, 0x41a67166},
-{'q', 0x00000000, 0x4155b0f8},
-{0, 0x40b01b80, 0x41a5e7f2},
-{'q', 0x40b24148, 0x40ec3dda},
-{0, 0x41780dbe, 0x40ec3dda},
+{15, 0x0000a008, 0x000007a7},/* length:1959 CTX_SUBDIV:8 CTX_BAKE_FONT_SIZE:160 */
+{'(', 0x00000008, 0x00000001},/* Roboto*/
+{32, 0x6f626f52, 0x00006f74},
+{')', 0x00000008, 0x00000001},
+{'(', 0x0000004b, 0x00000009},/* Apache Licence, Version 2.0
+                                Copyright 2014 Christian Robertson - Apache 2*/
+{32, 0x63617041, 0x4c206568},
+{'i', 0x636e6563, 0x56202c65},
+{'e', 0x6f697372, 0x2e32206e},
+{'0', 0x706f430a, 0x67697279},
+{'h', 0x30322074, 0x43203431},
+{'h', 0x74736972, 0x206e6169},
+{'R', 0x7265626f, 0x6e6f7374},
+{32, 0x7041202d, 0x65686361},
+{32, 0x00000032, 0x00000000},
+{')', 0x0000004b, 0x00000009},
+{'@', 0x00000020, 0x000021dd},/*                 x-advance: 33.863281 */
+{'@', 0x00000021, 0x00002333},/*        !        x-advance: 35.199219 */
+{'M', 0x41c08889, 0xc2c22223},
+{'l', 0xbf5ddde0, 0x428b5556},
+{'4', 0x0000ffa7, 0xfdd3fff9},
+{'6', 0x00000067, 0x02d6ff96},
+{'8', 0xd80ee800, 0xf02bf00e},
+{'8', 0x102b001c, 0x280f100f},
+{'8', 0x27f11600, 0x10d510f2},
+{'8', 0xf0d500e4, 0xd9f2f0f2},
+{'@', 0x00000022, 0x00002bbb},/*        "        x-advance: 43.730469 */
+{'M', 0x41944445, 0xc2baaaab},
+{'l', 0xc0000000, 0x41be6664},
+{'l', 0xc0ecccce, 0x00000000},
+{'4', 0xfefa0000, 0x0000004b},
+{'6', 0x00480000, 0x00000090},
+{'l', 0xc0000000, 0x41be6664},
+{'l', 0xc0ecccd0, 0x00000000},
+{'l', 0x00000000, 0xc2037778},
+{'l', 0x41166668, 0x00000000},
+{'l', 0x00000000, 0x41111118},
+{'[', 0x00770022, 0x000000bb},/*kerning*/
+{'@', 0x00000023, 0x00005411},/*        #        x-advance: 84.066406 */
+{'M', 0x4236eef0, 0x00000000},
+{'l', 0x40aaaaa8, 0xc1daaaab},
+{'l', 0xc18cccce, 0x00000000},
+{'l', 0xc0aaaaa8, 0x41daaaab},
+{'l', 0xc118888a, 0x00000000},
+{'l', 0x40aaaaac, 0xc1daaaab},
+{'l', 0xc1800000, 0x00000000},
+{'l', 0xb5000000, 0xc1133336},
+{'l', 0x418e6667, 0x00000000},
+{'l', 0x40911110, 0xc1bc4444},
+{'l', 0xc18a2222, 0x00000000},
+{'l', 0xb5800000, 0xc1144444},
+{'l', 0x4198888a, 0x00000000},
+{'l', 0x40acccc8, 0xc1dddde0},
+{'l', 0x4119999c, 0x00000000},
+{'l', 0xc0acccd0, 0x41dddde0},
+{'l', 0x418cccce, 0x00000000},
+{'l', 0x40acccd0, 0xc1dddde0},
+{'l', 0x41188888, 0x00000000},
+{'l', 0xc0acccd0, 0x41dddde0},
+{'l', 0x41588888, 0x00000000},
+{'l', 0x00000000, 0x41144444},
+{'l', 0xc1755558, 0x00000000},
+{'l', 0xc0933330, 0x41bc4444},
+{'l', 0x416eeef0, 0x00000000},
+{'l', 0x00000000, 0x41133336},
+{'4', 0x0000ff7b, 0x00daffd6},
+{'6', 0x0000ffb4, 0xfedcffad},
+{'l', 0x418ccccc, 0x00000000},
+{'l', 0x40933338, 0xc1bc4444},
+{'l', 0xc18cccce, 0x00000000},
+{'l', 0xc0933330, 0x41bc4444},
+{'@', 0x00000024, 0x00004cbb},/*        $        x-advance: 76.730469 */
+{'M', 0x428aeeef, 0xc1c91112},
+{'q', 0x00000000, 0x4139999b},
+{0, 0xc0dffff8, 0x4192aaac},
+{'9', 0x0035ffc9, 0x003fff6b},
+{'4', 0x00650000, 0x0000ffb1},
+{'l', 0x00000000, 0xc14aaaac},
+{'q', 0xc1244446, 0xbf888887},
+{0, 0xc1933334, 0xc0f9999a},
+{'9', 0xffcaffc0, 0xff50ffc0},
+{'l', 0x41466666, 0x00000000},
+{'q', 0x00000000, 0x41344446},
+{0, 0x40c00004, 0x41744446},
+{'8', 0x1f641f30, 0xdf6e0047},
+{'8', 0xa527de27, 0xadddd000},
+{'q', 0xc08aaaa8, 0xc08cccd0},
+{0, 0xc1700000, 0xc0f99998},
+{'q', 0xc149999a, 0xc0800000},
+{0, 0xc19ccccd, 0xc129999c},
+{'q', 0xc0e00000, 0xc0d33330},
+{0, 0xc0e00000, 0xc1919998},
+{'q', 0x00000000, 0xc1311118},
+{0, 0x40cccccc, 0xc18f7778},
+{'9', 0xffc90033, 0xffbe008b},
+{'4', 0xff8c0000, 0x00000050},
+{'l', 0x00000000, 0x416aaaa8},
+{'q', 0x41333334, 0x3fbbbbc0},
+{0, 0x418b3334, 0x41166668},
+{'9', 0x003e0032, 0x00ac0032},
+{'l', 0xc1444448, 0x00000000},
+{'q', 0x00000000, 0xc10eeef0},
+{0, 0xc0888888, 0xc16aaaa8},
+{'8', 0xd29ed2de, 0x229d00bd},
+{'8', 0x59e122e1, 0x531f3200},
+{'q', 0x407bbbc0, 0x40822220},
+{0, 0x41844444, 0x41055554},
+{'q', 0x414aaaac, 0x40888890},
+{0, 0x4198888a, 0x412aaaac},
+{'q', 0x40ceeee8, 0x40caaab0},
+{0, 0x40ceeee8, 0x418d5556},
+{'@', 0x00000025, 0x00006400},/*        %        x-advance: 100.000000 */
+{'M', 0x40e00001, 0xc29ccccd},
+{'q', 0x00000000, 0xc1044448},
+{0, 0x40aaaaab, 0xc1622228},
+{'q', 0x40aaaaac, 0xc0bddde0},
+{0, 0x4168888a, 0xc0bddde0},
+{'q', 0x41155554, 0x00000000},
+{0, 0x41699998, 0x40bddde0},
+{'9', 0x002e002a, 0x0071002a},
+{'l', 0x00000000, 0x40a44440},
+{'q', 0x00000000, 0x41022220},
+{0, 0xc0a88888, 0x41611110},
+{'q', 0xc0a88888, 0x40bbbbc0},
+{0, 0xc168888a, 0x40bbbbc0},
+{'q', 0xc1144446, 0x00000000},
+{0, 0xc16aaaac, 0xc0bbbbc0},
+{'9', 0xffd1ffd6, 0xff90ffd6},
+{'6', 0xffd70000, 0x0029004a},
+{'8', 0x42142400, 0x1d411d15},
+{'8', 0xe43f002a, 0xbe14e314},
+{'l', 0x00000000, 0xc0a44440},
+{'8', 0xbeebdb00, 0xe3c0e3ec},
+{'8', 0x1dc000d6, 0x42ec1dec},
+{'6', 0x00290000, 0xffb001e7},
+{'l', 0xc23d999a, 0x4297bbbc},
+{'4', 0xffddffc9, 0xfda2017b},
+{'6', 0x00230037, 0x01dbff49},
+{'q', 0x00000000, 0xc1033330},
+{0, 0x40aaaaa8, 0xc1611110},
+{'q', 0x40aaaaa8, 0xc0bddde0},
+{0, 0x4168888c, 0xc0bddde0},
+{'q', 0x41155558, 0x00000000},
+{0, 0x41699998, 0x40bddde0},
+{'9', 0x002e002a, 0x0070002a},
+{'l', 0x00000000, 0x40a66668},
+{'q', 0x00000000, 0x41033333},
+{0, 0xc0a88890, 0x41622222},
+{'q', 0xc0a88880, 0x40bbbbbd},
+{0, 0xc1688888, 0x40bbbbbd},
+{'q', 0xc1155558, 0x00000000},
+{0, 0xc16aaaac, 0xc0bbbbbc},
+{'9', 0xffd1ffd6, 0xff8fffd6},
+{'6', 0xffd70000, 0x0029004a},
+{'8', 0x42142500, 0x1d411d15},
+{'8', 0xe440002b, 0xbd14e314},
+{'l', 0x00000000, 0xc0a66668},
+{'8', 0xbeebdb00, 0xe3c0e3ec},
+{'8', 0x1dc000d6, 0x42ec1cec},
+{'l', 0x00000000, 0x40a66668},
+{'@', 0x00000026, 0x000054ee},/*        &        x-advance: 84.929688 */
+{'M', 0x428b5556, 0x00000000},
+{'l', 0xc0ccccd0, 0xc0f55556},
+{'8', 0x35a323d8, 0x129512cb},
+{'q', 0xc168888a, 0xb4000000},
+{0, 0xc1b77778, 0xc0f77779},
+{'q', 0xc1066667, 0xc0f77778},
+{0, 0xc1066667, 0xc19dddde},
+{'q', 0x00000000, 0xc10aaaac},
+{0, 0x40a66668, 0xc1699998},
+{'8', 0xa26cd02a, 0xa6c0d0d8},
+{'q', 0xc03bbbbc, 0xc0a88890},
+{0, 0xc03bbbbc, 0xc1300000},
+{'q', 0x00000000, 0xc1355558},
+{0, 0x40d55556, 0xc18b3334},
+{'q', 0x40d55558, 0xc0c44440},
+{0, 0x418d5557, 0xc0c44440},
+{'q', 0x412bbbbc, 0x00000000},
+{0, 0x4186eeee, 0x40c44440},
+{'q', 0x40c66668, 0x40c22220},
+{0, 0x40c66668, 0x41655558},
+{'8', 0x5ee43800, 0x4ab426e4},
+{'4', 0x002bffc6, 0x00ce00ac},
+{'9', 0xffbb0024, 0xff660024},
+{'l', 0x41311110, 0x00000000},
+{'9', 0x00880000, 0x00e1ffbf},
+{'4', 0x0084006e, 0x0000ff8a},
+{'m', 0xc22a6668, 0xc2968889},
+{'9', 0x00310000, 0x0080003e},
+{'l', 0x40e44448, 0xc0a22220},
+{'8', 0xd233e823, 0xc311ea11},
+{'8', 0xc7e8e100, 0xe6bbe6e8},
+{'8', 0x1fba00d2, 0x49e81ee8},
+{'m', 0xc0fddddc, 0x42448889},
+{'q', 0x00000000, 0x40e22224},
+{0, 0x40955554, 0x41433334},
+{'q', 0x40955558, 0x40a44446},
+{0, 0x41655556, 0x40a44446},
+{'9', 0x0000004e, 0xffc5008f},
+{'4', 0xff1eff43, 0x0010ffea},
+{'8', 0x4dba2ac7, 0x34f423f4},
+{'@', 0x00000027, 0x000017dd},/*        '        x-advance: 23.863281 */
+{'M', 0x41877778, 0xc2ccccce},
+{'l', 0x00000000, 0x40eaaab0},
+{'l', 0xbfb33338, 0x41c44444},
+{'l', 0xc109999a, 0x00000000},
+{'l', 0x3d8888c0, 0xc1feeef0},
+{'l', 0x411eeef0, 0x00000000},
+{'[', 0x00770027, 0x000000bb},/*kerning*/
+{'@', 0x00000028, 0x00002ebb},/*        (        x-advance: 46.730469 */
+{'M', 0x410eeeef, 0xc21dddde},
+{'q', 0x00000000, 0xc19aaaac},
+{0, 0x40b11112, 0xc2073334},
+{'q', 0x40b11114, 0xc1677778},
+{0, 0x41522224, 0xc1bccccc},
+{'9', 0xffb7003c, 0xff9b006f},
+{'l', 0x40266660, 0x41022228},
+{'q', 0xc0fbbbb8, 0x40bdddd0},
+{0, 0xc1766666, 0x41a99998},
+{'q', 0xc0eeeef0, 0x41733338},
+{0, 0xc0eeeef0, 0x42262223},
+{'q', 0x00000000, 0x41caaaab},
+{0, 0x40eeeef0, 0x4222eeef},
+{'9', 0x007b003c, 0x00ae007b},
+{'l', 0xc0266660, 0x40eeeef0},
+{'q', 0xc0caaab0, 0xc05ddde0},
+{0, 0xc15eeef0, 0xc149999c},
+{'q', 0xc0f33334, 0xc1122222},
+{0, 0xc1522224, 0xc1bc4444},
+{'q', 0xc0b11112, 0xc167777a},
+{0, 0xc0b11112, 0xc20aaaab},
+{'[', 0x00560028, 0x00000155},/*kerning*/
+{'[', 0x00570028, 0x00000133},/*kerning*/
+{'[', 0x00590028, 0x00000177},/*kerning*/
+{'@', 0x00000029, 0x00002f88},/*        )        x-advance: 47.531250 */
+{'M', 0x42173334, 0xc21b3334},
+{'q', 0x00000000, 0x419bbbbd},
+{0, 0xc0b11110, 0x4207bbbc},
+{'q', 0xc0b11114, 0x4167777a},
+{0, 0xc1533336, 0x41bcccce},
+{'9', 0x0049ffc4, 0x0064ff92},
+{'l', 0xc0266669, 0xc0eeeef0},
+{'q', 0x40f9999a, 0xc0bddde0},
+{0, 0x41755556, 0xc1ac4445},
+{'q', 0x40f11110, 0xc179999b},
+{0, 0x40f11110, 0xc227bbbc},
+{'q', 0x00000000, 0xc186eef2},
+{0, 0xc06eeef0, 0xc1eb3334},
+{'q', 0xc06eeef0, 0xc14999a0},
+{0, 0xc1111111, 0xc1a6eef0},
+{'9', 0xffbeffd6, 0xff9fffb0},
+{'l', 0x40266666, 0xc0f11110},
+{'q', 0x40c88889, 0x40622220},
+{0, 0x415dddde, 0x414aaab0},
+{'q', 0x40f55558, 0x41122220},
+{0, 0x41533336, 0x41bccccc},
+{'q', 0x40b11110, 0x41666668},
+{0, 0x40b11110, 0x4209ddde},
+{'@', 0x0000002a, 0x00003acc},/*        *        x-advance: 58.796875 */
+{'M', 0x4109999a, 0xc23ccccd},
+{'l', 0x41566668, 0xc1933336},
+{'l', 0xc1a11112, 0xc0c00000},
+{'l', 0x4048888a, 0xc1200000},
+{'l', 0x41a11112, 0x40ecccd0},
+{'l', 0xbf1999a0, 0xc1b77778},
+{'l', 0x41222222, 0x00000000},
+{'l', 0xbf2aaac0, 0x41baaaac},
+{'l', 0x419eeef0, 0xc0ecccd0},
+{'l', 0x40444450, 0x41233338},
+{'l', 0xc1a3bbbe, 0x40c22220},
+{'l', 0x41522224, 0x41908888},
+{'l', 0xc1044444, 0x40c66668},
+{'l', 0xc1455556, 0xc199999a},
+{'l', 0xc1411112, 0x4195ddde},
+{'l', 0xc1055556, 0xc0c22220},
+{'@', 0x0000002b, 0x00004d77},/*        +        x-advance: 77.464844 */
+{'M', 0x428f7778, 0xc221ddde},
+{'l', 0xc1d8888a, 0x00000000},
+{'l', 0x00000000, 0x41f5ddde},
+{'l', 0xc1455554, 0x00000000},
+{'l', 0x00000000, 0xc1f5ddde},
+{'l', 0xc1d91112, 0x00000000},
+{'l', 0xb5000000, 0xc139999c},
+{'l', 0x41d91112, 0x00000000},
+{'l', 0x00000000, 0xc1e2aaaa},
+{'l', 0x41455554, 0x00000000},
+{'l', 0x00000000, 0x41e2aaaa},
+{'l', 0x41d8888a, 0x00000000},
+{'l', 0x00000000, 0x4139999c},
+{'@', 0x0000002c, 0x00001add},/*        ,        x-advance: 26.863281 */
+{'M', 0x41a4cccd, 0xc16aaaab},
+{'l', 0x00000000, 0x411eeeef},
+{'8', 0x66e83000, 0x5abc35e8},
+{'l', 0xc0e00000, 0xc09bbbbe},
+{'9', 0xffb90033, 0xff6e0034},
+{'l', 0x00000000, 0xc12eeef0},
+{'l', 0x41411111, 0x00000000},
+{'@', 0x0000002d, 0x000025bb},/*        -        x-advance: 37.730469 */
+{'M', 0x420c4445, 0xc2395556},
+{'l', 0x00000000, 0x41222224},
+{'l', 0xc2022223, 0x00000000},
+{'l', 0x35400000, 0xc1222224},
+{'l', 0x42022223, 0x00000000},
+{'@', 0x0000002e, 0x00002400},/*        .        x-advance: 36.000000 */
+{'M', 0x4119999a, 0xc0d11112},
+{'8', 0xd60fe700, 0xef2def10},
+{'8', 0x112d001d, 0x2a101110},
+{'8', 0x29f01800, 0x11d311f1},
+{'8', 0xefd300e3, 0xd7f1eff1},
+{'@', 0x0000002f, 0x00003855},/*        /        x-advance: 56.332031 */
+{'M', 0x42515556, 0xc2c22223},
+{'l', 0xc221ddde, 0x42d2ccce},
+{'l', 0xc129999c, 0xb6000000},
+{'l', 0x42222223, 0xc2d2ccce},
+{'l', 0x41288888, 0x00000000},
+{'@', 0x00000030, 0x00004cbb},/*        0        x-advance: 76.730469 */
+{'M', 0x428a0000, 0xc225ddde},
+{'q', 0x00000000, 0x41beeeef},
+{0, 0xc1044440, 0x42055555},
+{'q', 0xc1033334, 0x41177779},
+{0, 0xc1b2aaac, 0x41177779},
+{'q', 0xc15bbbbc, 0x34c00000},
+{0, 0xc1b11111, 0xc1133334},
+{'9', 0xffb7ffbe, 0xff00ffbc},
+{'l', 0x00000000, 0xc182aaac},
+{'q', 0x00000000, 0xc1be6668},
+{0, 0x41055555, 0xc203bbbc},
+{'q', 0x41055556, 0xc1133330},
+{0, 0x41b22224, 0xc1133330},
+{'q', 0x415eeef0, 0x00000000},
+{0, 0x41b1999a, 0x410eeee8},
+{'9', 0x00460042, 0x00fd0044},
+{'6', 0x00820000, 0xff7aff9d},
+{'q', 0x00000000, 0xc1833334},
+{0, 0xc0955558, 0xc1b9999c},
+{'8', 0xca93cadb, 0x349500bb},
+{'9', 0x0034ffdb, 0x00b3ffda},
+{'l', 0x00000000, 0x419e6668},
+{'q', 0x00000000, 0x41822222},
+{0, 0x40977778, 0x41bbbbbc},
+{'8', 0x396c3926, 0xc86c0048},
+{'q', 0x40933338, 0xc0e44446},
+{0, 0x40955558, 0xc1b88888},
+{'l', 0x00000000, 0xc19b3334},
+{'@', 0x00000031, 0x00004cbb},/*        1        x-advance: 76.730469 */
+{'M', 0x42426667, 0xc2c33334},
+{'l', 0x00000000, 0x42c33334},
+{'l', 0xc1455554, 0x00000000},
+{'l', 0x00000000, 0xc2a46667},
+{'l', 0xc1c6eef0, 0x41111110},
+{'l', 0xb5800000, 0xc1322220},
+{'l', 0x420d1111, 0xc1555558},
+{'l', 0x3ff77780, 0x00000000},
+{'@', 0x00000032, 0x00004cbb},/*        2        x-advance: 76.730469 */
+{'M', 0x428f5556, 0xc1222223},
+{'l', 0x00000000, 0x41222223},
+{'4', 0x0000fe04, 0xffba0000},
+{'l', 0x4203bbbc, 0xc212aaac},
+{'q', 0x41022220, 0xc1133330},
+{0, 0x412eeef0, 0xc1699994},
+{'8', 0xaa16d516, 0x9fddc700},
+{'q', 0xc08cccc8, 0xc0a22220},
+{0, 0xc1477778, 0xc0a22220},
+{'q', 0xc11bbbbc, 0x00000000},
+{0, 0xc1688888, 0x40b11110},
+{'9', 0x002cffda, 0x0071ffda},
+{'l', 0xc1455556, 0x00000000},
+{'q', 0x35000000, 0xc1444440},
+{0, 0x41011112, 0xc1a88888},
+{'q', 0x41011112, 0xc10cccc8},
+{0, 0x41bccccd, 0xc10cccc8},
+{'q', 0x415bbbbc, 0x00000000},
+{0, 0x41abbbbc, 0x40e44440},
+{'q', 0x40f999a0, 0x40e44440},
+{0, 0x40f999a0, 0x41966668},
+{'q', 0x00000000, 0x41088884},
+{0, 0xc0a88888, 0x41899998},
+{'9', 0x0044ffd6, 0x0087ff99},
+{'l', 0xc1d00001, 0x41e1999a},
+{'l', 0x4242aaac, 0x35800000},
+{'@', 0x00000033, 0x00004cbb},/*        3        x-advance: 76.730469 */
+{'M', 0x41d08889, 0xc231ddde},
+{'4', 0xffaf0000, 0x00000048},
+{'q', 0x41188888, 0xbd888800},
+{0, 0x41633334, 0xc0999998},
+{'q', 0x40955558, 0xc0977780},
+{0, 0x40955558, 0xc13cccd0},
+{'q', 0x00000000, 0xc1888888},
+{0, 0xc1877778, 0xc1888888},
+{'8', 0x249b00c2, 0x60da23da},
+{'l', 0xc1455556, 0x00000000},
+{'q', 0x35000000, 0xc1322220},
+{0, 0x41033334, 0xc1977778},
+{'q', 0x41044444, 0xc0f99990},
+{0, 0x41addddf, 0xc0f99990},
+{'q', 0x41522220, 0x00000000},
+{0, 0x41a9999a, 0x40e00000},
+{'q', 0x41022220, 0x40ddddd0},
+{0, 0x41022220, 0x41a3bbbc},
+{'8', 0x5ce32b00, 0x4ca431e4},
+{'8', 0x4d69194d, 0x691c341c},
+{'q', 0x00000000, 0x4159999a},
+{0, 0xc10ccccc, 0x41a80000},
+{'q', 0xc10ccccc, 0x40eccccf},
+{0, 0xc1af7778, 0x40eccccf},
+{'q', 0xc14aaaac, 0xb4000000},
+{0, 0xc1adddde, 0xc0e00001},
+{'9', 0xffc8ffb8, 0xff60ffb8},
+{'l', 0x41455556, 0x00000000},
+{'8', 0x62273d00, 0x246c2428},
+{'8', 0xdd6b0043, 0x9427dd27},
+{'q', 0x00000000, 0xc1111112},
+{0, 0xc0b33338, 0xc1555556},
+{'q', 0xc0b33330, 0xc08aaaa8},
+{0, 0xc1700000, 0xc08aaaa8},
+{'l', 0xc10cccce, 0x00000000},
+{'@', 0x00000034, 0x00004cbb},/*        4        x-advance: 76.730469 */
+{'M', 0x40622223, 0xc1ee6667},
+{'l', 0x422ddddf, 0xc2868889},
+{'l', 0x41522220, 0x00000000},
+{'l', 0x00000000, 0x4280ccce},
+{'l', 0x4158888c, 0xb6800000},
+{'l', 0x00000000, 0x41222222},
+{'l', 0xc158888c, 0x00000000},
+{'l', 0x00000000, 0x41b44445},
+{'l', 0xc1455554, 0x00000000},
+{'4', 0xff4c0000, 0x0000fe9e},
+{'6', 0xffc60000, 0xffea0070},
+{'l', 0x41f22223, 0x00000000},
+{'l', 0x00000000, 0xc23eaaab},
+{'l', 0xbfc44440, 0x402eeee0},
+{'l', 0xc1e5dddf, 0x4233bbbd},
+{'@', 0x00000035, 0x00004cbb},/*        5        x-advance: 76.730469 */
+{'M', 0x41bd5556, 0xc238cccd},
+{'l', 0xc11dddde, 0xc0222230},
+{'l', 0x409bbbbc, 0xc2415556},
+{'l', 0x42473333, 0x00000000},
+{'4', 0x005b0000, 0x0000fec6},
+{'l', 0xc03bbbc0, 0x41d33334},
+{'q', 0x40eaaab0, 0xc0866668},
+{0, 0x4181999a, 0xc0866668},
+{'q', 0x41566668, 0x00000000},
+{0, 0x41a91112, 0x410ddde0},
+{'q', 0x40f99998, 0x410ccccc},
+{0, 0x40f99998, 0x41bd5556},
+{'q', 0x00000000, 0x415eeef0},
+{0, 0xc0f33330, 0x41b91112},
+{'q', 0xc0f33338, 0x41122221},
+{0, 0xc1b91112, 0x41122221},
+{'q', 0xc13cccce, 0x34c00000},
+{0, 0xc1a33334, 0xc0d33333},
+{'9', 0xffcbffbc, 0xff5effb1},
+{'l', 0x413bbbbd, 0x00000000},
+{'q', 0x40155550, 0x4185ddde},
+{0, 0x4194cccd, 0x4185ddde},
+{'q', 0x410bbbbc, 0x35800000},
+{0, 0x41588888, 0xc0bdddde},
+{'q', 0x409999a0, 0xc0bdddde},
+{0, 0x409999a0, 0xc1808888},
+{'q', 0x00000000, 0xc1122224},
+{0, 0xc0a22228, 0xc1755558},
+{'q', 0xc0a00000, 0xc0c88888},
+{0, 0xc1655554, 0xc0c88888},
+{'8', 0x0db500cf, 0x24cd0de7},
+{'@', 0x00000036, 0x00004cbb},/*        6        x-advance: 76.730469 */
+{'M', 0x428c6667, 0xc1fd5556},
+{'q', 0x00000000, 0x415cccce},
+{0, 0xc0f77778, 0x41bb3334},
+{'q', 0xc0f55558, 0x41199999},
+{0, 0xc1b33334, 0x41199999},
+{'q', 0xc1277778, 0x34c00000},
+{0, 0xc18b3334, 0xc0b11111},
+{'q', 0xc0ddddde, 0xc0b33333},
+{0, 0xc1266667, 0xc1622222},
+{'9', 0xffbcffe5, 0xff74ffe5},
+{'l', 0x00000000, 0xc0b999a0},
+{'q', 0x00000000, 0xc15aaaa8},
+{0, 0x40733334, 0xc1d33334},
+{'q', 0x4077777c, 0xc14bbbb8},
+{0, 0x415eeef1, 0xc1a6eef0},
+{'9', 0xffbf0050, 0xffbf00e6},
+{'4', 0x00000008, 0x00530000},
+{'q', 0xc14eeef0, 0x00000000},
+{0, 0xc1a11112, 0x40911110},
+{'q', 0xc0e44448, 0x40911110},
+{0, 0xc12aaaac, 0x413cccd0},
+{'q', 0xc05ddde0, 0x40e66660},
+{0, 0xc0866668, 0x41777778},
+{'q', 0x40f77778, 0xc10bbbc0},
+{0, 0x41a6eef0, 0xc10bbbc0},
+{'q', 0x411aaaac, 0x00000000},
+{0, 0x417ccccc, 0x40955558},
+{'q', 0x40c66668, 0x40955558},
+{0, 0x41122224, 0x41411114},
+{'9', 0x003a0017, 0x007a0017},
+{'m', 0xc243bbbc, 0xc0777780},
+{'q', 0xb6000000, 0x414eeef2},
+{0, 0x40b77774, 0x419e6668},
+{'8', 0x3668362e, 0xcf690044},
+{'q', 0x40977778, 0xc0c88888},
+{0, 0x40977778, 0xc1800000},
+{'q', 0x00000000, 0xc10aaaaa},
+{0, 0xc08aaab0, 0xc178888a},
+{'8', 0xca96cade, 0x1ea300cd},
+{'q', 0xc0a8888c, 0x40777770},
+{0, 0xc0eaaaac, 0x41166668},
+{'l', 0x00000000, 0x40955550},
+{'@', 0x00000037, 0x00004cbb},/*        7        x-advance: 76.730469 */
+{'M', 0x428d999a, 0xc2c22223},
+{'l', 0x00000000, 0x40dddde0},
+{'l', 0xc220cccd, 0x42b44445},
+{'l', 0xc1500002, 0x00000000},
+{'l', 0x4220888a, 0xc2adddde},
+{'l', 0xc2522223, 0x00000000},
+{'l', 0xb5000000, 0xc1222228},
+{'l', 0x42833334, 0x00000000},
+{'@', 0x00000038, 0x00004cbb},/*        8        x-advance: 76.730469 */
+{'M', 0x428a8889, 0xc1d22223},
+{'q', 0x00000000, 0x41555556},
+{0, 0xc10eeef0, 0x41a3bbbc},
+{'q', 0xc10ddddc, 0x40e44447},
+{0, 0xc1af7778, 0x40e44447},
+{'q', 0xc1511112, 0xb4000000},
+{0, 0xc1b00000, 0xc0e44445},
+{'q', 0xc10ddddf, 0xc0e44446},
+{0, 0xc10ddddf, 0xc1a3bbbc},
+{'q', 0x00000000, 0xc1022224},
+{0, 0x408aaaac, 0xc1655558},
+{'8', 0xb55ece23, 0xbaaee7cd},
+{'q', 0xc06eeef0, 0xc0b77778},
+{0, 0xc06eeef0, 0xc14ddddc},
+{'q', 0x00000000, 0xc14bbbc0},
+{0, 0x41011112, 0xc19d5558},
+{'q', 0x41022222, 0xc0ddddd0},
+{0, 0x41a44445, 0xc0ddddd0},
+{'q', 0x41477778, 0x00000000},
+{0, 0x41a44444, 0x40ddddd0},
+{'q', 0x41022220, 0x40dddde0},
+{0, 0x41022220, 0x419d5558},
+{'8', 0x67e23900, 0x46ae2de2},
+{'q', 0x40f11110, 0x404cccd0},
+{0, 0x41400000, 0x41177778},
+{'9', 0x00320023, 0x00720023},
+{'m', 0xc169999c, 0xc2355556},
+{'8', 0xa1dcc600, 0xdba2dbdc},
+{'8', 0x24a300c6, 0x61dd23dd},
+{'8', 0x60233c00, 0x245e2423},
+{'8', 0xdc5d003a, 0xa024dc24},
+{'m', 0x400cccd0, 0x42344446},
+{'8', 0x96d7bf00, 0xd795d7d7},
+{'8', 0x299500bd, 0x6ad929d9},
+{'8', 0x68274300, 0x256c2528},
+{'8', 0xdb6c0044, 0x9827db27},
+{'@', 0x00000039, 0x00004cbb},/*        9        x-advance: 76.730469 */
+{'M', 0x42877778, 0xc25aaaab},
+{'q', 0x00000000, 0x41177778},
+{0, 0xbfd55540, 0x41991110},
+{'q', 0xbfcccd00, 0x4119999c},
+{0, 0xc0caaab0, 0x418ddddf},
+{'q', 0xc0955558, 0x41011112},
+{0, 0xc15ddde0, 0x41500001},
+{'9', 0x0027ffb7, 0x0027ff34},
+{'l', 0x00000000, 0xc1277778},
+{'q', 0x416bbbbe, 0x00000000},
+{0, 0x41aeeeef, 0xc0933334},
+{'q', 0x40e66668, 0xc0933334},
+{0, 0x41200004, 0xc1400000},
+{'q', 0x40377770, 0xc0eeeef0},
+{0, 0x404cccc0, 0xc17ddde0},
+{'8', 0x3bb624e2, 0x16a316d5},
+{'q', 0xc119999a, 0x00000000},
+{0, 0xc17bbbbc, 0xc09999a0},
+{'q', 0xc0c44446, 0xc0999998},
+{0, 0xc1111112, 0xc1433334},
+{'q', 0xc03bbbbc, 0xc0eeeef0},
+{0, 0xc03bbbbc, 0xc1766664},
+{'q', 0x00000000, 0xc15ddde0},
+{0, 0x40f33334, 0xc1bd5558},
+{'q', 0x40f55556, 0xc11dddd8},
+{0, 0x41b44446, 0xc11dddd8},
+{'q', 0x41311110, 0x00000000},
+{0, 0x418eeeee, 0x40b77770},
+{'q', 0x40dbbbc0, 0x40b77780},
+{0, 0x411eeef4, 0x416bbbc0},
+{'9', 0x00480019, 0x00960019},
+{'6', 0x00230000, 0xffaafe79},
+{'q', 0xb6000000, 0x410aaab0},
+{0, 0x408aaaa8, 0x417bbbc0},
+{'8', 0x386a3823, 0xe25b0032},
+{'9', 0xffe20029, 0xffb5003c},
+{'l', 0x00000000, 0xc09bbbc0},
+{'q', 0x00000000, 0xc1544448},
+{0, 0xc0b55558, 0xc1a2aaac},
+{'8', 0xc898c8d4, 0x349600bc},
+{'q', 0xc0955554, 0x40ceeef0},
+{0, 0xc0955554, 0x41811110},
+{'@', 0x0000003a, 0x00002111},/*        :        x-advance: 33.066406 */
+{'M', 0x410dddde, 0xc0d11112},
+{'8', 0xd60fe700, 0xef2def10},
+{'8', 0x112d001d, 0x2a101110},
+{'8', 0x29f01800, 0x11d311f1},
+{'8', 0xefd300e3, 0xd7f1eff1},
+{'m', 0x3d888880, 0xc26b7778},
+{'8', 0xd60fe700, 0xef2def10},
+{'8', 0x112d001d, 0x2a101110},
+{'8', 0x29f01800, 0x11d311f1},
+{'8', 0xefd300e3, 0xd7f1eff1},
+{'@', 0x0000003b, 0x00001cdd},/*        ;        x-advance: 28.863281 */
+{'M', 0x40eaaaab, 0xc282cccd},
+{'8', 0xd60fe700, 0xef2def10},
+{'8', 0x112d001d, 0x2a101110},
+{'8', 0x29f01800, 0x11d311f1},
+{'8', 0xefd300e3, 0xd7f1eff1},
+{'m', 0x41611112, 0x424aeeef},
+{'l', 0x00000000, 0x411eeef0},
+{'8', 0x66e83000, 0x5abc35e8},
+{'l', 0xc0e00000, 0xc09bbbbe},
+{'9', 0xffb90033, 0xff6e0034},
+{'l', 0x00000000, 0xc12eeef0},
+{'l', 0x41411112, 0x00000000},
+{'@', 0x0000003c, 0x00004566},/*        <        x-advance: 69.398438 */
+{'M', 0x426d5556, 0xc1511112},
+{'l', 0xc25a2223, 0xc1ca2223},
+{'l', 0x35800000, 0xc11aaaac},
+{'l', 0x425a2223, 0xc1c9999a},
+{'l', 0x00000000, 0x41511114},
+{'l', 0xc2266667, 0x41891110},
+{'l', 0x42266667, 0x4186eef0},
+{'l', 0x00000000, 0x41511112},
+{'@', 0x0000003d, 0x00004aee},/*        =        x-advance: 74.929688 */
+{'M', 0x42837778, 0xc2820000},
+{'l', 0x00000000, 0x412bbbb8},
+{'4', 0x0000fe44, 0xffab0000},
+{'6', 0x000001bc, 0x00dd0000},
+{'l', 0x00000000, 0x412bbbbc},
+{'l', 0xc25e6667, 0x00000000},
+{'l', 0xb5800000, 0xc12bbbbc},
+{'l', 0x425e6667, 0x00000000},
+{'@', 0x0000003e, 0x00004766},/*        >        x-advance: 71.398438 */
+{'M', 0x41100000, 0xc292aaab},
+{'l', 0x4263bbbc, 0x41c9999a},
+{'l', 0x00000000, 0x411bbbbc},
+{'l', 0xc263bbbc, 0x41ca2222},
+{'l', 0x00000000, 0xc14bbbbc},
+{'l', 0x42308889, 0xc18c4444},
+{'l', 0xc2308889, 0xc189999a},
+{'l', 0x00000000, 0xc14bbbbc},
+{'@', 0x0000003f, 0x00004088},/*        ?        x-advance: 64.531250 */
+{'M', 0x4210cccd, 0xc1daaaab},
+{'l', 0xc1466666, 0x00000000},
+{'q', 0x3d888900, 0xc11aaaae},
+{0, 0x402aaaa8, 0xc167777a},
+{'8', 0xa646da14, 0xbb3fdc23},
+{'8', 0xa91bdf1b, 0xaae3ca00},
+{'8', 0xe0ace0e3, 0x19ad00d2},
+{'9', 0x0019ffdc, 0x0050ffdb},
+{'l', 0xc1455556, 0x00000000},
+{'q', 0x3e0888a0, 0xc1344448},
+{0, 0x41000001, 0xc18d5558},
+{'q', 0x40fdddde, 0xc0ccccc0},
+{0, 0x419bbbbc, 0xc0ccccc0},
+{'q', 0x414bbbbc, 0x00000000},
+{0, 0x419d5556, 0x40d99990},
+{'q', 0x40e00000, 0x40d999a0},
+{0, 0x40e00000, 0x41944444},
+{'q', 0x00000000, 0x410eeef0},
+{0, 0xc0a88888, 0x4180888a},
+{'q', 0xc0a88888, 0x40e22228},
+{0, 0xc1377778, 0x414cccd0},
+{'9', 0x002dffcf, 0x0086ffcf},
+{'m', 0xc14eeeee, 0x41a91111},
+{'8', 0xd80ee800, 0xf02bf00e},
+{'8', 0x102b001c, 0x280e100e},
+{'8', 0x27f21600, 0x10d510f2},
+{'8', 0xf0d500e4, 0xd9f2f0f2},
+{'@', 0x00000040, 0x00007a99},/*        @        x-advance: 122.597656 */
+{'M', 0x42a8aaab, 0x41c22223},
+{'8', 0x23a318db, 0x0b970bc9},
+{'q', 0xc1caaaac, 0x00000000},
+{0, 0xc21cccce, 0xc1855556},
+{'q', 0xc15ccccb, 0xc185ddde},
+{0, 0xc1499998, 0xc235999a},
+{'q', 0x3f4cccd0, 0xc1922222},
+{0, 0x40fddde0, 0xc2026666},
+{'q', 0x40e66668, 0xc1666668},
+{0, 0x419d5556, 0xc1b55558},
+{'q', 0x41488888, 0xc1044440},
+{0, 0x41ea2224, 0xc1044440},
+{'q', 0x41cd5554, 0x00000000},
+{0, 0x421bbbbc, 0x4185dddc},
+{'q', 0x41555558, 0x4185ddde},
+{0, 0x41433330, 0x42348889},
+{'q', 0xbeaaaa00, 0x41033336},
+{0, 0xc0488880, 0x41822223},
+{'q', 0xc02eef00, 0x41011112},
+{0, 0xc10aaaa8, 0x41566668},
+{'q', 0xc0bbbbc0, 0x40a88889},
+{0, 0xc1777778, 0x40a88889},
+{'q', 0xc1488890, 0x00000000},
+{0, 0xc1800004, 0xc1355556},
+{'q', 0xc0e66660, 0x41355556},
+{0, 0xc18eeeee, 0x41355556},
+{'q', 0xc11ccccc, 0x35000000},
+{0, 0xc1677778, 0xc1011111},
+{'q', 0xc0955558, 0xc1011112},
+{0, 0xc05ddde0, 0xc1a9999a},
+{'q', 0x3fc44440, 0xc18c4444},
+{0, 0x41200000, 0xc1de6666},
+{'q', 0x4108888c, 0xc1255554},
+{0, 0x4196eef2, 0xc1255554},
+{'8', 0x115a0039, 0x273e1021},
+{'l', 0xc05999a0, 0x4213bbbc},
+{'8', 0x64114dfa, 0x16321618},
+{'q', 0x41011118, 0x00000000},
+{0, 0x41466668, 0xc0fbbbbc},
+{'q', 0x408cccd0, 0xc0fbbbbe},
+{0, 0x409bbbc0, 0xc1991112},
+{'q', 0x3f911100, 0xc1c6eeee},
+{0, 0xc1144448, 0xc21c0001},
+{'q', 0xc1255550, 0xc1622220},
+{0, 0xc2062222, 0xc1622220},
+{'q', 0xc1a80000, 0x00000000},
+{0, 0xc205ddde, 0x41733338},
+{'q', 0xc1477778, 0x41733330},
+{0, 0xc1577778, 0x421e6666},
+{'q', 0xbf9999a0, 0x41c77778},
+{0, 0x411eeeee, 0x421d5556},
+{'q', 0x41333336, 0x41666668},
+{0, 0x4201ddde, 0x41666668},
+{'8', 0xf55e002e, 0xe251f530},
+{'6', 0x003c0014, 0xfe5ffed8},
+{'q', 0xbf5dde00, 0x4116666a},
+{0, 0x3fe66660, 0x4168888c},
+{'8', 0x29442915, 0xe83a001b},
+{'9', 0xffe8001e, 0xffaf0034},
+{'4', 0xfffc0000, 0xfef50018},
+{'8', 0xf1c0f1e3, 0x3b9b00c6},
+{'q', 0xc0aaaaa8, 0x40eeeef0},
+{0, 0xc0d55550, 0x41b08888},
+{'@', 0x00000041, 0x00005911},/*        A        x-advance: 89.066406 */
+{'M', 0x3ff77778, 0x00000000},
+{'l', 0x42140000, 0xc2c22223},
+{'l', 0x41344444, 0x00000000},
+{'l', 0x42148889, 0x42c22223},
+{'l', 0xc1533330, 0x00000000},
+{'l', 0xc1144448, 0xc1cb3334},
+{'4', 0x0000febc, 0x00cbffb7},
+{'6', 0x0000ff97, 0xfee100d1},
+{'l', 0x4203bbbc, 0x00000000},
+{'l', 0xc183bbbc, 0xc2351112},
+{'l', 0xc183bbbc, 0x42351112},
+{'[', 0x007a0041, 0x000000cc},/*kerning*/
+{'@', 0x00000042, 0x00005511},/*        B        x-advance: 85.066406 */
+{'M', 0x429aaaab, 0xc1e00001},
+{'q', 0x00000000, 0x4159999b},
+{0, 0xc10cccc8, 0x41a66667},
+{'9', 0x0039ffbb, 0x0039ff46},
+{'4', 0x0000fef0, 0xfcf80000},
+{'l', 0x41fe6668, 0x00000000},
+{'q', 0x416eeef0, 0x00000000},
+{0, 0x41ba2222, 0x40c66670},
+{'q', 0x41066668, 0x40c44440},
+{0, 0x41066668, 0x419d5554},
+{'8', 0x60e23500, 0x40ad29e2},
+{'q', 0x41033338, 0x40111110},
+{0, 0x41488888, 0x41099998},
+{'9', 0x00320023, 0x00740023},
+{'m', 0xc254cccd, 0xc26a2224},
+{'4', 0x00f60000, 0x0000009a},
+{'8', 0xdf6a0042, 0xa528df28},
+{'9', 0xff8a0000, 0xff87ff70},
+{'6', 0x0000ff63, 0x01d50143},
+{'q', 0x00000000, 0xc1022220},
+{0, 0xc08eeef8, 0xc14ccccc},
+{'9', 0xffdbffdd, 0xffdbff8f},
+{'4', 0x0000ff53, 0x01170000},
+{'l', 0x41a91112, 0x00000000},
+{'q', 0x41122220, 0x00000000},
+{0, 0x41633334, 0xc0955556},
+{'q', 0x40a22228, 0xc0977776},
+{0, 0x40a22228, 0xc14bbbbd},
+{'@', 0x00000043, 0x000058dd},/*        C        x-advance: 88.863281 */
+{'M', 0x428bbbbc, 0xc1f6eef0},
+{'l', 0x414cccd0, 0x00000000},
+{'q', 0xbfbbbbc0, 0x415cccce},
+{0, 0xc1266668, 0x41b80001},
+{'q', 0xc10eeef0, 0x41133333},
+{0, 0xc1d33334, 0x41133333},
+{'q', 0xc1877778, 0x34c00000},
+{0, 0xc1daaaab, 0xc1411111},
+{'9', 0xff9fffae, 0xfeffffac},
+{'l', 0x00000000, 0xc1266668},
+{'q', 0x00000000, 0xc1a33334},
+{0, 0x41277778, 0xc202eef0},
+{'q', 0x4128888a, 0xc1455550},
+{0, 0x41e44446, 0xc1455550},
+{'q', 0x4183bbbc, 0x00000000},
+{0, 0x41caaaaa, 0x41111110},
+{'9', 0x00480046, 0x00bb0052},
+{'l', 0xc14cccd0, 0x00000000},
+{'q', 0xbfbbbbc0, 0xc1222228},
+{0, 0xc0d11110, 0xc1800000},
+{'q', 0xc0a22220, 0xc0bddde0},
+{0, 0xc182aaaa, 0xc0bddde0},
+{'q', 0xc14ddde0, 0x00000000},
+{0, 0xc19c4446, 0x41177778},
+{'9', 0x004bffcb, 0x00c7ffcb},
+{'l', 0x00000000, 0x411cccd0},
+{'q', 0x00000000, 0x41655556},
+{0, 0x40c22224, 0x41c3bbbc},
+{'q', 0x40c22220, 0x41211111},
+{0, 0x41980000, 0x41211111},
+{'q', 0x41444444, 0x00000000},
+{0, 0x418a2222, 0xc0b77778},
+{'q', 0x40a22228, 0xc0b77776},
+{0, 0x40d77778, 0xc1800000},
+{'@', 0x00000044, 0x00005999},/*        D        x-advance: 89.597656 */
+{'M', 0x41344445, 0x00000000},
+{'4', 0xfcf80000, 0x000000db},
+{'q', 0x41991112, 0x00000000},
+{0, 0x41f7777a, 0x41455558},
+{'9', 0x0062005e, 0x010a005e},
+{'l', 0x00000000, 0x40b99998},
+{'q', 0x00000000, 0x41a88889},
+{0, 0xc13eeef0, 0x42055556},
+{'9', 0x0062ffa2, 0x0062ff00},
+{'6', 0x0000ff2e, 0xfd4c0066},
+{'4', 0x02600000, 0x0000006b},
+{'q', 0x41788888, 0x00000000},
+{0, 0x41bb3334, 0xc119999a},
+{'9', 0xffb4003e, 0xff34003e},
+{'l', 0x00000000, 0xc0bddde0},
+{'q', 0x00000000, 0xc185ddde},
+{0, 0xc0fbbbb8, 0xc1ceeeee},
+{'q', 0xc0fbbbc0, 0xc1122228},
+{0, 0xc1b1999c, 0xc1122228},
+{'l', 0xc1699998, 0x00000000},
+{'@', 0x00000045, 0x00004d99},/*        E        x-advance: 77.597656 */
+{'M', 0x41344445, 0x00000000},
+{'l', 0x00000000, 0xc2c22223},
+{'l', 0x42740001, 0x00000000},
+{'l', 0x00000000, 0x41288888},
+{'l', 0xc2408889, 0x00000000},
+{'l', 0x00000000, 0x41f9999c},
+{'l', 0x42280001, 0x00000000},
+{'l', 0x00000000, 0x41277778},
+{'l', 0xc2280001, 0x00000000},
+{'l', 0x00000000, 0x4209999a},
+{'l', 0x42433333, 0x00000000},
+{'l', 0x00000000, 0x41277778},
+{'l', 0xc276aaab, 0x00000000},
+{'[', 0x00540045, 0x00000155},/*kerning*/
+{'@', 0x00000046, 0x00004b77},/*        F        x-advance: 75.464844 */
+{'M', 0x41344445, 0x00000000},
+{'l', 0x00000000, 0xc2c22223},
+{'l', 0x42708889, 0x00000000},
+{'l', 0x00000000, 0x41288888},
+{'l', 0xc23d1111, 0x00000000},
+{'l', 0x00000000, 0x4204888a},
+{'l', 0x4222aaab, 0x00000000},
+{'l', 0x00000000, 0x41288888},
+{'l', 0xc222aaab, 0x00000000},
+{'l', 0x00000000, 0x422b7778},
+{'l', 0xc14ddddf, 0x00000000},
+{'[', 0x00540046, 0x00000155},/*kerning*/
+{'@', 0x00000047, 0x00005d00},/*        G        x-advance: 93.000000 */
+{'M', 0x42a60001, 0xc2415556},
+{'l', 0x00000000, 0x420e2222},
+{'q', 0xc02eef00, 0x40800006},
+{0, 0xc1266668, 0x41111114},
+{'q', 0xc0f55560, 0x40a22223},
+{0, 0xc1bf777a, 0x40a22223},
+{'q', 0xc18dddde, 0xb4000000},
+{0, 0xc1e91111, 0xc1422222},
+{'9', 0xff9fffa5, 0xfef0ffa5},
+{'l', 0x00000000, 0xc0f11110},
+{'q', 0x00000000, 0xc1ad5558},
+{0, 0x41222223, 0xc2077778},
+{'q', 0x41222222, 0xc1433330},
+{0, 0x41e77777, 0xc1433330},
+{'q', 0x41855556, 0x00000000},
+{0, 0x41ca2222, 0x41066660},
+{'9', 0x00430045, 0x00aa0054},
+{'l', 0xc14ddde0, 0x00000000},
+{'q', 0xbfaaaac0, 0xc0fbbbc0},
+{0, 0xc0d33338, 0xc1588888},
+{'q', 0xc0a66668, 0xc0b55550},
+{0, 0xc182aaac, 0xc0b55550},
+{'q', 0xc1566664, 0x00000000},
+{0, 0xc19dddde, 0x41177778},
+{'9', 0x004bffce, 0x00ccffcd},
+{'l', 0x00000000, 0x41000000},
+{'q', 0x00000000, 0x41866667},
+{0, 0x40f33334, 0x41d22223},
+{'q', 0x40f33338, 0x41166667},
+{0, 0x41a0888a, 0x41166667},
+{'q', 0x41255554, 0x00000000},
+{0, 0x416eeef0, 0xc0199998},
+{'9', 0xffed0024, 0xffdb0034},
+{'l', 0x00000000, 0xc1adddde},
+{'l', 0xc1b3bbbc, 0x00000000},
+{'l', 0x00000000, 0xc1266668},
+{'l', 0x420d1112, 0x00000000},
+{'@', 0x00000048, 0x00006166},/*        H        x-advance: 97.398438 */
+{'M', 0x42922223, 0x00000000},
+{'l', 0x00000000, 0xc2337778},
+{'l', 0xc243bbbd, 0x00000000},
+{'l', 0x00000000, 0x42337778},
+{'l', 0xc14ddddf, 0x00000000},
+{'l', 0x00000000, 0xc2c22223},
+{'l', 0x414ddddf, 0x00000000},
+{'l', 0x00000000, 0x4226eef0},
+{'l', 0x4243bbbd, 0x00000000},
+{'l', 0x00000000, 0xc226eef0},
+{'l', 0x414cccc8, 0x00000000},
+{'l', 0x00000000, 0x42c22223},
+{'l', 0xc14cccc8, 0x00000000},
+{'@', 0x00000049, 0x00002522},/*        I        x-advance: 37.132812 */
+{'M', 0x41c88889, 0xc2c22223},
+{'l', 0x00000000, 0x42c22223},
+{'l', 0xc14dddde, 0x00000000},
+{'l', 0x00000000, 0xc2c22223},
+{'l', 0x414dddde, 0x00000000},
+{'@', 0x0000004a, 0x00004b55},/*        J        x-advance: 75.332031 */
+{'M', 0x42500001, 0xc2c22223},
+{'4', 0x00000066, 0x02250000},
+{'q', 0x00000000, 0x41666668},
+{0, 0xc10aaaac, 0x41b0888a},
+{'q', 0xc1099998, 0x40f33333},
+{0, 0xc1af7778, 0x40f33333},
+{'q', 0xc1566666, 0xb4000000},
+{0, 0xc1b08888, 0xc0dddddf},
+{'9', 0xffc9ffbc, 0xff56ffbc},
+{'l', 0x414ddddf, 0x00000000},
+{'8', 0x6b274900, 0x22662228},
+{'q', 0x40f33338, 0x00000000},
+{0, 0x414aaaac, 0xc09bbbbc},
+{'q', 0x40a44448, 0xc09bbbba},
+{0, 0x40a44448, 0xc1655555},
+{'l', 0x00000000, 0xc2897778},
+{'@', 0x0000004b, 0x000055aa},/*        K        x-advance: 85.664062 */
+{'M', 0x428caaab, 0x00000000},
+{'l', 0xc2095556, 0xc234cccd},
+{'l', 0xc13ddddc, 0x41455554},
+{'l', 0x00000000, 0x42037778},
+{'l', 0xc14ddddf, 0x00000000},
+{'l', 0x00000000, 0xc2c22223},
+{'l', 0x414ddddf, 0x00000000},
+{'l', 0x00000000, 0x423f7779},
+{'l', 0x422c8889, 0xc23f7779},
+{'l', 0x41777778, 0x00000000},
+{'l', 0xc2188889, 0x422b7778},
+{'l', 0x42244445, 0x4258ccce},
+{'l', 0xc1755558, 0x00000000},
+{'@', 0x0000004c, 0x00004988},/*        L        x-advance: 73.531250 */
+{'M', 0x428c4445, 0xc1277778},
+{'l', 0x00000000, 0x41277778},
+{'l', 0xc26b7779, 0x00000000},
+{'l', 0x35800000, 0xc2c22223},
+{'l', 0x414ddddf, 0x00000000},
+{'l', 0x00000000, 0x42ad3334},
+{'l', 0x42380001, 0x00000000},
+{'[', 0x0041004c, 0x00000144},/*kerning*/
+{'@', 0x0000004d, 0x00007733},/*        M        x-advance: 119.199219 */
+{'M', 0x426e6667, 0xc18f7778},
+{'l', 0x41fdddde, 0xc29e4445},
+{'l', 0x41844444, 0x00000000},
+{'l', 0x00000000, 0x42c22223},
+{'l', 0xc14cccc8, 0x00000000},
+{'l', 0x00000000, 0xc2177778},
+{'l', 0x3fa22200, 0xc2226666},
+{'l', 0xc1ff7778, 0x429ceeef},
+{'l', 0xc11bbbbc, 0x00000000},
+{'l', 0xc1feeeef, 0xc29d3334},
+{'l', 0x3fa22220, 0x4222eef0},
+{'l', 0x00000000, 0x42177778},
+{'l', 0xc14ccccd, 0x00000000},
+{'l', 0x00000000, 0xc2c22223},
+{'l', 0x41844444, 0x00000000},
+{'l', 0x41fe6668, 0x429e4445},
+{'@', 0x0000004e, 0x00006166},/*        N        x-advance: 97.398438 */
+{'M', 0x42abddde, 0xc2c22223},
+{'l', 0x00000000, 0x42c22223},
+{'l', 0xc14eeef0, 0x00000000},
+{'l', 0xc2437777, 0xc295bbbc},
+{'l', 0x00000000, 0x4295bbbc},
+{'l', 0xc14ddddf, 0x00000000},
+{'l', 0x00000000, 0xc2c22223},
+{'l', 0x414ddddf, 0x00000000},
+{'l', 0x42444445, 0x42962223},
+{'l', 0x00000000, 0xc2962223},
+{'l', 0x414bbbb8, 0x00000000},
+{'@', 0x0000004f, 0x00005dee},/*        O        x-advance: 93.929688 */
+{'M', 0x42ac0001, 0xc235ddde},
+{'q', 0x00000000, 0x41aeeeef},
+{0, 0xc12999a0, 0x42095555},
+{'q', 0xc1299998, 0x41477779},
+{0, 0xc1e2aaaa, 0x41477779},
+{'q', 0xc18a2223, 0x34c00000},
+{0, 0xc1e1999b, 0xc1477778},
+{'9', 0xff9dffa9, 0xfeeeffa9},
+{'l', 0xb5000000, 0xc0c44448},
+{'q', 0x00000000, 0xc1ae6666},
+{0, 0x412dddde, 0xc2091111},
+{'q', 0x412dddde, 0xc1488888},
+{0, 0x41e11111, 0xc1488888},
+{'q', 0x418cccd0, 0x00000000},
+{0, 0x41e1999c, 0x41455550},
+{'9', 0x00620055, 0x010d0056},
+{'6', 0x00370000, 0xffceff9b},
+{'q', 0x00000000, 0xc18aaaac},
+{0, 0xc0dddde0, 0xc1d44444},
+{'q', 0xc0dddde0, 0xc1133338},
+{0, 0xc19b3334, 0xc1133338},
+{'q', 0xc13eeef0, 0x00000000},
+{0, 0xc1991111, 0x41133338},
+{'9', 0x0049ffc7, 0x00d4ffc7},
+{'l', 0x00000000, 0x40c88890},
+{'q', 0x00000000, 0x418bbbbb},
+{0, 0x40e66668, 0x41d5ddde},
+{'q', 0x40e88888, 0x41133333},
+{0, 0x4199999a, 0x41133333},
+{'q', 0x41488888, 0x00000000},
+{0, 0x419aaaaa, 0xc1133333},
+{'q', 0x40dbbbc0, 0xc1144446},
+{0, 0x40dbbbc0, 0xc1d5ddde},
+{'l', 0x00000000, 0xc0c88890},
+{'@', 0x00000050, 0x00005622},/*        P        x-advance: 86.132812 */
+{'M', 0x41c11112, 0xc2184445},
+{'l', 0x00000000, 0x42184445},
+{'4', 0x0000ff9a, 0xfcf80000},
+{'l', 0x420f3334, 0x00000000},
+{'q', 0x41844444, 0x00000000},
+{0, 0x41ca2222, 0x41055558},
+{'q', 0x410cccd0, 0x41055558},
+{0, 0x410cccd0, 0x41aa2224},
+{'q', 0x00000000, 0x41611110},
+{0, 0xc10cccd0, 0x41addddc},
+{'9', 0x003dffbb, 0x003dff36},
+{'6', 0x0000ff49, 0xfe7d0000},
+{'4', 0x01300000, 0x000000b7},
+{'q', 0x41355554, 0x00000000},
+{0, 0x41822222, 0xc0a88888},
+{'8', 0x9427d627, 0x96d9c500},
+{'q', 0xc09ddde0, 0xc0bbbbc0},
+{0, 0xc1822222, 0xc0bbbbc0},
+{'l', 0xc1b77778, 0x00000000},
+{'[', 0x00740050, 0x000000ee},/*kerning*/
+{'[', 0x00760050, 0x00000100},/*kerning*/
+{'[', 0x00790050, 0x00000100},/*kerning*/
+{'@', 0x00000051, 0x00005dee},/*        Q        x-advance: 93.929688 */
+{'M', 0x42ab7778, 0x41066667},
+{'4', 0x0040ffbb, 0xff7eff5d},
+{'q', 0xc0999998, 0x3f99999b},
+{0, 0xc1222220, 0x3f99999b},
+{'q', 0xc18a2224, 0x00000000},
+{0, 0xc1e1999b, 0xc1477778},
+{'9', 0xff9dffa9, 0xfeeeffa9},
+{'l', 0xb5000000, 0xc0c44448},
+{'q', 0x00000000, 0xc1ae6666},
+{0, 0x412dddde, 0xc2091111},
+{'q', 0x412dddde, 0xc1488888},
+{0, 0x41e11112, 0xc1488888},
+{'q', 0x418cccce, 0x00000000},
+{0, 0x41e1999c, 0x41455550},
+{'9', 0x00620055, 0x010d0056},
+{'l', 0x00000000, 0x40dddde0},
+{'q', 0x00000000, 0x415ffffe},
+{0, 0xc08eeef0, 0x41c22222},
+{'9', 0x0051ffdd, 0x007fff9d},
+{'6', 0x006d008a, 0xfe1fff98},
+{'q', 0x00000000, 0xc18aaaac},
+{0, 0xc0dddde0, 0xc1d44444},
+{'q', 0xc0dddde0, 0xc1133338},
+{0, 0xc19b3334, 0xc1133338},
+{'q', 0xc13eeef0, 0x00000000},
+{0, 0xc1991112, 0x41133338},
+{'9', 0x0049ffc7, 0x00d4ffc7},
+{'l', 0x00000000, 0x40c88890},
+{'q', 0x00000000, 0x418bbbbb},
+{0, 0x40e66668, 0x41d5ddde},
+{'q', 0x40e8888c, 0x41133333},
+{0, 0x4199999b, 0x41133333},
+{'q', 0x41488888, 0x00000000},
+{0, 0x419aaaaa, 0xc1133333},
+{'q', 0x40dbbbc0, 0xc1144446},
+{0, 0x40dbbbc0, 0xc1d5ddde},
+{'l', 0x00000000, 0xc0c88890},
+{'@', 0x00000052, 0x00005422},/*        R        x-advance: 84.132812 */
+{'M', 0x42880000, 0x00000000},
+{'l', 0xc1a88888, 0xc21d5556},
+{'l', 0xc1b66666, 0x00000000},
+{'l', 0x00000000, 0x421d5556},
+{'4', 0x0000ff9a, 0xfcf80000},
+{'l', 0x42008889, 0x00000000},
+{'q', 0x4182aaac, 0x00000000},
+{0, 0x41c91114, 0x40eeeef0},
+{'q', 0x410dddd8, 0x40eeeef0},
+{0, 0x410dddd8, 0x41ad5558},
+{'q', 0x00000000, 0x41111110},
+{0, 0xc09ddde0, 0x417ddddc},
+{'9', 0x0035ffda, 0x0050ff94},
+{'4', 0x014900b6, 0x00060000},
+{'6', 0x0000ff93, 0xfd4cfea2},
+{'4', 0x01250000, 0x0000009d},
+{'q', 0x41255554, 0x00000000},
+{0, 0x41788888, 0xc0a88888},
+{'8', 0x9a2ad62a, 0x95d8bd00},
+{'q', 0xc0a00000, 0xc0a44450},
+{0, 0xc1811112, 0xc0a44450},
+{'l', 0xc19a2222, 0x00000000},
+{'@', 0x00000053, 0x00005111},/*        S        x-advance: 81.066406 */
+{'M', 0x427c0001, 0xc1c44445},
+{'q', 0x00000000, 0xc0d55554},
+{0, 0xc0911110, 0xc12aaaaa},
+{'q', 0xc08eeef0, 0xc0800000},
+{0, 0xc196eef0, 0xc1033334},
+{'q', 0xc1666668, 0xc0888888},
+{0, 0xc1b66667, 0xc12cccd0},
+{'q', 0xc1055556, 0xc0d33330},
+{0, 0xc1055556, 0xc18e6664},
+{'q', 0x00000000, 0xc1355558},
+{0, 0x41100000, 0xc196eef0},
+{'q', 0x41111112, 0xc0f11110},
+{0, 0x41c00000, 0xc0f11110},
+{'q', 0x41833334, 0x00000000},
+{0, 0x41ca2224, 0x41100000},
+{'9', 0x00480047, 0x00a20047},
+{'l', 0xc14cccd0, 0x00000000},
+{'q', 0x00000000, 0xc1022220},
+{0, 0xc0a88888, 0xc1577778},
+{'q', 0xc0a88888, 0xc0aaaaa0},
+{0, 0xc1811112, 0xc0aaaaa0},
+{'q', 0xc1244444, 0x00000000},
+{0, 0xc1733332, 0x40911110},
+{'8', 0x59d923d9, 0x51293000},
+{'q', 0x40a88888, 0x40800000},
+{0, 0x41888889, 0x40eaaab0},
+{'q', 0x4186eef0, 0x40977778},
+{0, 0x41c4ccce, 0x413bbbbc},
+{'q', 0x40f77770, 0x40dddde0},
+{0, 0x40f77770, 0x41922222},
+{'q', 0x00000000, 0x413dddde},
+{0, 0xc1144440, 0x41977778},
+{'q', 0xc1144448, 0x40e22223},
+{0, 0xc1c4ccce, 0x40e22223},
+{'q', 0xc10eeef0, 0xb4000000},
+{0, 0xc18b3334, 0xc0555556},
+{'q', 0xc1066666, 0xc0555556},
+{0, 0xc15ddddf, 0xc11ddddf},
+{'9', 0xffccffd5, 0xff7effd5},
+{'l', 0x414cccce, 0x00000000},
+{'q', 0x00000000, 0x411eeef0},
+{0, 0x40e88888, 0x41677779},
+{'q', 0x40e88888, 0x40911110},
+{0, 0x4184ccce, 0x40911110},
+{'q', 0x41211110, 0x00000000},
+{0, 0x41777778, 0xc0844444},
+{'q', 0x40aeeef0, 0xc0866666},
+{0, 0x40aeeef0, 0xc1344445},
+{'@', 0x00000054, 0x00005177},/*        T        x-advance: 81.464844 */
+{'M', 0x40555556, 0xc2ad1112},
+{'l', 0x00000000, 0xc1288888},
+{'l', 0x42960000, 0x00000000},
+{'l', 0x00000000, 0x41288888},
+{'l', 0xc1f9999a, 0x00000000},
+{'l', 0x00000000, 0x42ad1112},
+{'l', 0xc14aaaac, 0x00000000},
+{'l', 0x00000000, 0xc2ad1112},
+{'l', 0xc1f91111, 0x00000000},
+{'[', 0x00540054, 0x00000111},/*kerning*/
+{'[', 0x00560054, 0x00000111},/*kerning*/
+{'[', 0x00570054, 0x00000100},/*kerning*/
+{'[', 0x00590054, 0x00000111},/*kerning*/
+{'@', 0x00000055, 0x00005888},/*        U        x-advance: 88.531250 */
+{'M', 0x4285999a, 0xc2c22223},
+{'4', 0x00000066, 0x020d0000},
+{'q', 0x00000000, 0x41833334},
+{0, 0xc1288888, 0x41c4ccce},
+{'q', 0xc128888c, 0x41022221},
+{0, 0xc1c55558, 0x41022221},
+{'q', 0xc16dddde, 0x34c00000},
+{0, 0xc1c80000, 0xc1022222},
+{'9', 0xffbfffb0, 0xff3cffb0},
+{'4', 0xfdf30000, 0x00000065},
+{'l', 0x00000000, 0x42835556},
+{'q', 0x00000000, 0x41366666},
+{0, 0x40c44444, 0x4186eef0},
+{'q', 0x40c66668, 0x40acccca},
+{0, 0x4181999a, 0x40acccca},
+{'q', 0x41222224, 0x00000000},
+{0, 0x41822222, 0xc0accccc},
+{'q', 0x40c44448, 0xc0aeeef2},
+{0, 0x40c44448, 0xc186eef0},
+{'l', 0x00000000, 0xc2835556},
+{'@', 0x00000056, 0x000056ee},/*        V        x-advance: 86.929688 */
+{'M', 0x42aa4445, 0xc2c22223},
+{'l', 0xc20fbbbd, 0x42c22223},
+{'l', 0xc1366664, 0x00000000},
+{'l', 0xc20f7778, 0xc2c22223},
+{'l', 0x415eeeef, 0x00000000},
+{'l', 0x41dc4444, 0x42a00001},
+{'l', 0x41de6668, 0xc2a00001},
+{'l', 0x415eeef0, 0x00000000},
+{'[', 0x00290056, 0x00000155},/*kerning*/
+{'[', 0x005d0056, 0x00000122},/*kerning*/
+{'[', 0x007d0056, 0x00000144},/*kerning*/
+{'@', 0x00000057, 0x00007922},/*        W        x-advance: 121.132812 */
+{'M', 0x42ec6667, 0xc2c22223},
+{'l', 0xc1bbbbbc, 0x42c22223},
+{'l', 0xc13aaaa8, 0x00000000},
+{'l', 0xc1a00002, 0xc28d7778},
+{'l', 0xbfc44440, 0xc0ecccd0},
+{'l', 0xbfc44440, 0x40ecccd0},
+{'l', 0xc1a5ddde, 0x428d7778},
+{'l', 0xc13aaaac, 0x00000000},
+{'l', 0xc1bc4445, 0xc2c22223},
+{'l', 0x414ccccc, 0x00000000},
+{'l', 0x41755556, 0x4284ccce},
+{'l', 0x3ff77780, 0x414dddda},
+{'l', 0x402aaab0, 0xc1388888},
+{'l', 0x419a2222, 0xc2877778},
+{'l', 0x412bbbbc, 0x00000000},
+{'l', 0x4195dde0, 0x42877778},
+{'l', 0x402eeee0, 0x413cccce},
+{'l', 0x40044440, 0xc1533334},
+{'l', 0x41700000, 0xc284aaab},
+{'l', 0x414ddde0, 0x00000000},
+{'[', 0x00290057, 0x00000100},/*kerning*/
+{'[', 0x00540057, 0x000000ee},/*kerning*/
+{'[', 0x005d0057, 0x000000cc},/*kerning*/
+{'[', 0x007d0057, 0x000000ee},/*kerning*/
+{'@', 0x00000058, 0x00005599},/*        X        x-advance: 85.597656 */
+{'M', 0x419ccccd, 0xc2c22223},
+{'l', 0x41baaaab, 0x4214ccce},
+{'l', 0x41baaaac, 0xc214ccce},
+{'l', 0x41700000, 0x00000000},
+{'l', 0xc1f55556, 0x42404445},
+{'l', 0x41fb3336, 0x42440001},
+{'l', 0xc1722228, 0x00000000},
+{'l', 0xc1bf7778, 0xc217bbbc},
+{'l', 0xc1bf7777, 0x4217bbbc},
+{'l', 0xc1722224, 0x00000000},
+{'l', 0x41fb3335, 0xc2440001},
+{'l', 0xc1f55557, 0xc2404445},
+{'l', 0x41700000, 0x00000000},
+{'[', 0x00560058, 0x000000ee},/*kerning*/
+{'@', 0x00000059, 0x00005200},/*        Y        x-advance: 82.000000 */
+{'M', 0x417bbbbd, 0xc2c22223},
+{'l', 0x41c9999a, 0x4242eef0},
+{'l', 0x41ca2224, 0xc242eef0},
+{'l', 0x41699998, 0x00000000},
+{'l', 0xc205ddde, 0x42733334},
+{'l', 0x00000000, 0x42111112},
+{'l', 0xc14ddde0, 0x00000000},
+{'l', 0x00000000, 0xc2111112},
+{'l', 0xc205ddde, 0xc2733334},
+{'l', 0x416bbbbd, 0x00000000},
+{'[', 0x00290059, 0x00000155},/*kerning*/
+{'[', 0x00540059, 0x00000122},/*kerning*/
+{'[', 0x00560059, 0x00000133},/*kerning*/
+{'[', 0x00570059, 0x00000122},/*kerning*/
+{'[', 0x00580059, 0x000000dd},/*kerning*/
+{'[', 0x00590059, 0x00000133},/*kerning*/
+{'[', 0x005d0059, 0x00000133},/*kerning*/
+{'[', 0x007d0059, 0x00000144},/*kerning*/
+{'@', 0x0000005a, 0x000051cc},/*        Z        x-advance: 81.796875 */
+{'M', 0x40d55556, 0xc2ad1112},
+{'l', 0x00000000, 0xc1288888},
+{'l', 0x42873334, 0x00000000},
+{'l', 0x00000000, 0x41155558},
+{'l', 0xc2555556, 0x429a8889},
+{'l', 0x425dddde, 0x00000000},
+{'l', 0x00000000, 0x41277778},
+{'l', 0xc28d3333, 0x00000000},
+{'l', 0xb6400000, 0xc119999a},
+{'l', 0x4254ccce, 0xc299dddf},
+{'l', 0xc2515556, 0x00000000},
+{'[', 0x0041005a, 0x000000dd},/*kerning*/
+{'@', 0x0000005b, 0x00002433},/*        [        x-advance: 36.199219 */
+{'M', 0x420b7778, 0xc2dddddf},
+{'l', 0x00000000, 0x41222228},
+{'l', 0xc14bbbbc, 0x00000000},
+{'l', 0x00000000, 0x42deeeef},
+{'l', 0x414bbbbc, 0x36400000},
+{'l', 0x00000000, 0x41222223},
+{'l', 0xc1c8888a, 0x00000000},
+{'l', 0x35800000, 0xc303bbbc},
+{'l', 0x41c8888a, 0xb7000000},
+{'@', 0x0000005c, 0x00003811},/*       \         x-advance: 56.066406 */
+{'M', 0x422d1112, 0x41055556},
+{'l', 0xc2222223, 0xc2d2ccce},
+{'l', 0x413bbbbc, 0x00000000},
+{'l', 0x42222223, 0x42d2ccce},
+{'l', 0xc13bbbbc, 0xb6000000},
+{'@', 0x0000005d, 0x00002433},/*        ]        x-advance: 36.199219 */
+{'M', 0x3f2aaaab, 0xc2c9999a},
+{'l', 0x00000000, 0xc1222228},
+{'l', 0x41c9999b, 0x00000000},
+{'l', 0x00000000, 0x4303bbbc},
+{'l', 0xc1c9999b, 0x36c00000},
+{'l', 0x35300000, 0xc1222223},
+{'l', 0x414ccccd, 0x00000000},
+{'l', 0x00000000, 0xc2deeeef},
+{'l', 0xc14ccccd, 0x00000000},
+{'@', 0x0000005e, 0x00003911},/*        ^        x-advance: 57.066406 */
+{'M', 0x40888889, 0xc2426667},
+{'l', 0x419f7778, 0xc241dddf},
+{'l', 0x41088888, 0x00000000},
+{'l', 0x419eeef0, 0x4241dddf},
+{'l', 0xc1377778, 0x00000000},
+{'l', 0xc14aaaaa, 0xc200cccd},
+{'l', 0xc14bbbbd, 0x4200cccd},
+{'l', 0xc1377778, 0x00000000},
+{'@', 0x0000005f, 0x00003d99},/*        _        x-advance: 61.597656 */
+{'M', 0x4275999a, 0x00000000},
+{'l', 0x00000000, 0x41222223},
+{'l', 0xc2748889, 0x00000000},
+{'l', 0x34900000, 0xc1222223},
+{'l', 0x42748889, 0x00000000},
+{'@', 0x00000060, 0x00002a33},/*        `        x-advance: 42.199219 */
+{'M', 0x4195ddde, 0xc2ccccce},
+{'l', 0x414ddde0, 0x419cccd0},
+{'l', 0xc129999a, 0x00000000},
+{'l', 0xc189999a, 0xc19cccd0},
+{'l', 0x416eeeee, 0x00000000},
+{'@', 0x00000061, 0x00004a44},/*        a        x-advance: 74.265625 */
+{'M', 0x4257bbbc, 0x00000000},
+{'8', 0xc4f3ecf7, 0x32bb1de5},
+{'q', 0xc0a66668, 0x40266668},
+{0, 0xc13ddde0, 0x40266668},
+{'q', 0xc1311112, 0xb4000000},
+{0, 0xc18dddde, 0xc0c66667},
+{'q', 0xc0d55557, 0xc0c66668},
+{0, 0xc0d55557, 0xc1733334},
+{'q', 0x00000000, 0xc139999a},
+{0, 0x410cccce, 0xc18ccccd},
+{'9', 0xffd00046, 0xffd000bd},
+{'4', 0x00000061, 0xffd30000},
+{'8', 0xafe2cd00, 0xe2a6e2e2},
+{'8', 0x1ba600c9, 0x3fde1bde},
+{'l', 0xc1455557, 0x00000000},
+{'q', 0x00000000, 0xc0f77778},
+{0, 0x40f9999a, 0xc168888c},
+{'q', 0x40f9999c, 0xc0d99990},
+{0, 0x41a6eeef, 0xc0d99990},
+{'q', 0x413bbbbc, 0x00000000},
+{0, 0x419a2224, 0x40c00000},
+{'9', 0x002f003c, 0x0091003c},
+{'l', 0x00000000, 0x4201999a},
+{'9', 0x00500000, 0x007e0014},
+{'4', 0x00080000, 0x0000ff9a},
+{'m', 0xc1a3bbbc, 0xc1177778},
+{'8', 0xe65c0035, 0xc537e627},
+{'4', 0xff8a0000, 0x0000ffa5},
+{'q', 0xc1a66666, 0x3ecccd00},
+{0, 0xc1a66666, 0x41555558},
+{'8', 0x451b2900, 0x1c521c1b},
+{'@', 0x00000062, 0x00004caa},/*        b        x-advance: 76.664062 */
+{'M', 0x428ceeef, 0xc20d1112},
+{'q', 0x00000000, 0x417cccd0},
+{0, 0xc0eaaaa8, 0x41d1999b},
+{'q', 0xc0eaaaa8, 0x41266667},
+{0, 0xc1a5ddde, 0x41266667},
+{'9', 0x0000ff93, 0xffb3ff58},
+{'l', 0xbf2aaaa0, 0x41055556},
+{'l', 0xc1355556, 0x00000000},
+{'4', 0xfccd0000, 0x00000063},
+{'l', 0x00000000, 0x42184446},
+{'q', 0x40eaaaac, 0xc1122220},
+{0, 0x41a44446, 0xc1122220},
+{'q', 0x41599998, 0x00000000},
+{0, 0x41a6eeee, 0x41222220},
+{'9', 0x0051003a, 0x00d5003a},
+{'6', 0x000b0000, 0xff22ff06},
+{'8', 0x1aa900cb, 0x3fcc19df},
+{'l', 0x00000000, 0x41fb3334},
+{'8', 0x40352613, 0x1a571a22},
 {'q', 0x41200000, 0x00000000},
-{0, 0x41780dbc, 0xc0ec3dda},
-{'9', 0xffc5002c, 0xff5b002c},
-{'m', 0x41459578, 0x41e90528},
-{'q', 0x00000000, 0x41998e9a},
-{0, 0xc1086038, 0x41e4b98e},
-{'q', 0xc1086034, 0x41154300},
-{0, 0xc1d0dbea, 0x41154300},
-{'8', 0xf99e00cc, 0xe8a7f8d2},
-{'l', 0x00000000, 0xc14036fb},
-{'8', 0x2255172b, 0x0b560b2a},
-{'q', 0x41425cc4, 0x00000000},
-{0, 0x419180dc, 0xc0c9e112},
-{'9', 0xffcd0030, 0xff670030},
-{'l', 0x00000000, 0xc0c36fb0},
-{'q', 0xc074d510, 0x40d49e12},
-{0, 0xc11cc750, 0x411eed1a},
-{'q', 0xc0bf2410, 0x40527844},
-{0, 0xc164b98c, 0x40527844},
-{'q', 0xc15d3544, 0x00000000},
-{0, 0xc1b2414a, 0xc1289732},
-{'q', 0xc1074d50, 0xc1289732},
-{0, 0xc1074d50, 0xc1df5b0f},
-{'q', 0xb5000000, 0xc18b98ea},
-{0, 0x41074d50, 0xc1dfe484},
-{'q', 0x41074d50, 0xc1289730},
-{0, 0x41b2414a, 0xc1289730},
-{'q', 0x41052784, 0x00000000},
-{0, 0x4164b98c, 0x40527840},
-{'9', 0x001a002f, 0x004f004e},
-{'l', 0x00000000, 0xc1368ce4},
-{'l', 0x41459578, 0x00000000},
-{'l', 0x00000000, 0x4283ad88},
-{'@', 0x00000068, 0x0000571d},/*        h        x-advance: 87.113281 */
-{'M', 0x4296df5b, 0xc23579fc},
-{'4', 0x016a0000, 0x0000ff9e},
-{'l', 0x00000000, 0xc233dda3},
-{'q', 0x00000000, 0xc12abcfc},
-{0, 0xc0852780, 0xc17f9208},
-{'q', 0xc0852788, 0xc0a9aa18},
-{0, 0xc147bb48, 0xc0a9aa18},
-{'q', 0xc1200000, 0x00000000},
-{0, 0xc17c5956, 0x40cc06d8},
-{'9', 0x0033ffd2, 0x008bffd2},
-{'l', 0x00000000, 0x4229eed1},
-{'l', 0xc146a860, 0x00000000},
-{'4', 0xfcbd0000, 0x00000063},
-{'l', 0x00000000, 0x4223c225},
-{'8', 0xaf53ca23, 0xe66fe630},
-{'q', 0x414f3f90, 0x00000000},
-{0, 0x419cc74e, 0x4100dbf0},
-{'q', 0x40d49e10, 0x40ff9208},
-{0, 0x40d49e10, 0x41bc74d4},
-{'@', 0x00000069, 0x00002630},/*        i        x-advance: 38.187500 */
-{'M', 0x414f3f92, 0xc29655e8},
-{'l', 0x4145957a, 0x00000000},
-{'4', 0x02590000, 0x0000ff9e},
-{'6', 0xfda70000, 0xff160000},
-{'l', 0x4145957a, 0x00000000},
-{'l', 0x00000000, 0x417a3388},
-{'l', 0xc145957a, 0x00000000},
-{'l', 0x00000000, 0xc17a3388},
-{'@', 0x0000006a, 0x00002630},/*        j        x-advance: 38.187500 */
-{'M', 0x414f3f92, 0xc29655e8},
-{'4', 0x00000062, 0x02640000},
-{'q', 0x00000000, 0x4165cc71},
-{0, 0xc0b01b80, 0x41a67163},
-{'9', 0x0033ffd5, 0x0033ff74},
-{'4', 0x0000ffdb, 0xffad0000},
-{'l', 0x40527845, 0x00000000},
-{'8', 0xe74c0038, 0x9414e614},
-{'6', 0xfd9c0000, 0xff160000},
-{'l', 0x4145957a, 0x00000000},
-{'l', 0x00000000, 0x417a3388},
-{'l', 0xc145957a, 0x00000000},
-{'l', 0x00000000, 0xc17a3388},
-{'@', 0x0000006b, 0x00004f98},/*        k        x-advance: 79.593750 */
-{'M', 0x4147bb46, 0xc2d0dbeb},
-{'l', 0x4146a860, 0x00000000},
-{'l', 0x00000000, 0x4276b61e},
-{'l', 0x421361ee, 0xc201aa18},
-{'l', 0x417c5958, 0x00000000},
-{'l', 0xc21f768d, 0x420cabd0},
-{'l', 0x42262cab, 0x42200000},
-{'l', 0xc180dbea, 0x00000000},
-{'l', 0xc218c06e, 0xc212d87b},
-{'l', 0x36000000, 0x4212d87b},
-{'l', 0xc146a860, 0x00000000},
-{'l', 0x00000000, 0xc2d0dbeb},
-{'@', 0x0000006c, 0x00002630},/*        l        x-advance: 38.187500 */
-{'M', 0x414f3f92, 0xc2d0dbeb},
-{'l', 0x4145957a, 0x00000000},
-{'l', 0x00000000, 0x42d0dbeb},
-{'l', 0xc145957a, 0x00000000},
-{'l', 0x00000000, 0xc2d0dbeb},
-{'@', 0x0000006d, 0x000085e4},/*        m        x-advance: 133.890625 */
-{'M', 0x428ef3f9, 0xc272f3f9},
-{'q', 0x40943020, 0xc1052784},
-{0, 0x41312e60, 0xc1448294},
-{'q', 0x40ce2cb0, 0xc07d6c40},
-{0, 0x4172af40, 0xc07d6c40},
-{'q', 0x413beb60, 0x00000000},
-{0, 0x4190f768, 0x410414a0},
-{'9', 0x00410033, 0x00ba0033},
-{'4', 0x016a0000, 0x0000ff9d},
-{'l', 0x00000000, 0xc233dda3},
-{'q', 0x00000000, 0xc12ce2cc},
-{0, 0xc074d500, 0xc1805278},
-{'q', 0xc074d500, 0xc0a78448},
-{0, 0xc13ad878, 0xc0a78448},
-{'q', 0xc1198ea0, 0x00000000},
-{0, 0xc172af40, 0x40cc06d8},
-{'9', 0x0033ffd4, 0x008bffd4},
-{'4', 0x01530000, 0x0000ff9d},
-{'l', 0x00000000, 0xc233dda3},
-{'q', 0x00000000, 0xc12df5b0},
-{0, 0xc074d510, 0xc1805278},
-{'q', 0xc074d500, 0xc0a78448},
-{0, 0xc13cfe48, 0xc0a78448},
-{'q', 0xc11768cc, 0x00000000},
-{0, 0xc1708972, 0x40ce2ca8},
-{'9', 0x0033ffd4, 0x008affd4},
-{'l', 0x00000000, 0x4229eed1},
-{'l', 0xc146a860, 0x00000000},
-{'4', 0xfda70000, 0x00000063},
-{'l', 0x00000000, 0x413ad87c},
-{'q', 0x40874d50, 0xc0dd3538},
-{0, 0x412225ce, 0xc12338b4},
-{'q', 0x40bcfe48, 0xc0527840},
-{0, 0x41606df4, 0xc0527840},
-{'8', 0x216f0041, 0x6044212e},
-{'@', 0x0000006e, 0x0000571d},/*        n        x-advance: 87.113281 */
-{'M', 0x4296df5b, 0xc23579fc},
-{'4', 0x016a0000, 0x0000ff9e},
-{'l', 0x00000000, 0xc233dda3},
-{'q', 0x00000000, 0xc12abcfc},
-{0, 0xc0852780, 0xc17f9208},
-{'q', 0xc0852788, 0xc0a9aa18},
-{0, 0xc147bb48, 0xc0a9aa18},
-{'q', 0xc1200000, 0x00000000},
-{0, 0xc17c5956, 0x40cc06d8},
-{'9', 0x0033ffd2, 0x008bffd2},
-{'l', 0x00000000, 0x4229eed1},
-{'l', 0xc146a860, 0x00000000},
-{'4', 0xfda70000, 0x00000063},
-{'l', 0x00000000, 0x413ad87c},
-{'8', 0xaf53ca23, 0xe66fe630},
-{'q', 0x414f3f90, 0x00000000},
-{0, 0x419cc74e, 0x4100dbf0},
-{'q', 0x40d49e10, 0x40ff9208},
-{0, 0x40d49e10, 0x41bc74d4},
-{'@', 0x0000006f, 0x00005418},/*        o        x-advance: 84.093750 */
-{'M', 0x42285278, 0xc2850527},
-{'q', 0xc11eed18, 0x00000000},
-{0, 0xc17b4670, 0x40f920a0},
-{'q', 0xc0b8b2b0, 0x40f6fad8},
-{0, 0xc0b8b2b0, 0x41a9aa18},
-{'q', 0x00000000, 0x4157d6c2},
-{0, 0x40b68ce0, 0x41aa338b},
-{'q', 0x40b8b2b0, 0x40f6fad6},
-{0, 0x417c5958, 0x40f6fad6},
-{'q', 0x411dda34, 0x00000000},
-{0, 0x417a338c, 0xc0f920a6},
-{'q', 0x40b8b2b0, 0xc0f920a4},
-{0, 0x40b8b2b0, 0xc1a9aa17},
-{'q', 0x00000000, 0xc155b0f8},
-{0, 0xc0b8b2b0, 0xc1a920a6},
-{'9', 0xffc2ffd2, 0xffc2ff83},
-{'m', 0x00000000, 0xc1278450},
-{'q', 0x4180dbec, 0x00000000},
-{0, 0x41ca6a84, 0x41278450},
-{'q', 0x41131d38, 0x41278448},
-{0, 0x41131d38, 0x41e7f240},
-{'q', 0x00000000, 0x4193a6a8},
-{0, 0xc1131d38, 0x41e7f240},
-{'q', 0xc1131d30, 0x4127844d},
-{0, 0xc1ca6a84, 0x4127844d},
-{'q', 0xc181655e, 0xb4c00000},
-{0, 0xc1caf3f9, 0xc127844c},
-{'q', 0xc1120a4e, 0xc1289731},
-{0, 0xc1120a4e, 0xc1e7f240},
-{'q', 0xb5000000, 0xc194301c},
-{0, 0x41120a4e, 0xc1e7f240},
-{'q', 0x41131d36, 0xc1278450},
-{0, 0x41caf3f9, 0xc1278450},
-{'[', 0x002d006f, 0x0000028c},
-{'@', 0x00000070, 0x0000573f},/*        p        x-advance: 87.246094 */
-{'M', 0x41c731d3, 0xc1346716},
-{'l', 0x00000000, 0x421f768c},
-{'l', 0xc146a860, 0x36000000},
-{'4', 0xfcc20000, 0x00000063},
-{'l', 0x00000000, 0x41368ce4},
-{'q', 0x407920a8, 0xc0d6c3d8},
-{0, 0x411cc74e, 0xc11eed1c},
-{'q', 0x40bf2410, 0xc0527840},
-{0, 0x4163a6a8, 0xc0527840},
-{'q', 0x415b0f74, 0x00000000},
-{0, 0x41b1b7d6, 0x412df5b0},
-{'q', 0x41097320, 0x412df5b4},
-{0, 0x41097320, 0x41e4b990},
-{'q', 0x00000000, 0x418dbeb6},
-{0, 0xc1097320, 0x41e4b98e},
-{'q', 0xc1086038, 0x412df5b1},
-{0, 0xc1b1b7d6, 0x412df5b1},
-{'q', 0xc10414a0, 0xb4c00000},
-{0, 0xc163a6a8, 0xc04e2cad},
-{'9', 0xffe6ffd1, 0xffb0ffb2},
-{'m', 0x42280dbe, 0xc1d1eed1},
-{'q', 0x00000000, 0xc159fc90},
-{0, 0xc0b46718, 0xc1aabcfe},
-{'q', 0xc0b24148, 0xc0f920a8},
-{0, 0xc175e7f0, 0xc0f920a8},
-{'q', 0xc11cc750, 0x00000000},
-{0, 0xc176fada, 0x40f920a8},
-{'q', 0xc0b24148, 0x40f6fad8},
-{0, 0xc0b24148, 0x41aabcfe},
-{'q', 0x00000000, 0x4159fc90},
-{0, 0x40b24148, 0x41ab4671},
-{'q', 0x40b46714, 0x40f6fad8},
-{0, 0x4176fada, 0x40f6fad8},
-{'q', 0x411cc74c, 0x00000000},
-{0, 0x4175e7f0, 0xc0f6fad8},
-{'q', 0x40b46718, 0xc0f920a4},
-{0, 0x40b46718, 0xc1ab4671},
-{'@', 0x00000071, 0x0000573f},/*        q        x-advance: 87.246094 */
-{'M', 0x41a2af3f, 0xc216112e},
-{'q', 0x00000000, 0x4159fc90},
-{0, 0x40b2414c, 0x41ab4671},
-{'q', 0x40b46714, 0x40f6fad8},
-{0, 0x4176fad8, 0x40f6fad8},
-{'q', 0x411cc74c, 0x00000000},
-{0, 0x4176fad8, 0xc0f6fad8},
-{'q', 0x40b46718, 0xc0f920a4},
-{0, 0x40b46718, 0xc1ab4671},
-{'q', 0x00000000, 0xc159fc90},
-{0, 0xc0b46718, 0xc1aabcfe},
-{'q', 0xc0b46718, 0xc0f920a8},
-{0, 0xc176fad8, 0xc0f920a8},
-{'q', 0xc11cc74e, 0x00000000},
-{0, 0xc176fad8, 0x40f920a8},
-{'9', 0x003dffd4, 0x00aaffd4},
-{'m', 0x42285278, 0x41d1eed1},
-{'q', 0xc07920b0, 0x40d6c3dd},
-{0, 0xc11dda34, 0x41200000},
-{'q', 0xc0bcfe48, 0x404e2caa},
-{0, 0xc163a6a8, 0x404e2caa},
-{'q', 0xc159fc90, 0x34000000},
-{0, 0xc1b1b7d7, 0xc12df5b0},
-{'q', 0xc1086036, 0xc12df5b0},
-{0, 0xc1086036, 0xc1e4b98e},
-{'q', 0xb5000000, 0xc18dbeb6},
-{0, 0x41086036, 0xc1e4b990},
-{'q', 0x4109731e, 0xc12df5b0},
-{0, 0x41b1b7d7, 0xc12df5b0},
-{'q', 0x41052784, 0x00000000},
-{0, 0x4163a6a8, 0x40527840},
-{'9', 0x0019002f, 0x004f004e},
-{'l', 0x00000000, 0xc1368ce4},
-{'l', 0x41459578, 0x00000000},
-{'l', 0x00000000, 0x42cf844c},
-{'l', 0xc1459578, 0xb6800000},
-{'l', 0x00000000, 0xc21f768c},
-{'@', 0x00000072, 0x00003882},/*        r        x-advance: 56.507812 */
-{'M', 0x42620a4f, 0xc27e7f24},
-{'8', 0xf3dcf7f0, 0xfcd6fced},
-{'q', 0xc127844c, 0x00000000},
-{0, 0xc180dbeb, 0x40db0f78},
-{'9', 0x0036ffd4, 0x009cffd4},
-{'l', 0x00000000, 0x421e63a6},
-{'l', 0xc146a860, 0x00000000},
-{'4', 0xfda70000, 0x00000063},
-{'l', 0x00000000, 0x413ad87c},
-{'q', 0x407920a8, 0xc0db0f78},
-{0, 0x412225ce, 0xc12225cc},
-{'q', 0x40c7bb40, 0xc056c3e0},
-{0, 0x4172af3c, 0xc056c3e0},
-{'8', 0x0116000a, 0x031b010c},
-{'l', 0x3d897400, 0x414af3f8},
-{'@', 0x00000073, 0x0000479c},/*        s        x-advance: 71.609375 */
-{'M', 0x42737d6c, 0xc291e7f2},
-{'l', 0x00000000, 0x413ad87c},
-{'8', 0xe0aaebd7, 0xf6a3f6d3},
-{'8', 0x169200b7, 0x43dc16dc},
-{'8', 0x361a2200, 0x2569131a},
-{'l', 0x40874d50, 0x3f708980},
-{'q', 0x41527844, 0x40346720},
-{0, 0x41954302, 0x40ff9208},
-{'q', 0x40b24150, 0x40a338b4},
-{0, 0x40b24150, 0x4164b990},
-{'q', 0x00000000, 0x4127844b},
-{0, 0xc1052788, 0x41849e11},
-{'q', 0xc104149c, 0x40c36fad},
-{0, 0xc1b6036e, 0x40c36fad},
-{'8', 0xf79c00d0, 0xe492f7cc},
-{'l', 0x00000000, 0xc14c06df},
-{'8', 0x2a6b1c36, 0x0d690d35},
-{'8', 0xe96b0045, 0xbd25e825},
-{'q', 0x00000000, 0xc0a112e8},
-{0, 0xc05b0f70, 0xc0f6fad8},
-{'9', 0xffebffe6, 0xffd7ff8a},
-{'l', 0xc0897320, 0xbf80dbe0},
-{'q', 0xc1379fc8, 0xc01aa180},
-{0, 0xc1849e11, 0xc0ec3de0},
-{'q', 0xc0a338b2, 0xc0a112e0},
-{0, 0xc0a338b2, 0xc15c225c},
-{'q', 0x00000000, 0xc129aa18},
-{0, 0x40f08972, 0xc18301b8},
-{'q', 0x40f08974, 0xc0b8b2b0},
-{0, 0x41aabcff, 0xc0b8b2b0},
-{'8', 0x08670036, 0x18590830},
-{'@', 0x00000074, 0x000035e4},/*        t        x-advance: 53.890625 */
-{'M', 0x41c9579f, 0xc2c10527},
-{'l', 0x00000000, 0x41aabcfc},
-{'l', 0x41cb7d6d, 0x00000000},
-{'4', 0x004c0000, 0x0000ff35},
-{'l', 0x00000000, 0x422338b2},
-{'8', 0x5e134900, 0x14521414},
-{'4', 0x00000065, 0x00520000},
-{'l', 0xc14af3f8, 0x00000000},
-{'q', 0xc164b990, 0x00000000},
-{0, 0xc19dda34, 0xc0a9aa18},
-{'9', 0xffd6ffd5, 0xff65ffd5},
-{'l', 0x00000000, 0xc22338b2},
-{'l', 0xc110f768, 0x00000000},
-{'l', 0xb5000000, 0xc1198ea0},
-{'l', 0x4110f768, 0x00000000},
-{'l', 0x35800000, 0xc1aabcfc},
-{'l', 0x4146a85f, 0x00000000},
-{'@', 0x00000075, 0x0000571d},/*        u        x-advance: 87.113281 */
-{'M', 0x413ad87b, 0xc1ed50c0},
-{'4', 0xfe940000, 0x00000062},
-{'l', 0x00000000, 0x4234225d},
-{'q', 0x00000000, 0x412abcfe},
-{0, 0x40852784, 0x41805278},
-{'q', 0x40852780, 0x40a9aa18},
-{0, 0x4147bb44, 0x40a9aa18},
+{0, 0x41655554, 0xc0f55556},
+{'9', 0xffc30023, 0xff6d0023},
+{'l', 0x00000000, 0xbfb33320},
+{'q', 0x00000000, 0xc12bbbbc},
+{0, 0xc0866668, 0xc1944446},
+{'q', 0xc0844440, 0xc0fbbbb8},
+{0, 0xc16aaaac, 0xc0fbbbb8},
+{'@', 0x00000063, 0x00004777},/*        c        x-advance: 71.464844 */
+{'M', 0x42191112, 0xc10ccccd},
+{'8', 0xe15c0034, 0xb02be128},
+{'l', 0x413bbbb8, 0x00000000},
+{'q', 0xbeeeee00, 0x411aaaab},
+{0, 0xc10ddddc, 0x41877778},
+{'q', 0xc1066664, 0x40e66667},
+{0, 0xc19eeeee, 0x40e66667},
+{'q', 0xc1822223, 0xb4000000},
+{0, 0xc1c1999b, 0xc12bbbbc},
+{'9', 0xffabffc2, 0xff36ffc2},
+{'l', 0x00000000, 0xc0333330},
+{'q', 0x00000000, 0xc168888c},
+{0, 0x40fbbbbd, 0xc1ca2224},
+{'q', 0x40fddde0, 0xc12bbbb8},
+{0, 0x41c1999b, 0xc12bbbb8},
+{'q', 0x414aaaa8, 0x00000000},
+{0, 0x41a3bbbc, 0x40f11110},
+{'9', 0x003b003e, 0x00940042},
+{'l', 0xc13bbbb8, 0x00000000},
+{'8', 0xa6d8cbfd, 0xdba1dbdc},
+{'8', 0x1ea100c4, 0x4ed01ede},
+{'9', 0x002ffff3, 0x0061fff3},
+{'l', 0x00000000, 0x40333330},
+{'8', 0x620d3200, 0x4e302f0d},
+{'q', 0x408aaaac, 0x40733334},
+{0, 0x41400002, 0x40733334},
+{'@', 0x00000064, 0x00004d00},/*        d        x-advance: 77.000000 */
+{'M', 0x425fbbbc, 0x00000000},
+{'l', 0xbf199980, 0xc0f77778},
+{'q', 0xc0ecccd0, 0x41111111},
+{0, 0xc1a4ccce, 0x41111111},
+{'q', 0xc14aaaaa, 0x34c00000},
+{0, 0xc1a3bbbc, 0xc1244444},
+{'9', 0xffaeffc2, 0xff32ffc1},
+{'l', 0x00000000, 0xbff77780},
+{'q', 0x00000000, 0xc1844446},
+{0, 0x40f9999b, 0xc1d55556},
+{'q', 0x40fbbbbe, 0xc1222220},
+{0, 0x41a5ddde, 0xc1222220},
+{'9', 0x00000065, 0x004400a0},
+{'l', 0x00000000, 0xc215dde0},
+{'4', 0x00000063, 0x03330000},
+{'6', 0x0000ffa6, 0xfee6fed7},
+{'q', 0x00000000, 0x412bbbbe},
+{0, 0x40911114, 0x4193bbbd},
+{'q', 0x40911110, 0x40f55556},
+{0, 0x4168888a, 0x40f55556},
+{'9', 0x0000005b, 0xffad0088},
+{'l', 0x00000000, 0xc204ccce},
+{'q', 0xc0b11110, 0xc1244444},
+{0, 0xc1877778, 0xc1244444},
+{'q', 0xc1211110, 0x00000000},
+{0, 0xc16aaaaa, 0x40fbbbb8},
+{'q', 0xc0911114, 0x40f999a0},
+{0, 0xc0911114, 0x41944446},
+{'l', 0x00000000, 0x3fb33320},
+{'@', 0x00000065, 0x00004866},/*        e        x-advance: 72.398438 */
+{'M', 0x4284eeef, 0xc149999a},
+{'q', 0xc0622210, 0x40aaaaab},
+{0, 0xc11ffffc, 0x411aaaab},
+{'q', 0xc0ceeef0, 0x40888889},
+{0, 0xc1891112, 0x40888889},
+{'q', 0xc1711112, 0xb4000000},
+{0, 0xc1c11112, 0xc11cccce},
+{'9', 0xffb2ffb8, 0xff38ffb8},
+{'l', 0xb5000000, 0xc0333330},
+{'q', 0x00000000, 0xc13ccccc},
+{0, 0x408eeeef, 0xc1a08888},
+{'q', 0x40911112, 0xc1055558},
+{0, 0x413bbbbd, 0xc14aaab0},
+{'q', 0x40e66668, 0xc08cccc0},
+{0, 0x41755554, 0xc08cccc0},
+{'q', 0x4177777c, 0x00000000},
+{0, 0x41b44446, 0x41222220},
+{'9', 0x00500039, 0x00c90039},
+{'4', 0x002c0000, 0x0000fe7a},
+{'q', 0x3e8888c0, 0x411eeef0},
+{0, 0x40bbbbc0, 0x41877778},
+{'q', 0x40b55558, 0x40dddde0},
+{0, 0x4178888c, 0x40dddde0},
+{'8', 0xeb580034, 0xc73feb24},
+{'6', 0x002f003b, 0xfe6bff1b},
+{'q', 0xc0eaaaa8, 0x00000000},
+{0, 0xc1466666, 0x40aaaaa8},
+{'9', 0x002affd8, 0x007affce},
+{'4', 0x00000120, 0xfff90000},
+{'8', 0x95dfc7fd, 0xce97cee3},
+{'@', 0x00000066, 0x00002f77},/*        f        x-advance: 47.464844 */
+{'M', 0x422c8889, 0xc27aaaac},
+{'l', 0xc1755556, 0x00000000},
+{'l', 0x00000000, 0x427aaaac},
+{'l', 0xc1455556, 0x00000000},
+{'l', 0x00000000, 0xc27aaaac},
+{'0', 0xb50000a5, 0xc000005b},
+{'q', 0x3e088880, 0xc1377778},
+{0, 0x40ccccd0, 0xc18c4444},
+{'q', 0x40caaaa8, 0xc0c22220},
+{0, 0x418a2222, 0xc0c22220},
+{'9', 0x00000020, 0x00080044},
+{'l', 0xbf2aaa80, 0x41211110},
+{'8', 0xfccbfcea, 0x699c009e},
+{'l', 0x00000000, 0x41000000},
+{'l', 0x41755556, 0x00000000},
+{'l', 0x00000000, 0x41177778},
+{'[', 0x00220066, 0x00000111},/*kerning*/
+{'[', 0x00270066, 0x00000111},/*kerning*/
+{'[', 0x00290066, 0x00000155},/*kerning*/
+{'[', 0x005d0066, 0x00000133},/*kerning*/
+{'[', 0x007d0066, 0x00000144},/*kerning*/
+{'@', 0x00000067, 0x00004caa},/*        g        x-advance: 76.664062 */
+{'M', 0x42133334, 0x41e3bbbd},
+{'8', 0xeb9300d4, 0xb298ebbf},
+{'l', 0x40ceeef0, 0xc0eaaaac},
+{'q', 0x41000000, 0x411bbbbc},
+{0, 0x419aaaab, 0x411bbbbc},
+{'q', 0x410bbbbc, 0x00000000},
+{0, 0x415eeef0, 0xc09bbbbc},
+{'9', 0xffd90029, 0xff8d0029},
+{'l', 0x00000000, 0xc0caaaab},
+{'q', 0xc0eaaab0, 0x4109999a},
+{0, 0xc1a1999a, 0x4109999a},
+{'q', 0xc1500002, 0xb4000000},
+{0, 0xc1a55556, 0xc1266668},
+{'9', 0xffadffc3, 0xff2fffc3},
+{'l', 0x00000000, 0xbfb33320},
+{'q', 0x00000000, 0xc1844446},
+{0, 0x40f33334, 0xc1d55556},
+{'q', 0x40f55554, 0xc1222220},
+{0, 0x41a6eeef, 0xc1222220},
+{'9', 0x0000006a, 0x004a00a4},
+{'4', 0xffc00004, 0x00000059},
+{'l', 0x00000000, 0x428d3334},
+{'q', 0x00000000, 0x41655556},
+{0, 0xc1088888, 0x41b1999a},
+{'9', 0x003effbc, 0x003eff50},
+{'m', 0xc1900001, 0xc27eeef0},
+{'q', 0x00000000, 0x412bbbbe},
+{0, 0x408eeef0, 0x4193bbbd},
+{'q', 0x40911110, 0x40f55556},
+{0, 0x4168888a, 0x40f55556},
+{'9', 0x0000005d, 0xffab0089},
+{'l', 0x00000000, 0xc2037778},
+{'8', 0xc5cdddee, 0xe8ace8df},
+{'q', 0xc1211110, 0x00000000},
+{0, 0xc169999a, 0x40fbbbb8},
+{'q', 0xc0911110, 0x40f999a0},
+{0, 0xc0911110, 0x41944446},
+{'l', 0x00000000, 0x3fb33320},
+{'@', 0x00000068, 0x00004b33},/*        h        x-advance: 75.199219 */
+{'M', 0x421d5556, 0xc27c4445},
+{'8', 0x19ad00d1, 0x42c719dc},
+{'l', 0x00000000, 0x424e2223},
+{'l', 0xc1455555, 0x00000000},
+{'4', 0xfccd0000, 0x00000062},
+{'l', 0x00000000, 0x421b7779},
+{'q', 0x41033334, 0xc11eeeec},
+{0, 0x41aa2224, 0xc11eeeec},
+{'q', 0x41299998, 0x00000000},
+{0, 0x41866666, 0x40bdddd0},
+{'9', 0x002f0032, 0x009f0032},
+{'4', 0x017c0000, 0x0000ff9d},
+{'l', 0x00000000, 0xc23d999a},
+{'8', 0xa0e3bd00, 0xe4abe4e3},
+{'@', 0x00000069, 0x00002133},/*        i        x-advance: 33.199219 */
+{'M', 0x41177778, 0xc2b68889},
+{'8', 0xd80ee800, 0xf02bf00e},
+{'8', 0x102b001c, 0x280f100f},
+{'8', 0x27f11600, 0x10d510f2},
+{'8', 0xf0d500e4, 0xd9f2f0f2},
+{'m', 0x41555556, 0x41991110},
+{'l', 0x00000000, 0x42904445},
+{'l', 0xc1466667, 0x00000000},
+{'l', 0x00000000, 0xc2904445},
+{'l', 0x41466667, 0x00000000},
+{'@', 0x0000006a, 0x000020aa},/*        j        x-advance: 32.664062 */
+{'M', 0x41077778, 0xc2b68889},
+{'8', 0xd80ee800, 0xf02bf00e},
+{'8', 0x102b001c, 0x280e100e},
+{'8', 0x27f21600, 0x10d510f2},
+{'8', 0xf0d500e4, 0xd9f2f0f2},
+{'m', 0x3fa22220, 0x41991110},
+{'4', 0x00000063, 0x02850000},
+{'q', 0x00000000, 0x41a44446},
+{0, 0xc196eef0, 0x41a44446},
+{'9', 0x0000ffdf, 0xfff7ffc3},
+{'l', 0x3d888880, 0xc11eeef0},
+{'8', 0x042d0413, 0xb6430041},
+{'l', 0x00000000, 0xc2a31112},
+{'@', 0x0000006b, 0x00004533},/*        k        x-advance: 69.199219 */
+{'M', 0x425a6667, 0x00000000},
+{'l', 0xc1c80000, 0xc205ddde},
+{'l', 0xc0f9999c, 0x41011110},
+{'l', 0x00000000, 0x41cb3334},
+{'l', 0xc1466667, 0x00000000},
+{'l', 0x00000000, 0xc2ccccce},
+{'l', 0x41466667, 0x00000000},
+{'l', 0x00000000, 0x42777779},
+{'l', 0x40d33334, 0xc0fbbbb8},
+{'l', 0x41b33334, 0xc1bddde0},
+{'l', 0x41711110, 0x00000000},
+{'l', 0xc1e11112, 0x41f0888a},
+{'l', 0x41fb3336, 0x42284445},
+{'l', 0xc168888c, 0x00000000},
+{'@', 0x0000006c, 0x00002133},/*        l        x-advance: 33.199219 */
+{'M', 0x41b66667, 0xc2ccccce},
+{'l', 0x00000000, 0x42ccccce},
+{'l', 0xc1466667, 0x00000000},
+{'l', 0x00000000, 0xc2ccccce},
+{'l', 0x41466667, 0x00000000},
+{'@', 0x0000006d, 0x000077bb},/*        m        x-advance: 119.730469 */
+{'M', 0x42191112, 0xc27c4445},
+{'9', 0x0000ff9f, 0x0051ff7c},
+{'l', 0x00000000, 0x42537778},
+{'l', 0xc1466667, 0x00000000},
+{'4', 0xfdbf0000, 0x0000005d},
+{'l', 0x3eaaaa80, 0x40fbbbc0},
+{'q', 0x40f9999c, 0xc1133330},
+{0, 0x41aaaaab, 0xc1133330},
+{'8', 0x16620037, 0x4642152b},
+{'8', 0xbd4ad71c, 0xe76ce72e},
+{'q', 0x41399998, 0x00000000},
+{0, 0x418eeef0, 0x40c66660},
+{'9', 0x00310032, 0x009e0032},
+{'4', 0x017b0000, 0x0000ff9d},
+{'l', 0x00000000, 0xc23e2223},
+{'8', 0x9edfb800, 0xe6a7e6df},
+{'8', 0x23a300c5, 0x55d923de},
+{'4', 0x017e0000, 0x0000ff9e},
+{'l', 0x00000000, 0xc23ddddf},
+{'8', 0xa0dfbd00, 0xe4a7e4df},
+{'@', 0x0000006e, 0x00004b66},/*        n        x-advance: 75.398438 */
+{'M', 0x421d5556, 0xc27c4445},
+{'8', 0x19ad00d1, 0x42c719dc},
+{'l', 0x00000000, 0x424e2223},
+{'l', 0xc1455555, 0x00000000},
+{'4', 0xfdbf0000, 0x0000005d},
+{'l', 0x3eccccc0, 0x41100004},
+{'q', 0x41033334, 0xc1255554},
+{0, 0x41ac4446, 0xc1255554},
+{'q', 0x41299998, 0x00000000},
+{0, 0x41866666, 0x40bdddd0},
+{'9', 0x002f0032, 0x009f0032},
+{'4', 0x017c0000, 0x0000ff9d},
+{'l', 0x00000000, 0xc23d999a},
+{'8', 0xa0e3bd00, 0xe4abe4e3},
+{'@', 0x0000006f, 0x00004ddd},/*        o        x-advance: 77.863281 */
+{'M', 0x40c44445, 0xc2133334},
+{'q', 0x00000000, 0xc17aaaac},
+{0, 0x410cccce, 0xc1d11112},
+{'q', 0x410cccce, 0xc1288884},
+{0, 0x41bf7778, 0xc1288884},
+{'q', 0x41722224, 0x00000000},
+{0, 0x41bf7778, 0x41255554},
+{'9', 0x00520046, 0x00cd0048},
+{'l', 0x00000000, 0x400cccc0},
+{'q', 0x00000000, 0x417aaaae},
+{0, 0xc10ddddc, 0x41d11112},
+{'q', 0xc10cccd0, 0x41277779},
+{0, 0xc1bf7778, 0x41277779},
+{'q', 0xc1733336, 0x34c00000},
+{0, 0xc1c0888a, 0xc1277778},
+{'9', 0xffadffba, 0xff2fffba},
+{'6', 0xfff40000, 0x000c0062},
+{'q', 0x00000000, 0x412bbbbe},
+{0, 0x40a22224, 0x4194ccce},
+{'q', 0x40a44444, 0x40fbbbbe},
+{0, 0x4177777a, 0x40fbbbbe},
+{'q', 0x41211110, 0x00000000},
+{0, 0x41733334, 0xc0f7777a},
+{'9', 0xffc20029, 0xff6c0029},
+{'l', 0x00000000, 0xbfdddde0},
+{'q', 0x00000000, 0xc1299998},
+{0, 0xc0a44440, 0xc1944444},
+{'q', 0xc0a44448, 0xc1000000},
+{0, 0xc1766668, 0xc1000000},
+{'q', 0xc1233334, 0x00000000},
+{0, 0xc1755556, 0x41000000},
+{'q', 0xc0a22224, 0x40fddde0},
+{0, 0xc0a22224, 0x41944444},
+{'l', 0x00000000, 0x3fc44440},
+{'@', 0x00000070, 0x00004caa},/*        p        x-advance: 76.664062 */
+{'M', 0x42295556, 0x3faaaaab},
+{'9', 0x0000ff98, 0xffbeff5c},
+{'l', 0x00000000, 0x420aeef0},
+{'l', 0xc1466666, 0xb6000000},
+{'4', 0xfce20000, 0x0000005a},
+{'l', 0x3f1999a0, 0x40fddde0},
+{'q', 0x40f33334, 0xc1144440},
+{0, 0x41a6eeef, 0xc1144440},
+{'q', 0x415aaaac, 0x00000000},
+{0, 0x41a77778, 0x41222220},
+{'9', 0x0051003a, 0x00d5003a},
+{'l', 0x00000000, 0x3fb33320},
+{'q', 0x00000000, 0x417cccd0},
+{0, 0xc0eaaaa8, 0x41d1999b},
+{'9', 0x0053ffc6, 0x0053ff5b},
+{'m', 0xc0733330, 0xc280cccd},
+{'9', 0x0000ffa7, 0x004fff7a},
+{'l', 0x00000000, 0x420a2222},
+{'q', 0x40b55558, 0x411ccccf},
+{0, 0x41877778, 0x411ccccf},
 {'q', 0x41200000, 0x00000000},
-{0, 0x417c5958, 0xc0cc06de},
-{'9', 0xffcd002e, 0xff75002e},
-{'l', 0x00000000, 0xc22a7845},
-{'l', 0x41459574, 0x00000000},
-{'4', 0x02590000, 0x0000ff9e},
-{'l', 0x00000000, 0xc138b2af},
-{'8', 0x51ad36dd, 0x1a921ad1},
-{'q', 0xc14f3f94, 0x34000000},
-{0, 0xc19d50c1, 0xc100dbeb},
-{'9', 0xffc0ffcb, 0xff44ffcb},
-{'m', 0x41f89732, 0xc23d4302},
-{'l', 0x00000000, 0x00000000},
-{'@', 0x00000076, 0x00005157},/*        v        x-advance: 81.339844 */
-{'M', 0x408301b8, 0xc29655e8},
-{'l', 0x4151655e, 0x00000000},
-{'l', 0x41bbeb61, 0x427c5958},
-{'l', 0x41bbeb62, 0xc27c5958},
-{'l', 0x41516560, 0x00000000},
-{'l', 0xc1e180dc, 0x429655e8},
-{'l', 0xc1863a6a, 0x00000000},
-{'l', 0xc1e180dc, 0xc29655e8},
-{'@', 0x00000077, 0x0000706a},/*        w        x-advance: 112.414062 */
-{'M', 0x40b8b2af, 0xc29655e8},
-{'l', 0x4145957a, 0x00000000},
-{'l', 0x4176fad6, 0x426aa181},
-{'l', 0x4175e7f4, 0xc26aa181},
-{'l', 0x41690528, 0x00000000},
-{'l', 0x4176fad4, 0x426aa181},
-{'l', 0x4175e7f8, 0xc26aa181},
-{'l', 0x41459578, 0x00000000},
-{'l', 0xc19d50c0, 0x429655e8},
-{'l', 0xc1690528, 0x00000000},
-{'l', 0xc1816560, 0xc2767165},
-{'l', 0xc181eed0, 0x42767165},
-{'l', 0xc1690528, 0x00000000},
-{'l', 0xc19d50c0, 0xc29655e8},
-{'@', 0x00000078, 0x00005157},/*        x        x-advance: 81.339844 */
-{'M', 0x4296df5b, 0xc29655e8},
-{'l', 0xc1d9731e, 0x42124f09},
-{'l', 0x41e4b98e, 0x421a5cc7},
-{'l', 0xc1690524, 0x00000000},
-{'l', 0xc1af0898, 0xc1ec3dda},
-{'l', 0xc1af0897, 0x41ec3dda},
-{'l', 0xc1690527, 0x00000000},
-{'l', 0x41e98e9a, 0xc21d50c0},
-{'l', 0xc1d5b0f7, 0xc20f5b10},
-{'l', 0x41690526, 0x00000000},
-{'l', 0x419f768e, 0x41d63a6c},
-{'l', 0x419f768c, 0xc1d63a6c},
-{'l', 0x41690528, 0x00000000},
-{'@', 0x00000079, 0x00005157},/*        y        x-advance: 81.339844 */
-{'M', 0x4230e9aa, 0x40df5b0f},
-{'q', 0xc0a78450, 0x4156c3dc},
-{0, 0xc12338b4, 0x418c225c},
-{'9', 0x0020ffd9, 0x0020ff96},
-{'4', 0x0000ffb2, 0xffae0000},
-{'l', 0x40e7f242, 0x00000000},
-{'8', 0xed3f0028, 0xa531ed16},
-{'l', 0x400dbeb0, 0xc0b46716},
-{'l', 0xc1f338b2, 0xc293eb62},
-{'l', 0x4151655e, 0x00000000},
-{'l', 0x41bbeb61, 0x426b2af4},
-{'l', 0x41bbeb62, 0xc26b2af4},
-{'l', 0x41516560, 0x00000000},
-{'l', 0xc204149e, 0x42a44b99},
-{'@', 0x0000007a, 0x00004825},/*        z        x-advance: 72.144531 */
-{'M', 0x40f2af3f, 0xc29655e8},
-{'l', 0x426aa180, 0x00000000},
-{'l', 0x00000000, 0x41346718},
-{'l', 0xc239c595, 0x42581b7d},
-{'l', 0x4239c595, 0x35800000},
-{'l', 0x00000000, 0x411dda33},
-{'l', 0xc271579f, 0x00000000},
-{'l', 0x00000000, 0xc1346716},
-{'l', 0x4239c595, 0xc2581b7c},
-{'l', 0xc2330f76, 0x00000000},
-{'l', 0xb5000000, 0xc11dda38},
-{'@', 0x0000007b, 0x00005773},/*        {        x-advance: 87.449219 */
-{'M', 0x428c8973, 0x414c06df},
-{'4', 0x004d0000, 0x0000ffdf},
-{'q', 0xc185b0f8, 0x00000000},
-{0, 0xc1b35432, 0xc09eed1c},
-{'9', 0xffd9ffd3, 0xff62ffd3},
-{'l', 0x00000000, 0xc1805278},
-{'q', 0x00000000, 0xc12225cc},
-{0, 0xc067f240, 0xc1606df6},
-{'9', 0xffe1ffe4, 0xffe1ff97},
-{'4', 0x0000ffe0, 0xffb40000},
-{'l', 0x408301b8, 0x00000000},
-{'8', 0xe269004c, 0x911ce11c},
-{'l', 0x00000000, 0xc180dbec},
-{'q', 0x00000000, 0xc16d50c0},
-{0, 0x40b46710, 0xc19dda30},
-{'9', 0xffd9002d, 0xffd900b3},
-{'4', 0x00000021, 0x004c0000},
-{'l', 0xc0920a50, 0x00000000},
-{'8', 0x179e00b5, 0x63e917e9},
-{'l', 0x00000000, 0x41852786},
-{'q', 0x00000000, 0x41289730},
-{0, 0xc0459580, 0x4174d50c},
-{'8', 0x33ad26e8, 0x34530e3b},
-{'9', 0x00260018, 0x00790018},
-{'l', 0x00000000, 0x41852785},
-{'8', 0x63174b00, 0x17621717},
-{'l', 0x40920a50, 0x00000000},
-{'@', 0x0000007c, 0x00002e4f},/*        |        x-advance: 46.308594 */
-{'M', 0x41e6df5b, 0xc2d2112e},
-{'l', 0x00000000, 0x4309731d},
-{'l', 0xc1368ce4, 0x00000000},
-{'l', 0x00000000, 0xc309731d},
-{'l', 0x41368ce4, 0x00000000},
-{'@', 0x0000007d, 0x00005773},/*        }        x-advance: 87.449219 */
-{'M', 0x4189731d, 0x414c06df},
-{'l', 0x409655e8, 0x00000000},
-{'8', 0xe961004b, 0x9d17e917},
-{'l', 0x00000000, 0xc1852784},
-{'q', 0x00000000, 0xc127844a},
-{0, 0x404149e0, 0xc173c224},
-{'8', 0xcc53da18, 0xcdadf3c5},
-{'9', 0xffdaffe8, 0xff86ffe8},
-{'l', 0x00000000, 0xc1852786},
-{'8', 0x9de9b400, 0xe99fe9ea},
-{'4', 0x0000ffdb, 0xffb40000},
-{'l', 0x40874d50, 0x00000000},
-{'q', 0x4185b0f7, 0x00000000},
-{0, 0x41b24149, 0x409eed20},
-{'9', 0x0027002d, 0x009d002d},
-{'l', 0x00000000, 0x4180dbec},
-{'8', 0x6f1c5000, 0x1e691e1c},
-{'4', 0x00000021, 0x004c0000},
-{'l', 0xc0852780, 0x00000000},
-{'q', 0xc1187bb8, 0x00000000},
-{0, 0xc1527848, 0x407920a0},
-{'9', 0x001fffe4, 0x0070ffe4},
-{'l', 0x00000000, 0x41805278},
-{'q', 0x00000000, 0x416d50c0},
-{0, 0xc0b46718, 0x419e63a6},
-{'9', 0x0027ffd4, 0x0027ff4e},
-{'l', 0xc0874d50, 0x00000000},
-{'l', 0x00000000, 0xc11aa181},
-{'@', 0x0000007e, 0x0000732a},/*        ~        x-advance: 115.164062 */
-{'M', 0x42c93543, 0xc25b5430},
-{'l', 0x00000000, 0x413f2414},
-{'8', 0x3c982ac8, 0x129d12d1},
-{'q', 0xc0ec3dd0, 0x00000000},
-{0, 0xc189731c, 0xc07d6c40},
-{'8', 0xfdf8fefb, 0xfcf5fffd},
-{'q', 0xc1267168, 0xc0852780},
-{0, 0xc185b0f8, 0xc0852780},
-{'8', 0x14a300d1, 0x409e14d2},
-{'l', 0x00000000, 0xc13f2414},
-{'8', 0xc468d638, 0xee64ee30},
-{'q', 0x40ec3dd8, 0x00000000},
-{0, 0x4189fc90, 0x4080dbe8},
-{'8', 0x03080205, 0x040b0104},
-{'q', 0x41267164, 0x40852780},
-{0, 0x4185b0f6, 0x40852780},
-{'8', 0xec5b002e, 0xbf64ec2d},
+{0, 0x4169999c, 0xc0fbbbbe},
+{'9', 0xffc20025, 0xff6c0025},
+{'l', 0x00000000, 0xbfb33320},
+{'q', 0x00000000, 0xc12bbbbc},
+{0, 0xc0955558, 0xc1944446},
+{'q', 0xc0933338, 0xc0fbbbb8},
+{0, 0xc16bbbbc, 0xc0fbbbb8},
+{'@', 0x00000071, 0x00004d99},/*        q        x-advance: 77.597656 */
+{'M', 0x42866667, 0xc2904445},
+{'4', 0x031e0000, 0x0000ff9d},
+{'l', 0x00000000, 0xc209999a},
+{'q', 0xc0ecccd0, 0x40ffffff},
+{0, 0xc19eeef0, 0x40ffffff},
+{'q', 0xc1555556, 0xb4000000},
+{0, 0xc1a80000, 0xc1266668},
+{'9', 0xffadffc4, 0xff2fffc4},
+{'l', 0x00000000, 0xbfb33320},
+{'q', 0x00000000, 0xc1844446},
+{0, 0x40f33335, 0xc1d55556},
+{'q', 0x40f33334, 0xc1222220},
+{0, 0x41a91112, 0xc1222220},
+{'9', 0x00000066, 0x004400a2},
+{'4', 0xffc60004, 0x0000005a},
+{'m', 0xc241dddf, 0x42137778},
+{'q', 0x00000000, 0x412bbbbe},
+{0, 0x40933334, 0x4194ccce},
+{'q', 0x40955558, 0x40fbbbbe},
+{0, 0x416aaaae, 0x40fbbbbe},
+{'9', 0x00000058, 0xffb30086},
+{'l', 0x00000000, 0xc20d999a},
+{'q', 0xc0b99998, 0xc1177778},
+{0, 0xc1855556, 0xc1177778},
+{'q', 0xc1222222, 0x00000000},
+{0, 0xc16cccce, 0x41000000},
+{'q', 0xc0933334, 0x40fddde0},
+{0, 0xc0933334, 0x4195ddde},
+{'l', 0x00000000, 0x3faaaaa0},
+{'@', 0x00000072, 0x00002e44},/*        r        x-advance: 46.265625 */
+{'M', 0x4218cccd, 0xc2766667},
+{'9', 0x0000ffa0, 0x0053ff7d},
+{'l', 0x00000000, 0x424cccce},
+{'l', 0xc1455555, 0x00000000},
+{'4', 0xfdbf0000, 0x00000060},
+{'l', 0x3e888880, 0x41044448},
+{'q', 0x40bddde0, 0xc1199998},
+{0, 0x41891112, 0xc1199998},
+{'9', 0x0000001b, 0x0007002b},
+{'l', 0xbd888a00, 0x4137777c},
+{'q', 0xc02eeef0, 0xbf088880},
+{0, 0xc0c00000, 0xbf088880},
+{'[', 0x00220072, 0x00000111},/*kerning*/
+{'[', 0x00270072, 0x00000111},/*kerning*/
+{'[', 0x00660072, 0x00000100},/*kerning*/
+{'[', 0x00740072, 0x00000355},/*kerning*/
+{'[', 0x00760072, 0x00000133},/*kerning*/
+{'[', 0x00770072, 0x00000122},/*kerning*/
+{'[', 0x00790072, 0x00000133},/*kerning*/
+{'@', 0x00000073, 0x00004677},/*        s        x-advance: 70.464844 */
+{'M', 0x424d999a, 0xc1991112},
+{'8', 0xc8e9e100, 0xd696e7ea},
+{'q', 0xc1411112, 0xc01dddd8},
+{0, 0xc199999a, 0xc0e44444},
+{'q', 0xc0e44446, 0xc0977778},
+{0, 0xc0e44446, 0xc15bbbbc},
+{'q', 0x00000000, 0xc108888c},
+{0, 0x40e8888a, 0xc16cccd0},
+{'q', 0x40eaaaac, 0xc0c88880},
+{0, 0x419bbbbd, 0xc0c88880},
+{'q', 0x414eeef0, 0x00000000},
+{0, 0x41a1999a, 0x40d33330},
+{'9', 0x0034003a, 0x007f003a},
+{'l', 0xc1455558, 0x00000000},
+{'8', 0xbde1dd00, 0xe0a7e0e1},
+{'8', 0x1aa800c3, 0x3ae61ae6},
+{'8', 0x33181f00, 0x25691319},
+{'q', 0x41544448, 0x40400000},
+{0, 0x419ddde0, 0x40fbbbb8},
+{'q', 0x40d11110, 0x409bbbc0},
+{0, 0x40d11110, 0x415bbbbe},
+{'q', 0x00000000, 0x41188889},
+{0, 0xc0f55558, 0x41777778},
+{'q', 0xc0f33330, 0x40bddddf},
+{0, 0xc1a1999a, 0x40bddddf},
+{'q', 0xc1655556, 0xb4000000},
+{0, 0xc1af7778, 0xc0eaaaac},
+{'9', 0xffc6ffc4, 0xff7effc4},
+{'l', 0x41466666, 0x00000000},
+{'8', 0x542e3d03, 0x165a162c},
+{'8', 0xe95c003c, 0xc520e920},
+{'@', 0x00000074, 0x00002caa},/*        t        x-advance: 44.664062 */
+{'M', 0x421fbbbc, 0x00000000},
+{'8', 0x0ab40adf, 0xdfa300ca},
+{'9', 0xffdfffda, 0xff88ffda},
+{'l', 0x00000000, 0xc232eef0},
+{'l', 0xc1533334, 0x00000000},
+{'l', 0xb4c00000, 0xc1177778},
+{'l', 0x41533334, 0x00000000},
+{'l', 0x00000000, 0xc18c4444},
+{'l', 0x41455556, 0x00000000},
+{'l', 0x00000000, 0x418c4444},
+{'l', 0x41577778, 0x00000000},
+{'4', 0x004b0000, 0x0000ff95},
+{'l', 0x00000000, 0x42333334},
+{'8', 0x38132c00, 0x0c2c0c13},
+{'q', 0x40155550, 0x00000000},
+{0, 0x40b99998, 0xbf4cccd0},
+{'l', 0x3d888800, 0x41211112},
+{'@', 0x00000075, 0x00004b44},/*        u        x-advance: 75.265625 */
+{'M', 0x42588889, 0x00000000},
+{'l', 0xbe888880, 0xc0e44445},
+{'q', 0xc0e22220, 0x41077778},
+{0, 0xc1a88888, 0x41077778},
+{'q', 0xc129999c, 0xb4000000},
+{0, 0xc1891112, 0xc0c88889},
+{'9', 0xffceffcc, 0xff5bffcc},
+{'4', 0xfe8c0000, 0x00000062},
+{'l', 0x00000000, 0x423aaaac},
+{'8', 0x68204d00, 0x1a491a21},
+{'9', 0x0000006f, 0xffad0096},
+{'l', 0x00000000, 0xc2522224},
+{'l', 0x41466664, 0x00000000},
+{'l', 0x00000000, 0x42904445},
+{'l', 0xc13ccccc, 0x00000000},
+{'@', 0x00000076, 0x00004222},/*        v        x-advance: 66.132812 */
+{'M', 0x427eaaac, 0xc2904445},
+{'l', 0xc1cf777a, 0x42904445},
+{'l', 0xc1166666, 0x00000000},
+{'l', 0xc1d11111, 0xc2904445},
+{'l', 0x414aaaab, 0x00000000},
+{'l', 0x4192aaaa, 0x425d1112},
+{'l', 0x418eeef0, 0xc25d1112},
+{'l', 0x4149999c, 0x00000000},
+{'[', 0x00220076, 0x00000100},/*kerning*/
+{'[', 0x00270076, 0x00000100},/*kerning*/
+{'[', 0x00660076, 0x000000dd},/*kerning*/
+{'@', 0x00000077, 0x00006699},/*        w        x-advance: 102.597656 */
+{'M', 0x42c6cccd, 0xc2904445},
+{'l', 0xc1a77778, 0x42904445},
+{'l', 0xc1200000, 0x00000000},
+{'l', 0xc18c4444, 0xc25a6667},
+{'l', 0xc1888888, 0x425a6667},
+{'l', 0xc1211112, 0x00000000},
+{'l', 0xc1a77778, 0xc2904445},
+{'l', 0x41455556, 0x00000000},
+{'l', 0x41633334, 0x42577778},
+{'l', 0x41866666, 0xc2577778},
+{'l', 0x411eeef0, 0x00000000},
+{'l', 0x4188888a, 0x425c0001},
+{'l', 0x415eeef0, 0xc25c0001},
+{'l', 0x41444440, 0x00000000},
+{'@', 0x00000078, 0x000043bb},/*        x        x-advance: 67.730469 */
+{'M', 0x418dddde, 0xc2904445},
+{'l', 0x417cccd0, 0x41d22224},
+{'l', 0x41800000, 0xc1d22224},
+{'l', 0x41677774, 0x00000000},
+{'l', 0xc1bccccc, 0x420e6667},
+{'l', 0x41c2aaac, 0x42122223},
+{'l', 0xc1644444, 0x00000000},
+{'l', 0xc1855556, 0xc1d88889},
+{'l', 0xc1855556, 0x41d88889},
+{'l', 0xc1655557, 0x00000000},
+{'l', 0x41c22222, 0xc2122223},
+{'l', 0xc1bc4444, 0xc20e6667},
+{'l', 0x41633334, 0x00000000},
+{'@', 0x00000079, 0x00004099},/*        y        x-advance: 64.597656 */
+{'M', 0x42080000, 0x41322223},
+{'9', 0x0087ffcd, 0x008fff66},
+{'l', 0xc0044448, 0x3d888800},
+{'9', 0x0000ffe1, 0xfff8ffc9},
+{'4', 0xffb00000, 0x0002001a},
+{'8', 0xec4e0032, 0xb62eec1c},
+{'l', 0x402aaaa8, 0xc0eaaaac},
+{'l', 0xc1cdddde, 0xc28eaaab},
+{'l', 0x41577778, 0x00000000},
+{'l', 0x41908888, 0x42580001},
+{'l', 0x4185dde0, 0xc2580001},
+{'l', 0x41533334, 0x00000000},
+{'l', 0xc1e7777a, 0x42a68889},
+{'[', 0x00220079, 0x00000100},/*kerning*/
+{'[', 0x00270079, 0x00000100},/*kerning*/
+{'[', 0x00660079, 0x000000dd},/*kerning*/
+{'@', 0x0000007a, 0x000043bb},/*        z        x-advance: 67.730469 */
+{'M', 0x40ceeef0, 0xc277bbbd},
+{'l', 0x00000000, 0xc1233334},
+{'l', 0x425aeef0, 0x00000000},
+{'l', 0x00000000, 0x410bbbc0},
+{'l', 0xc220888a, 0x42551111},
+{'l', 0x42284445, 0x35800000},
+{'l', 0x00000000, 0x41222223},
+{'l', 0xc264cccd, 0x00000000},
+{'l', 0xb5000000, 0xc1111112},
+{'l', 0x421eeeef, 0xc2537778},
+{'l', 0xc21ccccd, 0xb6800000},
+{'@', 0x0000007b, 0x00002e33},/*        {        x-advance: 46.199219 */
+{'M', 0x40888889, 0xc210cccd},
+{'l', 0x00000000, 0xc11aaaac},
+{'9', 0x00000071, 0xff7f0071},
+{'l', 0x00000000, 0xc1577774},
+{'q', 0x00000000, 0xc1288890},
+{0, 0x40a22220, 0xc1966668},
+{'9', 0xffbe0028, 0xff9f0095},
+{'l', 0x40266670, 0x40f33340},
+{'q', 0xc0fddde0, 0x401ddde0},
+{0, 0xc12eeef0, 0x410dddd8},
+{'9', 0x0032ffe8, 0x0074ffe8},
+{'l', 0x00000000, 0x41533330},
+{'q', 0x00000000, 0x41744444},
+{0, 0xc1322222, 0x41aa2222},
+{'9', 0x002e0059, 0x00aa0059},
+{'l', 0x00000000, 0x41511112},
+{'q', 0x00000000, 0x41033334},
+{0, 0x40400008, 0x4168888a},
+{'9', 0x00320018, 0x00460057},
+{'l', 0xc0266670, 0x40f55558},
+{'q', 0xc159999a, 0xc0777778},
+{0, 0xc1955556, 0xc1433334},
+{'9', 0xffbeffd8, 0xff6affd8},
+{'l', 0x00000000, 0xc1555556},
+{'q', 0x00000000, 0xc1822222},
+{0, 0xc1622224, 0xc1822222},
+{'@', 0x0000007c, 0x00002155},/*        |        x-advance: 33.332031 */
+{'M', 0x41ad5556, 0xc2c22223},
+{'l', 0x00000000, 0x42e62223},
+{'l', 0xc11eeef0, 0x00000000},
+{'l', 0x00000000, 0xc2e62223},
+{'l', 0x411eeef0, 0x00000000},
+{'@', 0x0000007d, 0x00002e33},/*        }        x-advance: 46.199219 */
+{'M', 0x42273334, 0xc2377778},
+{'l', 0x00000000, 0x411aaaac},
+{'9', 0x0000ff8f, 0x0081ff8f},
+{'l', 0x00000000, 0x41577778},
+{'q', 0x00000000, 0x41277778},
+{0, 0xc0a22224, 0x41966667},
+{'9', 0x0042ffd8, 0x0061ff6b},
+{'l', 0xc026666a, 0xc0f55558},
+{'q', 0x40fbbbbd, 0xc01ddddc},
+{0, 0x412dddde, 0xc10ccccc},
+{'9', 0xffce0018, 0xff8c0018},
+{'l', 0x00000000, 0xc1544444},
+{'q', 0x00000000, 0xc17aaaae},
+{0, 0x41422223, 0xc1a91113},
+{'9', 0xffd5ff9f, 0xff57ff9f},
+{'l', 0x00000000, 0xc1544440},
+{'q', 0x00000000, 0xc1033338},
+{0, 0xc0400000, 0xc1688890},
+{'9', 0xffcdffe8, 0xffbaffa9},
+{'l', 0x40266669, 0xc0f33340},
+{'q', 0x415aaaab, 0x40777780},
+{0, 0x41955555, 0x41433338},
+{'9', 0x00420028, 0x00960028},
+{'l', 0x00000000, 0x41599998},
+{'q', 0x00000000, 0x41800000},
+{0, 0x41622224, 0x41800000},
+{'@', 0x0000007e, 0x00005cdd},/*        ~        x-advance: 92.863281 */
+{'M', 0x42942223, 0xc24f3334},
+{'l', 0x41222220, 0xbd888800},
+{'q', 0x00000000, 0x41244444},
+{0, 0xc0c22220, 0x418d5556},
+{'q', 0xc0c00000, 0x40eaaaa8},
+{0, 0xc178888c, 0x40eaaaa8},
+{'8', 0xeeae00d2, 0xcab4eedd},
+{'8', 0xdacee7e5, 0xf3cff3ea},
+{'8', 0x1cc100d8, 0x4eea1cea},
+{'l', 0xc12bbbbc, 0x3e088880},
+{'q', 0x00000000, 0xc127777a},
+{0, 0x40c00002, 0xc18bbbbd},
+{'q', 0x40c22222, 0xc0e00000},
+{0, 0x41788889, 0xc0e00000},
+{'8', 0x1351002d, 0x354b1223},
+{'8', 0x2c3b2328, 0x09290913},
+{'8', 0xe1420029, 0xaf19e119},
 };
-#define CTX_FONT_ascii 1
+#define ctx_font_ascii_name "Roboto"
 #endif
 #endif //_CTX_INTERNAL_FONT_
 #ifndef __CTX_LIST__
 #define __CTX_LIST__
 
-#if !__COSMOPOLITAN__
 #include <stdlib.h>
-#endif
 
-/* The whole ctx_list implementation is in the header and will be inlined
- * wherever it is used.
- */
+#ifndef CTX_EXTERNAL_MALLOC
+static inline void *ctx_realloc (void *mem, size_t old_size, size_t new_size)
+{
+  return (void*)realloc (mem, new_size);
+}
+
+static inline void *ctx_malloc (size_t size)
+{
+  return (void*)malloc (size);
+}
+
+static inline void ctx_free (void *mem)
+{
+  free (mem);
+}
 
 static inline void *ctx_calloc (size_t size, size_t count)
 {
-  size_t byte_size = size * count;
-  char *ret = (char*)malloc (byte_size);
-  for (size_t i = 0; i < byte_size; i++)
-     ret[i] = 0;
-  return ret;
+  return calloc (size, count);
 }
 
+#endif
+
+/* The whole ctx_list implementation is in the header and will be inlined
+ * wherever it is used.
+ */
 struct _CtxList {
   void *data;
   CtxList *next;
@@ -4524,7 +4644,7 @@ static inline void ctx_list_remove (CtxList **list, void *data)
       if ((*list)->freefunc)
         (*list)->freefunc ((*list)->data, (*list)->freefunc_data);
       prev = (*list)->next;
-      free (*list);
+      ctx_free (*list);
       *list = prev;
       return;
     }
@@ -4534,7 +4654,7 @@ static inline void ctx_list_remove (CtxList **list, void *data)
         if (iter->freefunc)
           iter->freefunc (iter->data, iter->freefunc_data);
         prev->next = iter->next;
-        free (iter);
+        ctx_free (iter);
         break;
       }
     else
@@ -4747,6 +4867,9 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
  * option is used set to 0 by the tool that converts ttf fonts to ctx internal
  * representation - both should be possible so that this tool can be made
  * into a TTF/OTF font import at runtime (perhaps even with live subsetting).
+ *
+ * improving this feature and making it runtime selectable could also
+ * be part of encoding all text as beziers upon pdf export
  */
 #ifndef CTX_BACKEND_TEXT
 #define CTX_BACKEND_TEXT 1
@@ -4960,6 +5083,11 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_MAX_EDGE_LIST_SIZE  CTX_MIN_EDGE_LIST_SIZE
 #endif
 
+#ifndef CTX_MAX_KEYDB
+#define CTX_MAX_KEYDB 64 // number of entries in keydb
+                         // entries are "copy-on-change" between states
+#endif
+
 #ifndef CTX_STRINGPOOL_SIZE
   // XXX should be possible to make zero and disappear when codepaths not in use
   //     to save size, for card10 this is defined as a low number (some text
@@ -4973,6 +5101,7 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #ifndef CTX_32BIT_SEGMENTS
 #define CTX_32BIT_SEGMENTS 1  // without this clipping problems might
                               // occur when drawing far outside the viewport
+                              // or with large translate amounts
                               // on micro controllers you most often will
                               // want this set to 0
 #endif
@@ -5003,7 +5132,7 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
  * up compiles at penalty for the given formats.
  */
 #ifndef CTX_INLINED_NORMAL     
-#define CTX_INLINED_NORMAL      0
+#define CTX_INLINED_NORMAL      1
 #endif
 
 /*
@@ -5054,6 +5183,30 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_EVENTS              1
 #endif
 
+#ifndef CTX_AVOID_CLIPPED_SUBDIVISION
+#define CTX_AVOID_CLIPPED_SUBDIVISION 0
+#endif
+
+#ifndef CTX_MAX_DEVICES
+#define CTX_MAX_DEVICES 16
+#endif
+
+#ifndef CTX_MAX_KEYBINDINGS
+#define CTX_MAX_KEYBINDINGS 256
+#endif
+
+
+#ifndef CTX_PROTOCOL_U8_COLOR
+#define CTX_PROTOCOL_U8_COLOR 0
+#endif
+
+#ifndef CTX_TERMINAL_EVENTS
+#if CTX_EVENTS
+#define CTX_TERMINAL_EVENTS 1
+#else
+#define CTX_TERMINAL_EVENTS 0
+#endif
+#endif
 
 #ifndef CTX_LIMIT_FORMATS
 #define CTX_LIMIT_FORMATS       0
@@ -5113,17 +5266,21 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
                                             // for a ~15% overall performance hit
 #endif
 
+
 /* by including ctx-font-regular.h, or ctx-font-mono.h the
  * built-in fonts using ctx drawlist encoding is enabled
  */
-#if CTX_FONT_regular || CTX_FONT_mono || CTX_FONT_bold \
-  || CTX_FONT_italic || CTX_FONT_sans || CTX_FONT_serif \
-  || CTX_FONT_ascii
+#ifndef CTX_NO_FONTS
 #ifndef CTX_FONT_ENGINE_CTX
 #define CTX_FONT_ENGINE_CTX        1
 #endif
 #endif
 
+#ifndef CTX_ONE_FONT_ENGINE
+#define CTX_ONE_FONT_ENGINE 0
+#endif
+
+
 #ifndef CTX_FONT_ENGINE_CTX_FS
 #define CTX_FONT_ENGINE_CTX_FS 0
 #endif
@@ -5248,7 +5405,7 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 
 #define CTX_PI                              3.141592653589793f
 #ifndef CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS
-#define CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS  (180)
+#define CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS  (128)
 #endif
 
 #ifndef CTX_MAX_FRAMEBUFFER_WIDTH
@@ -5256,7 +5413,15 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #endif
 
 #ifndef CTX_MAX_FONTS
-#define CTX_MAX_FONTS            3
+#define CTX_MAX_FONTS            32
+#endif
+
+#ifndef CTX_GLYPH_CACHE
+#define CTX_GLYPH_CACHE 1
+#endif
+
+#ifndef CTX_GLYPH_CACHE_SIZE
+#define CTX_GLYPH_CACHE_SIZE  128
 #endif
 
 #ifndef CTX_MAX_STATES
@@ -5281,10 +5446,10 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #endif
 
 #ifndef CTX_HASH_ROWS
-#define CTX_HASH_ROWS            4
+#define CTX_HASH_ROWS            6
 #endif
 #ifndef CTX_HASH_COLS
-#define CTX_HASH_COLS            8
+#define CTX_HASH_COLS            5
 #endif
 
 #ifndef CTX_INLINE_FILL_RULE
@@ -5310,8 +5475,18 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_IMPLEMENTATION 1
 #endif
 
+#ifndef CTX_MAX_SCANLINE_LENGTH
+#define CTX_MAX_SCANLINE_LENGTH 4096
+#endif
+
 
-#ifndef static_OPAQUE
+#ifndef CTX_MAX_CBS
+#define CTX_MAX_CBS              1 //128
+#endif
+
+#ifndef static_OPAQUE // causes a CTX_MAX_SCANLINE_LENGTH
+                          // buffer of 255 bytes to be part of
+                          // rasterizer
 #define static_OPAQUE 1
 #endif
 
@@ -5338,8 +5513,12 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_EVENTS 1
 #endif
 
-#if CTX_EVENTS
+
+
+
 #ifndef CTX_HEADLESS
+
+#if CTX_FB || CTX_SDL || CTX_KMS
 #define CTX_HEADLESS 1
 #endif
 #endif
@@ -5353,6 +5532,9 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_PARSER_MAX_ARGS 20
 #endif
 
+#ifndef CTX_MAX_DASHES
+#define CTX_MAX_DASHES CTX_PARSER_MAX_ARGS
+#endif
 
 #ifndef CTX_SCREENSHOT
 #define CTX_SCREENSHOT 0
@@ -5447,6 +5629,9 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_COMPOSITE 0
 #endif
 
+#ifndef CTX_MAX_GRADIENT_STOPS
+#define CTX_MAX_GRADIENT_STOPS 16
+#endif
 
 #ifndef CTX_BRANCH_HINTS
 #define CTX_BRANCH_HINTS  1
@@ -5458,6 +5643,9 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_WASM 0
 #endif
 
+#ifndef CTX_MAX_LISTEN_FDS
+#define CTX_MAX_LISTEN_FDS 128 // becomes max clients..
+#endif
 
 #if CTX_WASM
 #undef CTX_THREADS
@@ -5480,10 +5668,18 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
 #define CTX_TINYVG 0
 #endif
 
+#ifndef CTX_PDF
+#define CTX_PDF 0
+#endif
+
 #define uncompress tinf_uncompress
 #define Z_OK TINF_OK
 #define Z_BUF_ERROR TINF_BUF_ERROR
 #define Z_DATA_ERROR TINF_DATA_ERROR
+
+#ifndef CTX_ENABLE_CBRLE
+#define CTX_ENABLE_CBRLE 0
+#endif
  /* Copyright (C) 2020 Øyvind Kolås <pippin gimp org>
  */
 
@@ -5528,6 +5724,8 @@ typedef enum CtxOutputmode
   CTX_OUTPUT_MODE_GRAYS,
   CTX_OUTPUT_MODE_CTX,
   CTX_OUTPUT_MODE_CTX_COMPACT,
+  CTX_OUTPUT_MODE_CTX_FILE,
+  CTX_OUTPUT_MODE_CTX_COMPACT_FILE,
   CTX_OUTPUT_MODE_UI
 } CtxOutputmode;
 
@@ -5603,7 +5801,7 @@ ctx_sinf (float x)
   if (x < -CTX_PI * 2)
     {
       x = -x;
-      long ix = x / (CTX_PI * 2);
+      long ix = (long)(x / (CTX_PI * 2));
       x = x - ix * CTX_PI * 2;
       x = -x;
     }
@@ -5619,7 +5817,7 @@ ctx_sinf (float x)
   }
   if (x > CTX_PI * 2)
     { 
-      long ix = x / (CTX_PI * 2);
+      long ix = (long)(x / (CTX_PI * 2));
       x = x - (ix * CTX_PI * 2);
     }
   while (x < -CTX_PI)
@@ -5724,6 +5922,7 @@ ctx_expf (float x)
 #endif
 static inline float ctx_fabsf (float x)           { return fabsf (x); }
 static inline float ctx_floorf (float x)          { return floorf (x); }
+static inline float ctx_asinf (float x)            { return asinf (x); }
 static inline float ctx_sinf (float x)            { return sinf (x); }
 static inline float ctx_atan2f (float y, float x) { return atan2f (y, x); }
 static inline float ctx_hypotf (float a, float b) { return hypotf (a, b); }
@@ -5732,11 +5931,16 @@ static inline float ctx_cosf (float a)            { return cosf (a); }
 static inline float ctx_tanf (float a)            { return tanf (a); }
 static inline float ctx_expf (float p)            { return expf (p); }
 static inline float ctx_sqrtf (float a)           { return sqrtf (a); }
+
+static inline float ctx_hypotf_fast (float a, float b)
+{
+  return ctx_sqrtf (ctx_pow2 (a)+ctx_pow2 (b) );
+}
 #endif
 
 static inline float _ctx_parse_float (const char *str, char **endptr)
 {
-  return strtod (str, endptr); /* XXX: , vs . problem in some locales */
+  return strtof (str, endptr); /* XXX: , vs . problem in some locales */
 }
 
 const char *ctx_get_string (Ctx *ctx, uint32_t hash);
@@ -5827,261 +6031,204 @@ int ctx_pixel_format_ebpp (CtxPixelFormat format);
 #endif
 #ifndef __CTX_CONSTANTS
 #define __CTX_CONSTANTS
-
-#define TOKENHASH(a)    ((uint32_t)a)
-
-#define CTX_strokeSource TOKENHASH(3387288669)
-#define CTX_add_stop TOKENHASH(3572486242)
-#define CTX_addStop TOKENHASH(3805374936)
-#define CTX_alphabetic TOKENHASH(2558771929)
-#define CTX_arc TOKENHASH(7298)
-#define CTX_arc_to TOKENHASH(4010563993)
-#define CTX_arcTo TOKENHASH(4138935887)
-#define CTX_begin_path TOKENHASH(3275811535)
-#define CTX_beginPath TOKENHASH(2384638508)
-#define CTX_bevel TOKENHASH(25538884)
-#define CTX_bottom TOKENHASH(905225156)
-#define CTX_cap TOKENHASH(32838)
-#define CTX_center TOKENHASH(1219785030)
-#define CTX_clear TOKENHASH(37825286)
-#define CTX_color TOKENHASH(38757318)
-#define CTX_copy TOKENHASH(1672134)
-#define CTX_clip TOKENHASH(1067782)
-#define CTX_close_path TOKENHASH(3215881683)
-#define CTX_closePath TOKENHASH(3625577848)
-#define CTX_cmyka TOKENHASH(2870086)
-#define CTX_cmyk TOKENHASH(772934)
-#define CTX_cmykaS TOKENHASH(3116500921)
-#define CTX_cmykS TOKENHASH(934005574)
-#define CTX_color TOKENHASH(38757318)
-#define CTX_blending TOKENHASH(3402343403)
-#define CTX_blend TOKENHASH(9317124)
-#define CTX_blending_mode TOKENHASH(4000829592)
-#define CTX_blendingMode TOKENHASH(2577020122)
-#define CTX_blend_mode TOKENHASH(2229422236)
-#define CTX_blendMode TOKENHASH(3450578624)
-#define CTX_composite TOKENHASH(2191186513)
-#define CTX_compositing_mode TOKENHASH(3415700633)
-#define CTX_compositingMode TOKENHASH(3625102151)
-#define CTX_curve_to TOKENHASH(3569729066)
-#define CTX_curveTo TOKENHASH(3536162037)
-#define CTX_darken TOKENHASH(950767688)
-#define CTX_defineGlyph TOKENHASH(3698027829)
-#define CTX_defineTexture TOKENHASH(4201008335)
-#define CTX_kerningPair TOKENHASH(3655936472)
-#define CTX_destinationIn TOKENHASH(2718725020)
-#define CTX_destination_in TOKENHASH(3351938654)
-#define CTX_destinationAtop TOKENHASH(3609906960)
-#define CTX_destination_atop TOKENHASH(2783515582)
-#define CTX_destinationOver TOKENHASH(2378926016)
-#define CTX_destination_over TOKENHASH(2856771196)
-#define CTX_destinationOut TOKENHASH(3944490553)
-#define CTX_destination_out TOKENHASH(3021444620)
-#define CTX_difference TOKENHASH(2530251746)
-#define CTX_done TOKENHASH(357320)
-#define CTX_drgba TOKENHASH(2243720)
-#define CTX_drgb TOKENHASH(146568)
-#define CTX_drgbaS TOKENHASH(2541895879)
-#define CTX_drgbS TOKENHASH(933379208)
-#define CTX_end TOKENHASH(9098)
-#define CTX_endfun TOKENHASH(983966602)
-#define CTX_end_group TOKENHASH(2564160724)
-#define CTX_endGroup TOKENHASH(3639210663)
-#define CTX_even_odd TOKENHASH(2587574889)
-#define CTX_evenOdd TOKENHASH(4065502508)
-#define CTX_exit TOKENHASH(1330698)
-#define CTX_extend TOKENHASH(298165770)
-#define CTX_fill TOKENHASH(811596)
-#define CTX_fill_rule TOKENHASH(3026141741)
-#define CTX_fillRule TOKENHASH(2727819936)
-#define CTX_flush TOKENHASH(18066188)
-#define CTX_font TOKENHASH(1340364)
-#define CTX_font_size TOKENHASH(3138232552)
-#define CTX_setFontSize TOKENHASH(2794810212)
-#define CTX_fontSize TOKENHASH(2516141542)
-#define CTX_function TOKENHASH(2157387644)
-#define CTX_getkey TOKENHASH(1688969550)
-#define CTX_global_alpha TOKENHASH(4195339170)
-#define CTX_globalAlpha TOKENHASH(3503999095)
-#define CTX_glyph TOKENHASH(17877774)
-#define CTX_gradient_add_stop TOKENHASH(2527862800)
-#define CTX_gradientAddStop TOKENHASH(2707733066)
-#define CTX_graya TOKENHASH(3738766)
-#define CTX_gray TOKENHASH(1641614)
-#define CTX_grayaS TOKENHASH(3152913809)
-#define CTX_grayS TOKENHASH(934874254)
-#define CTX_hanging TOKENHASH(3379012612)
-#define CTX_height TOKENHASH(1359432016)
-#define CTX_hor_line_to TOKENHASH(3576305368)
-#define CTX_horLineTo TOKENHASH(2768557894)
-#define CTX_hue TOKENHASH(11600)
-#define CTX_identity TOKENHASH(4244560551)
-#define CTX_ideographic TOKENHASH(4062138887)
-#define CTX_imageSmoothing TOKENHASH(3391439578)
-#define CTX_join TOKENHASH(936916)
-#define CTX_laba TOKENHASH(69720)
-#define CTX_lab TOKENHASH(4184)
-#define CTX_lcha TOKENHASH(82136)
-#define CTX_lch TOKENHASH(16600)
-#define CTX_labaS TOKENHASH(933302360)
-#define CTX_labS TOKENHASH(29167704)
-#define CTX_lchaS TOKENHASH(933314776)
-#define CTX_lchS TOKENHASH(29180120)
-#define CTX_left TOKENHASH(1323352)
-#define CTX_lighter TOKENHASH(3085731552)
-#define CTX_lighten TOKENHASH(2243427702)
-#define CTX_linear_gradient TOKENHASH(2750495200)
-#define CTX_linearGradient TOKENHASH(2530643087)
-#define CTX_line_cap TOKENHASH(3442398380)
-#define CTX_lineCap TOKENHASH(4099906770)
-#define CTX_setLineCap TOKENHASH(3062640202)
-#define CTX_line_height TOKENHASH(2825006065)
-#define CTX_line_join TOKENHASH(2796226529)
-#define CTX_lineJoin TOKENHASH(3149521206)
-#define CTX_setLineJoin TOKENHASH(3876390174)
-#define CTX_line_spacing TOKENHASH(3474024390)
-#define CTX_line_to TOKENHASH(2950597468)
-#define CTX_lineTo TOKENHASH(3995194545)
-#define CTX_lineDash TOKENHASH(2275747153)
-#define CTX_lineDashOffset TOKENHASH(2164798257)
-#define CTX_line_width TOKENHASH(2644675969)
-#define CTX_lineWidth TOKENHASH(4067116285)
-#define CTX_setLineWidth TOKENHASH(3835759450)
-#define CTX_view_box TOKENHASH(3076034236)
-#define CTX_viewBox TOKENHASH(3661895848)
-#define CTX_middle TOKENHASH(360981082)
-#define CTX_miter TOKENHASH(38117978)
-#define CTX_miter_limit TOKENHASH(2692682139)
-#define CTX_miterLimit TOKENHASH(3784823268)
-#define CTX_move_to TOKENHASH(3482077014)
-#define CTX_moveTo TOKENHASH(3135948887)
-#define CTX_multiply TOKENHASH(2379318058)
-#define CTX_new_page TOKENHASH(3781461413)
-#define CTX_newPage TOKENHASH(3875814849)
-#define CTX_new_path TOKENHASH(4253517559)
-#define CTX_newPath TOKENHASH(2442450175)
-#define CTX_new_state TOKENHASH(3282144098)
-#define CTX_none TOKENHASH(357340)
-#define CTX_nonzero TOKENHASH(2230085415)
-#define CTX_non_zero TOKENHASH(3127422280)
-#define CTX_normal TOKENHASH(808293340)
-#define CTX_paint TOKENHASH(42879072)
-#define CTX_quad_to TOKENHASH(3896875982)
-#define CTX_quadTo TOKENHASH(3916306495)
-#define CTX_radial_gradient TOKENHASH(4226017763)
-#define CTX_radialGradient TOKENHASH(3218566169)
-#define CTX_rectangle TOKENHASH(4111149391)
-#define CTX_rect TOKENHASH(1317220)
-#define CTX_rel_arc_to TOKENHASH(2653353243)
-#define CTX_relArcTo TOKENHASH(2940381656)
-#define CTX_rel_curve_to TOKENHASH(2413603721)
-#define CTX_relCurveTo TOKENHASH(3745640049)
-#define CTX_rel_hor_line_to TOKENHASH(3292310681)
-#define CTX_relHorLineTo TOKENHASH(2661057467)
-#define CTX_relVerLineTo TOKENHASH(3868849192)
-#define CTX_rel_line_to TOKENHASH(2865414393)
-#define CTX_relLineTo TOKENHASH(2437091951)
-#define CTX_rel_move_to TOKENHASH(4169997481)
-#define CTX_relMoveTo TOKENHASH(2527491593)
-#define CTX_rel_quad_to TOKENHASH(4209276505)
-#define CTX_relQuadTo TOKENHASH(3961311908)
-#define CTX_rel_smoothq_to TOKENHASH(3923163705)
-#define CTX_relSmoothqTo TOKENHASH(2913202089)
-#define CTX_rel_smooth_to TOKENHASH(4229528839)
-#define CTX_relSmoothTo TOKENHASH(3458671695)
-#define CTX_rel_ver_line_to TOKENHASH(2484242991)
-#define CTX_restore TOKENHASH(2936409475)
-#define CTX_reset TOKENHASH(42309988)
-#define CTX_rgba TOKENHASH(70116)
-#define CTX_rgb TOKENHASH(4580)
-#define CTX_rgbaS TOKENHASH(933302756)
-#define CTX_rgbS TOKENHASH(29168100)
-#define CTX_right TOKENHASH(42482276)
-#define CTX_rotate TOKENHASH(377594852)
-#define CTX_round TOKENHASH(9350116)
-#define CTX_round_rectangle TOKENHASH(2766896494)
-#define CTX_roundRectangle TOKENHASH(3688082153)
-#define CTX_save TOKENHASH(372838)
-#define CTX_scale TOKENHASH(11274470)
-#define CTX_screen TOKENHASH(950374630)
-#define CTX_setkey TOKENHASH(1688969574)
-#define CTX_shadowBlur TOKENHASH(3119062524)
-#define CTX_shadowColor TOKENHASH(3795289804)
-#define CTX_shadowOffsetX TOKENHASH(4134163333)
-#define CTX_shadowOffsetY TOKENHASH(3519010566)
-#define CTX_smooth_quad_to TOKENHASH(3789701842)
-#define CTX_smoothQuadTo TOKENHASH(4024936051)
-#define CTX_smooth_to TOKENHASH(2307159288)
-#define CTX_smoothTo TOKENHASH(3997790061)
-#define CTX_sourceIn TOKENHASH(3513756343)
-#define CTX_source_in TOKENHASH(3936775584)
-#define CTX_sourceAtop TOKENHASH(3201391080)
-#define CTX_source_atop TOKENHASH(3568635572)
-#define CTX_sourceOut TOKENHASH(4217691207)
-#define CTX_source_out TOKENHASH(2998974401)
-#define CTX_sourceOver TOKENHASH(4071274055)
-#define CTX_sourceTransform TOKENHASH(3608891648)
-#define CTX_source_over TOKENHASH(2221728393)
-#define CTX_square TOKENHASH(373402726)
-#define CTX_start TOKENHASH(43126054)
-#define CTX_start_move TOKENHASH(2528525896)
-#define CTX_start_group TOKENHASH(2643259216)
-#define CTX_startGroup TOKENHASH(4199711715)
-#define CTX_stroke TOKENHASH(359634214)
-#define CTX_text_align TOKENHASH(2641259250)
-#define CTX_textAlign TOKENHASH(4087119491)
-#define CTX_texture TOKENHASH(2603404275)
-#define CTX_text_baseline TOKENHASH(2666328946)
-#define CTX_text_baseline TOKENHASH(2666328946)
-#define CTX_textBaseline TOKENHASH(3671121506)
-#define CTX_fillRect TOKENHASH(2617922007)
-#define CTX_text TOKENHASH(1360232)
-#define CTX_text_direction TOKENHASH(2683352974)
-#define CTX_textDirection TOKENHASH(2303324726)
-#define CTX_text_stroke TOKENHASH(2394879415)
-#define CTX_strokeText TOKENHASH(4077103477)
-#define CTX_strokeRect TOKENHASH(3918462693)
-#define CTX_top TOKENHASH(33768)
-#define CTX_transform TOKENHASH(3717307466)
-#define CTX_translate TOKENHASH(2746303805)
-#define CTX_verLineTo TOKENHASH(2881865279)
-#define CTX_ver_line_to TOKENHASH(3445689061)
-#define CTX_width TOKENHASH(18096750)
-#define CTX_winding TOKENHASH(3743938776)
-#define CTX_x TOKENHASH(48)
-#define CTX_xor TOKENHASH(37872)
-#define CTX_y TOKENHASH(50)
-#define CTX_colorSpace TOKENHASH(2624117287)
-#define CTX_userRGB TOKENHASH(2839509677)
-#define CTX_userCMYK TOKENHASH(4240023559)
-#define CTX_deviceRGB TOKENHASH(3975717407)
-#define CTX_deviceCMYK TOKENHASH(4096729420)
-#define CTX_silver TOKENHASH(1219912294)
-#define CTX_fuchsia TOKENHASH(3356500405)
-#define CTX_gray TOKENHASH(1641614)
-#define CTX_yellow TOKENHASH(1575772530)
-#define CTX_white TOKENHASH(11815470)
-#define CTX_maroon TOKENHASH(972001370)
-#define CTX_magenta TOKENHASH(2383173845)
-#define CTX_blue TOKENHASH(371460)
-#define CTX_green TOKENHASH(29699214)
-#define CTX_red TOKENHASH(8548)
-#define CTX_purple TOKENHASH(361796960)
-#define CTX_olive TOKENHASH(11946782)
-#define CTX_teal TOKENHASH(788840)
-#define CTX_black TOKENHASH(23268100)
-#define CTX_cyan TOKENHASH(921158)
-#define CTX_navy TOKENHASH(1683548)
-#define CTX_lime TOKENHASH(354904)
-#define CTX_aqua TOKENHASH(109634)
-#define CTX_transparent TOKENHASH(3143361910)
-#define CTX_currentColor TOKENHASH(2944012414)
-#define CTX_title TOKENHASH(11313768)
-
+#define CTX_action 971612354u
+#define CTX_addStop 3805374936u
+#define CTX_alphabetic 2558771929u
+#define CTX_aqua 109634u
+#define CTX_arc 7298u
+#define CTX_arcTo 4138935887u
+#define CTX_beginPath 2384638508u
+#define CTX_bevel 25538884u
+#define CTX_black 23268100u
+#define CTX_blend 9317124u
+#define CTX_blending 3402343403u
+#define CTX_blendMode 3450578624u
+#define CTX_blue 371460u
+#define CTX_bottom 905225156u
+#define CTX_cap 32838u
+#define CTX_center 1219785030u
+#define CTX_clear 37825286u
+#define CTX_clip 1067782u
+#define CTX_closePath 3625577848u
+#define CTX_cmyk 772934u
+#define CTX_cmyka 2870086u
+#define CTX_cmykaS 3116500921u
+#define CTX_cmykS 934005574u
+#define CTX_cmykSpace 2661208064u
+#define CTX_color 38757318u
+#define CTX_colorSpace 2624117287u
+#define CTX_compositingMode 3625102151u
+#define CTX_copy 1672134u
+#define CTX_currentColor 2944012414u
+#define CTX_curveTo 3536162037u
+#define CTX_cyan 921158u
+#define CTX_darken 950767688u
+#define CTX_defineFont 2930064664u
+#define CTX_defineGlyph 3698027829u
+#define CTX_defineTexture 4201008335u
+#define CTX_destinationAtop 3609906960u
+#define CTX_destinationIn 2718725020u
+#define CTX_destinationOut 3944490553u
+#define CTX_destinationOver 2378926016u
+#define CTX_deviceCMYK 4096729420u
+#define CTX_deviceRGB 3975717407u
+#define CTX_difference 2530251746u
+#define CTX_done 357320u
+#define CTX_drgb 146568u
+#define CTX_drgba 2243720u
+#define CTX_drgbaS 2541895879u
+#define CTX_drgbS 933379208u
+#define CTX_drgbSpace 3152489160u
+#define CTX_end 9098u
+#define CTX_endFrame 3482141353u
+#define CTX_endGroup 3639210663u
+#define CTX_evenOdd 4065502508u
+#define CTX_exit 1330698u
+#define CTX_extend 298165770u
+#define CTX_fill 811596u
+#define CTX_fillRect 2617922007u
+#define CTX_fillRule 2727819936u
+#define CTX_font 1340364u
+#define CTX_fontSize 2516141542u
+#define CTX_fuchsia 3356500405u
+#define CTX_globalAlpha 3503999095u
+#define CTX_glyph 17877774u
+#define CTX_gradientAddStop 2707733066u
+#define CTX_gray 1641614u
+#define CTX_graya 3738766u
+#define CTX_grayaS 3152913809u
+#define CTX_grayS 934874254u
+#define CTX_green 29699214u
+#define CTX_hanging 3379012612u
+#define CTX_height 1359432016u
+#define CTX_horLineTo 2768557894u
+#define CTX_hue 11600u
+#define CTX_identity 4244560551u
+#define CTX_ideographic 4062138887u
+#define CTX_imageSmoothing 3391439578u
+#define CTX_join 936916u
+#define CTX_kerningPair 3655936472u
+#define CTX_lab 4184u
+#define CTX_laba 69720u
+#define CTX_labaS 933302360u
+#define CTX_labS 29167704u
+#define CTX_lch 16600u
+#define CTX_lcha 82136u
+#define CTX_lchaS 933314776u
+#define CTX_lchS 29180120u
+#define CTX_left 1323352u
+#define CTX_lighten 2243427702u
+#define CTX_lime 354904u
+#define CTX_linearGradient 2530643087u
+#define CTX_lineCap 4099906770u
+#define CTX_lineDash 2275747153u
+#define CTX_lineDashOffset 2164798257u
+#define CTX_lineHeight 2180215986u
+#define CTX_lineJoin 3149521206u
+#define CTX_lineTo 3995194545u
+#define CTX_lineWidth 4067116285u
+#define CTX_lower 38124504u
+#define CTX_lower 38124504u
+#define CTX_lowerBottom 4236857599u
+#define CTX_magenta 2383173845u
+#define CTX_maroon 972001370u
+#define CTX_maximize 4029307923u
+#define CTX_middle 360981082u
+#define CTX_miter 38117978u
+#define CTX_miterLimit 3784823268u
+#define CTX_moveTo 3135948887u
+#define CTX_multiply 2379318058u
+#define CTX_navy 1683548u
+#define CTX_newPage 3875814849u
+#define CTX_newPath 2442450175u
+#define CTX_newState 3540663677u
+#define CTX_none 357340u
+#define CTX_nonzero 2230085415u
+#define CTX_normal 808293340u
+#define CTX_olive 11946782u
+#define CTX_paint 42879072u
+#define CTX_purple 361796960u
+#define CTX_quadTo 3916306495u
+#define CTX_radialGradient 3218566169u
+#define CTX_raise 11749476u
+#define CTX_raise 11749476u
+#define CTX_raiseTop 3277017940u
+#define CTX_rect 1317220u
+#define CTX_rectangle 4111149391u
+#define CTX_red 8548u
+#define CTX_relArcTo 2940381656u
+#define CTX_relCurveTo 3745640049u
+#define CTX_relHorLineTo 2661057467u
+#define CTX_relLineTo 2437091951u
+#define CTX_relMoveTo 2527491593u
+#define CTX_relQuadTo 3961311908u
+#define CTX_relSmoothqTo 2913202089u
+#define CTX_relSmoothTo 3458671695u
+#define CTX_relVerLineTo 3868849192u
+#define CTX_restore 2936409475u
+#define CTX_rgb 4580u
+#define CTX_rgba 70116u
+#define CTX_rgbaS 933302756u
+#define CTX_rgbS 29168100u
+#define CTX_rgbSpace 3275074815u
+#define CTX_right 42482276u
+#define CTX_rotate 377594852u
+#define CTX_round 9350116u
+#define CTX_roundRectangle 3688082153u
+#define CTX_save 372838u
+#define CTX_scale 11274470u
+#define CTX_screen 950374630u
+#define CTX_setFontSize 2794810212u
+#define CTX_setLineCap 3062640202u
+#define CTX_setLineJoin 3876390174u
+#define CTX_setLineWidth 3835759450u
+#define CTX_shadowBlur 3119062524u
+#define CTX_shadowColor 3795289804u
+#define CTX_shadowOffsetX 4134163333u
+#define CTX_shadowOffsetY 3519010566u
+#define CTX_silver 1219912294u
+#define CTX_smoothQuadTo 4024936051u
+#define CTX_smoothTo 3997790061u
+#define CTX_sourceAtop 3201391080u
+#define CTX_sourceIn 3513756343u
+#define CTX_sourceOut 4217691207u
+#define CTX_sourceOver 4071274055u
+#define CTX_sourceTransform 3608891648u
+#define CTX_square 373402726u
+#define CTX_start 43126054u
+#define CTX_startFrame 4232434924u
+#define CTX_startGroup 4199711715u
+#define CTX_stroke 359634214u
+#define CTX_strokeRect 3918462693u
+#define CTX_strokeSource 3387288669u
+#define CTX_strokeText 4077103477u
+#define CTX_teal 788840u
+#define CTX_terminate 2614989576u
+#define CTX_text 1360232u
+#define CTX_textAlign 4087119491u
+#define CTX_textBaseline 3671121506u
+#define CTX_textDirection 2303324726u
+#define CTX_texture 2603404275u
+#define CTX_title 11313768u
+#define CTX_top 33768u
+#define CTX_transform 3717307466u
+#define CTX_translate 2746303805u
+#define CTX_transparent 3143361910u
+#define CTX_unmaximize 3478656422u
+#define CTX_userCMYK 4240023559u
+#define CTX_userRGB 2839509677u
+#define CTX_verLineTo 2881865279u
+#define CTX_viewBox 3661895848u
+#define CTX_white 11815470u
+#define CTX_width 18096750u
+#define CTX_winding 3743938776u
+#define CTX_wrapLeft 2742686349u
+#define CTX_wrapRight 2519274407u
+#define CTX_x 48u
+#define CTX_xor 37872u
+#define CTX_y 50u
+#define CTX_yellow 1575772530u
 #endif
-
-
-
 #ifndef __CTX_LIBC_H
 #define __CTX_LIBC_H
 
@@ -6142,6 +6289,7 @@ static inline int ctx_strncmp (const char *a, const char *b, size_t n)
   for (i = 0; a[i] && b[i] && i < n; a++, b++)
     if (a[0] != b[0])
       { return 1; }
+  if (i >=n) return 1;
   return 0;
 }
 
@@ -6157,11 +6305,8 @@ static inline char *ctx_strstr (const char *h, const char *n)
   int needle_len = ctx_strlen (n);
   if (n[0]==0)
     { return (char *) h; }
-  while (h)
+  while (*h)
     {
-      h = ctx_strchr (h, n[0]);
-      if (!h)
-        { return NULL; }
       if (!ctx_strncmp (h, n, needle_len) )
         { return (char *) h; }
       h++;
@@ -6169,6 +6314,15 @@ static inline char *ctx_strstr (const char *h, const char *n)
   return NULL;
 }
 
+static inline char *ctx_strdup (const char *str)
+{
+  int len = ctx_strlen (str);
+  char *ret = (char*)ctx_malloc (len + 1);
+  memcpy (ret, str, len);
+  ret[len]=0;
+  return ret;
+}
+
 #endif
 
 uint32_t    ctx_strhash        (const char *str);
@@ -6186,10 +6340,10 @@ Ctx        *ctx_new_for_buffer (CtxBuffer *buffer);
 /* This enum should be kept in sync with the corresponding mmm enum.
  */
 typedef enum {
-  CTX_f32,
-  CTX_f32S,
-  CTX_s16,
-  CTX_s16S
+  CTX_F32,
+  CTX_F32S,
+  CTX_S16,
+  CTX_S16S
 } CtxPCM;
 
 void   ctx_pcm_set_format        (Ctx *ctx, CtxPCM format);
@@ -6202,28 +6356,12 @@ float  ctx_pcm_get_queued_length (Ctx *ctx);
 int    ctx_pcm_queue             (Ctx *ctx, const int8_t *data, int frames);
 
 #endif
+
+#if CTX_IMPLEMENTATION || CTX_SIMD_BUILD
 #ifndef __CTX_CLIENTS_H
 #define __CTX_CLIENTS_H
 
-typedef enum CtxClientFlags {
-  ITK_CLIENT_UI_RESIZABLE = 1<<0,
-  ITK_CLIENT_CAN_LAUNCH   = 1<<1,
-  ITK_CLIENT_MAXIMIZED    = 1<<2,
-  ITK_CLIENT_ICONIFIED    = 1<<3,
-  ITK_CLIENT_SHADED       = 1<<4,
-  ITK_CLIENT_TITLEBAR     = 1<<5,
-  ITK_CLIENT_LAYER2       = 1<<6,  // used for having a second set
-                                   // to draw - useful for splitting
-                                   // scrolled and HUD items
-                                   // with HUD being LAYER2
-                                  
-  ITK_CLIENT_KEEP_ALIVE   = 1<<7,  // do not automatically
-  ITK_CLIENT_FINISHED     = 1<<8,  // do not automatically
-                                   // remove after process quits
-  ITK_CLIENT_PRELOAD      = 1<<9
-} CtxClientFlags;
 
-typedef void (*CtxClientFinalize)(CtxClient *client, void *user_data);
 
 struct _CtxClient {
   VT    *vt;        // or NULL when thread
@@ -6275,84 +6413,10 @@ struct _CtxClient {
 #endif
 };
 
-int   ctx_client_resize        (Ctx *ctx, int id, int width, int height);
-void  ctx_client_set_font_size (Ctx *ctx, int id, float font_size);
-float ctx_client_get_font_size (Ctx *ctx, int id);
-void  ctx_client_maximize      (Ctx *ctx, int id);
-
-
-CtxClient *vt_get_client (VT *vt);
-CtxClient *ctx_client_new (Ctx *ctx,
-                           const char *commandline,
-                           int x, int y, int width, int height,
-                           float font_size,
-                           CtxClientFlags flags,
-                           void *user_data,
-                           CtxClientFinalize client_finalize);
-
-CtxClient *ctx_client_new_argv (Ctx *ctx, char **argv, int x, int y, int width, int height, float font_size, 
CtxClientFlags flags, void *user_data,
-                CtxClientFinalize client_finalize);
-int ctx_clients_need_redraw (Ctx *ctx);
-
-CtxClient *ctx_client_new_thread (Ctx *ctx, void (*start_routine)(Ctx *ctx, void *user_data),
-                                  int x, int y, int width, int height, float font_size, CtxClientFlags 
flags, void *user_data, CtxClientFinalize finalize);
-
-extern float ctx_shape_cache_rate;
-extern int _ctx_max_threads;
-
-CtxEvent *ctx_event_copy (CtxEvent *event);
-
-void  ctx_client_move         (Ctx *ctx, int id, int x, int y);
-void  ctx_client_shade_toggle (Ctx *ctx, int id);
-float ctx_client_min_y_pos    (Ctx *ctx);
-float ctx_client_max_y_pos    (Ctx *ctx);
-void ctx_client_paste (Ctx *ctx, int id, const char *str);
-char  *ctx_client_get_selection        (Ctx *ctx, int id);
-
-void  ctx_client_rev_inc      (CtxClient *client);
-long  ctx_client_rev          (CtxClient *client);
-
-int   ctx_clients_active      (Ctx *ctx);
-
-CtxClient *ctx_client_by_id (Ctx *ctx, int id);
-
-int ctx_clients_draw (Ctx *ctx, int layer2);
-
-void ctx_client_feed_keystring (CtxClient *client, CtxEvent *event, const char *str);
-// need not be public?
-void ctx_client_register_events (CtxClient *client, Ctx *ctx, double x0, double y0);
-
-void ctx_client_remove (Ctx *ctx, CtxClient *client);
-
-int  ctx_client_height           (Ctx *ctx, int id);
-int  ctx_client_x                (Ctx *ctx, int id);
-int  ctx_client_y                (Ctx *ctx, int id);
-void ctx_client_raise_top        (Ctx *ctx, int id);
-void ctx_client_lower_bottom     (Ctx *ctx, int id);
-void ctx_client_iconify          (Ctx *ctx, int id);
-int  ctx_client_is_iconified     (Ctx *ctx, int id);
-void ctx_client_uniconify        (Ctx *ctx, int id);
-void ctx_client_maximize         (Ctx *ctx, int id);
-int  ctx_client_is_maximized     (Ctx *ctx, int id);
-void ctx_client_unmaximize       (Ctx *ctx, int id);
-void ctx_client_maximized_toggle (Ctx *ctx, int id);
-void ctx_client_shade            (Ctx *ctx, int id);
-int  ctx_client_is_shaded        (Ctx *ctx, int id);
-void ctx_client_unshade          (Ctx *ctx, int id);
-void ctx_client_toggle_maximized (Ctx *ctx, int id);
-void ctx_client_shade_toggle     (Ctx *ctx, int id);
-void ctx_client_move             (Ctx *ctx, int id, int x, int y);
-int  ctx_client_resize           (Ctx *ctx, int id, int width, int height);
-void ctx_client_set_opacity      (Ctx *ctx, int id, float opacity);
-float ctx_client_get_opacity     (Ctx *ctx, int id);
-void ctx_client_set_title        (Ctx *ctx, int id, const char *title);
-const char *ctx_client_get_title (Ctx *ctx, int id);
 
 
 #endif
 
-#if CTX_IMPLEMENTATION || CTX_SIMD_BUILD
-
 #if CTX_IMPLEMENTATION|CTX_COMPOSITE
 
 #ifndef __CTX_INTERNAL_H
@@ -6376,11 +6440,22 @@ const char *ctx_client_get_title (Ctx *ctx, int id);
 
 typedef struct _CtxRasterizer CtxRasterizer;
 typedef struct _CtxGState     CtxGState;
-typedef struct _CtxState      CtxState;
+//typedef struct _CtxState      CtxState;
 
 typedef struct _CtxSource CtxSource;
 
 
+enum _CtxAntialias
+{
+  CTX_ANTIALIAS_DEFAULT, //
+  CTX_ANTIALIAS_NONE, // non-antialiased
+  CTX_ANTIALIAS_FAST, // aa 3    // deprected or is default equal to this now?
+  CTX_ANTIALIAS_GOOD, // aa 5    // this should perhaps still be 5?
+};
+typedef enum _CtxAntialias CtxAntialias;
+void         ctx_set_antialias (Ctx *ctx, CtxAntialias antialias);
+CtxAntialias ctx_get_antialias (Ctx *ctx);
+
 #define CTX_VALID_RGBA_U8     (1<<0)
 #define CTX_VALID_RGBA_DEVICE (1<<1)
 #if CTX_ENABLE_CM
@@ -6489,10 +6564,11 @@ struct _CtxBuffer
 //void _ctx_user_to_device          (CtxState *state, float *x, float *y);
 //void _ctx_user_to_device_distance (CtxState *state, float *x, float *y);
 
+
 typedef struct _CtxGradient CtxGradient;
 struct _CtxGradient
 {
-  CtxGradientStop stops[16];
+  CtxGradientStop stops[CTX_MAX_GRADIENT_STOPS];
   int n_stops;
 };
 
@@ -6501,8 +6577,7 @@ struct _CtxSource
   int type;
   CtxMatrix  set_transform;
   CtxMatrix  transform;
-  CtxMatrix  transform_inv;
-  int pad; // to align next properly
+  uint32_t   pad;
   union
   {
     CtxColor color;
@@ -6538,12 +6613,32 @@ struct _CtxSource
   };
 };
 
+
+typedef struct _Ctx16f16Matrix     Ctx16f16Matrix;
+struct
+  _Ctx16f16Matrix
+{
+#if CTX_32BIT_SEGMENTS
+  int64_t m[3][3];  // forcing higher precision easily, the extra
+                    // memory cost is minuscle
+#else
+  int32_t m[3][3];
+#endif
+};
+
+
 struct _CtxGState
 {
-  int           keydb_pos;
-  int           stringpool_pos;
+#if CTX_32BIT_SEGMENTS
+  uint32_t      keydb_pos;
+  uint32_t      stringpool_pos;
+#else
+  uint16_t      keydb_pos;      // this limits these
+  uint16_t      stringpool_pos; // 
+#endif
 
   CtxMatrix     transform;
+  Ctx16f16Matrix  prepped_transform;
   CtxSource     source_stroke;
   CtxSource     source_fill;
   float         global_alpha_f;
@@ -6557,6 +6652,7 @@ struct _CtxGState
   float         shadow_offset_x;
   float         shadow_offset_y;
 #endif
+  unsigned int  transform_type:3;
   unsigned int        clipped:1;
   CtxColorModel    color_model:8;
   /* bitfield-pack small state-parts */
@@ -6600,8 +6696,11 @@ struct _CtxGState
   CtxBlend                  blend_mode; // non-vectorization
   CtxExtend                 extend;
 
-  float dashes[CTX_PARSER_MAX_ARGS];
-
+  float dashes[CTX_MAX_DASHES]; // XXX moving dashes 
+                                //  to state storage,. will
+                                //  allow it to be larger,
+                                //  free up memory, and
+                                //  make save/restore faster
 };
 
 typedef enum
@@ -6629,9 +6728,6 @@ struct _CtxDrawlist
   int       bitpack_pos;  // stream is bitpacked up to this offset
 };
 
-#define CTX_MAX_KEYDB 64 // number of entries in keydb
-                         // entries are "copy-on-change" between states
-
 // the keydb consists of keys set to floating point values,
 // that might also be interpreted as integers for enums.
 //
@@ -6648,7 +6744,6 @@ struct _CtxState
 {
   int           has_moved:1;
   int           has_clipped:1;
-  int16_t       gstate_no;
   int8_t        source; // used for the single-shifting to stroking
                 // 0  = fill
                 // 1  = start_stroke
@@ -6656,6 +6751,7 @@ struct _CtxState
                 //
                 //   if we're at in_stroke at start of a source definition
                 //   we do filling
+  int16_t       gstate_no;
 
   float         x;
   float         y;
@@ -6693,39 +6789,47 @@ struct _CtxFontEngine
   float (*glyph_kern)  (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unicharB);
 };
 
+
+#pragma pack(push,1)
 struct _CtxFont
 {
+#if CTX_ONE_FONT_ENGINE==0
   CtxFontEngine *engine;
-  const char *name;
-  int type; // 0 ctx    1 stb    2 monobitmap
+#endif
   union
   {
     struct
     {
       CtxEntry *data;
-      int length;
+    //uint16_t length;
       /* we've got ~110 bytes to fill to cover as
          much data as stbtt_fontinfo */
       //int16_t glyph_pos[26]; // for a..z
-      int       glyphs; // number of glyphs
-      uint32_t *index;
     } ctx;
+#if CTX_FONT_ENGINE_CTX_FS
     struct
     {
+      const char *name;
       char *path;
     } ctx_fs;
+#endif
 #if CTX_FONT_ENGINE_STB
     struct
     {
+      const char *name;
       stbtt_fontinfo ttf_info;
-      int cache_index;
-      uint32_t cache_unichar;
     } stb;
 #endif
+#if 0
     struct { int start; int end; int gw; int gh; const uint8_t *data;} monobitmap;
+#endif
   };
+#if CTX_ONE_FONT_ENGINE==0
+  uint8_t type:3; // 0 ctx    1 stb    2 monobitmap
+  uint8_t monospaced:1;
+#endif
 };
-
+#pragma pack(pop)
 
 enum _CtxIteratorFlag
 {
@@ -6736,8 +6840,7 @@ enum _CtxIteratorFlag
 typedef enum _CtxIteratorFlag CtxIteratorFlag;
 
 
-struct
-  _CtxIterator
+struct _CtxIterator
 {
   int              pos;
   int              first_run;
@@ -6750,8 +6853,6 @@ struct
   CtxEntry         bitpack_command[6]; // the command returned to the
   // user if unpacking is needed.
 };
-#define CTX_MAX_DEVICES 16
-#define CTX_MAX_KEYBINDINGS         256
 
 #if CTX_EVENTS 
 
@@ -6770,7 +6871,6 @@ typedef struct CtxItemCb {
 } CtxItemCb;
 
 
-#define CTX_MAX_CBS              128
 
 typedef struct CtxItem {
   CtxMatrix inv_matrix;  /* for event coordinate transforms */
@@ -6802,10 +6902,6 @@ struct _CtxEvents
   CtxList        *grabs; /* could split the grabs per device in the same way,
                             to make dispatch overhead smaller,. probably
                             not much to win though. */
-  CtxItem         *prev[CTX_MAX_DEVICES];
-  float            pointer_x[CTX_MAX_DEVICES];
-  float            pointer_y[CTX_MAX_DEVICES];
-  unsigned char    pointer_down[CTX_MAX_DEVICES];
   CtxEvent         drag_event[CTX_MAX_DEVICES];
   CtxList         *idles;
   CtxList         *idles_to_remove;
@@ -6813,13 +6909,17 @@ struct _CtxEvents
   CtxList         *events; // for ctx_get_event
   CtxBinding       bindings[CTX_MAX_KEYBINDINGS]; /*< better as list, uses no mem if unused */
   int              n_bindings;
-  int              in_idle_dispatch;
-  int              ctx_get_event_enabled;
+  CtxItem         *prev[CTX_MAX_DEVICES];
+  float            pointer_x[CTX_MAX_DEVICES];
+  float            pointer_y[CTX_MAX_DEVICES];
+  unsigned char    pointer_down[CTX_MAX_DEVICES];
+  unsigned int     in_idle_dispatch:1;
+  unsigned int     ctx_get_event_enabled:1;
+  CtxModifierState modifier_state;
   int              idle_id;
   CtxList         *items;
   CtxItem         *last_item;
-  CtxModifierState modifier_state;
-  double           tap_hysteresis;
+  float            tap_hysteresis;
 #if CTX_CLIENTS
   CtxList         *clients;
   CtxClient *active;
@@ -6829,8 +6929,6 @@ struct _CtxEvents
   int              tap_delay_max;
   int              tap_delay_hold;
 };
-
-
 #endif
 
 typedef struct _CtxEidInfo
@@ -6841,6 +6939,15 @@ typedef struct _CtxEidInfo
   int   height;
 } CtxEidInfo;
 
+
+struct _CtxGlyphEntry
+{
+  uint32_t  unichar;
+  uint16_t  offset;
+  CtxFont  *font;
+};
+typedef struct _CtxGlyphEntry CtxGlyphEntry;
+
 struct _Ctx
 {
   CtxBackend       *backend;
@@ -6848,12 +6955,14 @@ struct _Ctx
   int               transformation;
   int               width;
   int               height;
+  int               dirty;
   Ctx              *texture_cache;
   CtxList          *eid_db;
   CtxState          state;        /**/
   int               frame; /* used for texture lifetime */
+  uint32_t          bail;
+  CtxBackend       *backend_pushed;
   CtxBuffer         texture[CTX_MAX_TEXTURES];
-  int               dirty;
 #if CTX_EVENTS 
   CtxCursor         cursor;
   int               quit;
@@ -6866,8 +6975,14 @@ struct _Ctx
   CtxDrawlist       current_path; // possibly transformed coordinates !
   CtxIterator       current_path_iterator;
 #endif
+#if CTX_GLYPH_CACHE
+  CtxGlyphEntry     glyph_index_cache[CTX_GLYPH_CACHE_SIZE];
+#endif
+  CtxFont *fonts; // a copy to keep it alive with mp's
+                  // garbage collector, the fonts themselves
+                  // are static and shared beyond ctx contexts
+ 
 
-  uint32_t          bail;
 };
 
 static inline void
@@ -6878,7 +6993,7 @@ ctx_process (Ctx *ctx, CtxEntry *entry)
 
 CtxBuffer *ctx_buffer_new (int width, int height,
                            CtxPixelFormat pixel_format);
-void ctx_buffer_free (CtxBuffer *buffer);
+void ctx_buffer_destroy (CtxBuffer *buffer);
 
 void
 ctx_state_gradient_clear_stops (CtxState *state);
@@ -7007,8 +7122,8 @@ typedef enum {
    CTX_COV_PATH_RGBA8_OVER_FRAGMENT,
    CTX_COV_PATH_GRAYA8_COPY,
    CTX_COV_PATH_GRAY1_COPY,
-
-
+   CTX_COV_PATH_GRAY2_COPY,
+   CTX_COV_PATH_GRAY4_COPY,
    CTX_COV_PATH_RGB565_COPY,
    CTX_COV_PATH_RGB332_COPY,
    CTX_COV_PATH_GRAY8_COPY,
@@ -7017,11 +7132,8 @@ typedef enum {
    CTX_COV_PATH_CMYK8_COPY,
    CTX_COV_PATH_CMYKA8_COPY,
    CTX_COV_PATH_CMYKAF_COPY,
-   CTX_COV_PATH_GRAYAF_COPY 
-
-
-
-
+   CTX_COV_PATH_GRAYAF_COPY,
+   CTX_COV_PATH_CBRLE_COPY 
 } CtxCovPath;
 
 struct _CtxRasterizer
@@ -7045,7 +7157,6 @@ struct _CtxRasterizer
   void       (*apply_coverage) (CtxRasterizer *r, uint8_t * __restrict__ dst, uint8_t * __restrict__ src, 
int x, uint8_t *coverage, unsigned int count);
 
   unsigned int aa;          // level of vertical aa
-  int        uses_transforms;
   unsigned int prev_active_edges;
   unsigned int active_edges;
   unsigned int pending_edges;
@@ -7126,7 +7237,7 @@ struct _CtxRasterizer
 #endif
 
 #if static_OPAQUE
-  uint8_t opaque[4096];
+  uint8_t opaque[CTX_MAX_SCANLINE_LENGTH];
 #endif
 
 #if CTX_SHAPE_CACHE
@@ -7146,31 +7257,34 @@ struct _CtxMurmur {
 };
 
 
+#pragma pack(push,1)
 typedef struct CtxCommandState
 {
-  uint32_t pos;
+  uint16_t pos;
   uint32_t active;
 } CtxCommandState;
+#pragma pack(pop)
 
 struct _CtxHasher
 {
   CtxRasterizer rasterizer;
   int           cols;
   int           rows;
-  uint32_t     *hashes;
+  uint32_t      hashes[CTX_HASH_COLS*CTX_HASH_ROWS];
   CtxMurmur     murmur_fill[CTX_MAX_STATES]; 
   CtxMurmur     murmur_stroke[CTX_MAX_STATES];
   int           source_level;
   int           pos; 
-  //CtxList *active_info;
 
-  CtxCommandState *active_info;
-  int              active_info_size;
-  int              active_info_count;
+  int           prev_command;
+
+  CtxDrawlist  *drawlist;
+
 };
 
 #if CTX_RASTERIZER
 void ctx_rasterizer_deinit (CtxRasterizer *rasterizer);
+void ctx_rasterizer_destroy (CtxRasterizer *rasterizer);
 #endif
 
 enum {
@@ -7192,6 +7306,8 @@ typedef struct _CtxCtx CtxCtx;
 struct _CtxCtx
 {
    CtxBackend backend;
+   int  width;
+   int  height;
    int  cols;
    int  rows;
    int  was_down;
@@ -7300,7 +7416,6 @@ ctx_rasterizer_rel_curve_to (CtxRasterizer *rasterizer,
 
 static void
 ctx_rasterizer_reset (CtxRasterizer *rasterizer);
-static uint32_t ctx_rasterizer_poly_to_hash (CtxRasterizer *rasterizer);
 static void
 ctx_rasterizer_arc (CtxRasterizer *rasterizer,
                     float        x,
@@ -7581,10 +7696,6 @@ struct _CtxTiled
    int       min_row;
    int       max_col;
    int       max_row;
-  // CtxList  *active_info;
-   CtxCommandState *active_info;
-  // int              active_info_size;
-   int              active_info_count;
    uint32_t  hashes[CTX_HASH_ROWS * CTX_HASH_COLS];
    int8_t    tile_affinity[CTX_HASH_ROWS * CTX_HASH_COLS]; // which render thread no is
                                                            // responsible for a tile
@@ -7620,28 +7731,20 @@ int ctx_is_set (Ctx *ctx, uint32_t hash);
 
 static Ctx *_ctx_new_drawlist (int width, int height);
 
-/**
- * ctx_new_ui:
- *
- * Create a new interactive ctx context, might depend on additional
- * integration.
- *
- * The values for backend are as for the environment variable,
- * NULL for auto.
- */
-static Ctx *ctx_new_ui (int width, int height, const char *backend);
 
 static inline void
 _ctx_matrix_apply_transform (const CtxMatrix *m, float *x, float *y)
 {
   float x_in = *x;
   float y_in = *y;
-
   float w =   (x_in * m->m[2][0]) + (y_in * m->m[2][1]) + m->m[2][2];
-       *x = ( (x_in * m->m[0][0]) + (y_in * m->m[0][1]) + m->m[0][2]) / w;
-       *y = ( (x_in * m->m[1][0]) + (y_in * m->m[1][1]) + m->m[1][2]) / w;
+  float w_recip = 1.0f/w;
+       *x = ( (x_in * m->m[0][0]) + (y_in * m->m[0][1]) + m->m[0][2]) * w_recip;
+       *y = ( (x_in * m->m[1][0]) + (y_in * m->m[1][1]) + m->m[1][2]) * w_recip;
 }
 
+
+
 static inline void
 _ctx_matrix_multiply (CtxMatrix       *result,
                       const CtxMatrix *t,
@@ -7678,27 +7781,1127 @@ _ctx_matrix_identity (CtxMatrix *matrix)
   matrix->m[2][2] = 1.0f;
 }
 
+static inline void
+_ctx_user_to_device_prepped (CtxState *state, float x, float y, int *out_x, int *out_y);
+static inline void
+_ctx_user_to_device_prepped_fixed (CtxState *state, int x, int y, int *x_out, int *y_out);
 
 static int ctx_float_to_string_index (float val);
 
 void
-ctx_render_ctx_masked (Ctx *ctx, Ctx *d_ctx, CtxCommandState *active_list, int count, uint32_t mask);
-
-CtxCommandState *ctx_hasher_get_active_info (Ctx *ctx, int *count);
+ctx_render_ctx_masked (Ctx *ctx, Ctx *d_ctx, uint32_t mask);
 
 static void ctx_state_set_blob (CtxState *state, uint32_t key, uint8_t *data, int len);
 
+
+static inline void
+_ctx_transform_prime (CtxState *state);
+
+void ctx_push_backend (Ctx *ctx,
+                       void *backend);
+void ctx_pop_backend (Ctx *ctx);
+
+
+static inline float ctx_fmod1f (float val)
+{
+  return ctx_fabsf (val - (int)(val));
+}
+
+static inline float ctx_fmodf (float val, float modulus)
+{
+  return ctx_fmod1f(val/modulus) * modulus;
+}
+
 #if EMSCRIPTEN
 #define CTX_EXPORT EMSCRIPTEN_KEEPALIVE
 #else
 #define CTX_EXPORT
 #endif
 
+
+
 #endif
 
 #if CTX_EVENTS
 #include <sys/select.h>
 #endif
+/*
+ * each scanline is encoded as a header + rle data + free space + reversed palette
+ * 
+ * header:  u16_length, u8_colors, u8_0
+ *
+ * The u8_0 padding byte needs to be 0 in the future it might hold higher values, but
+ * always smaller than colors, this to make it use a value that never naturally occurs
+ * for u8 associated alpha, making it possible to store either CBRLE or raw pixel
+ * values in 32bpp scanlines.
+ * 
+ * The indexed palette is per-scanline, the first eight palette entries are
+ * fixed as a grayscale. The palette is allocated on the fly and is stored from
+ * the end of the scanline. As the palette fills up it gets harder and harder
+ * for new colors to warrant a allocating new entries, gradients only allocate
+ * colors for their start and end colors.
+ *
+ * When we run out of free space the scanline gets recompressed, reducing color
+ * depth and simplifying pixel data, for 32bpp scanlines this can in the future
+ * mean fall over to uncompressed raw data. Doing composiing on RLE encoded
+ * data can on high resolution framebuffers lead to significantly lower memory
+ * bandwidth and computation required on frames with significant overdraw; to
+ * fully realise this potential further integration is needed.
+ *
+ */
+
+
+
+#if CTX_IMPLEMENTATION || CTX_SIMD_BUILD
+#if CTX_ENABLE_CBRLE
+
+
+#define CBRLE_GRADIENT  1
+#define ALLOW_MERGE     1
+
+#define PAL_GRAY_PREDEF 0
+
+#define GRADIENT_THRESHOLD     1
+#define COLOR_THRESHOLD_START  6
+#define COLOR_THRESHOLD_END    (color_budget<=128?32:21)
+
+#define MAX_GRADIENT_LENGTH    (color_budget<=128?63:63)
+
+// with high numbers, repeated recompressions steal a *lot* of time
+// when data is overflowing
+//
+#define MAX_RECOMPRESS         2
+
+// increase to have larger safety margin between pixeldata
+// and palette
+#define BORDER                 1
+
+
+//  -- currently unused
+#define MERGE_THRESHOLD        64   //(no<2?50:98)
+#define MERGE_CHANCE           42   //(no<2?25:80)
+
+#define PAL_GRAY_OFFSET      (PAL_GRAY_PREDEF * 8)
+
+enum {
+        CBRLE_MODE_SET=0,
+        CBRLE_MODE_OVER=1,
+        CBRLE_MODE_COPY=2,
+        CBRLE_MODE_SET_COLOR=3
+};
+
+
+///  max 32 or 64 colors per scanline
+//      
+//     1  5 2
+//     1  7    8
+//     1         4  4  4 1 1 1  - the last 3bits are lengths 0 means 1 and 1 means 2 for 2 first
+static inline int encode_pix (uint8_t *cbrle, int pos, 
+                              uint8_t idx, int range, int gradient,
+                              int allow_merge)
+{
+#if ALLOW_MERGE
+   if (allow_merge && pos > 3)
+   {
+      if (cbrle[pos-1]        < 128 &&  //
+          cbrle[pos-2]        < 128 &&  // previous must be single
+          (cbrle[pos-1] >> 4) == 0 && idx <4 && range == 1 &&
+          (cbrle[pos-1]&15) <4)
+      {
+         int previdx = cbrle[pos-1]&15;
+         cbrle[pos-1] = (8-1) * 16 + (idx << 2) + previdx;
+         return 0;
+      }
+   }
+#endif
+
+   if (range > 64)
+     fprintf (stderr, "ERROR trying to encode too big range %i!\n", range);
+   if (idx <= 15 && range < 8 && !gradient)
+   {
+     cbrle[pos] = (range-1) * 16 + idx;
+     return 1;
+   }
+   else
+   {
+     cbrle[pos] = (range) + 128 + gradient * 64;
+     cbrle[pos+1] = idx;
+     return 2;
+   }
+}
+
+
+// pix: pointer to data to decode
+// ret_col: where to store 8bit color index
+// length_px: number of pixels wide
+// gradient: set to 1 if it is a gradient
+//
+// returns number of bytes in encoded form.
+static inline int decode_pix (const uint8_t *pix,
+                              uint8_t       *ret_col1,
+                              uint8_t       *ret_col2,
+                              int           *length_px,
+                              int           *gradient)
+{
+  int encoded_length = 1;
+  int len = 1;
+  int col = 0;
+  int col2 = 0;
+  if (gradient)
+    *gradient = 0;
+  if ((*pix & 0x80) == 0)
+  {
+    len = pix[0] >> 4;
+    len++;
+    if (len == 8)
+    {
+      len = 2;
+      col = pix[0] & 15;
+      col2 = col >> 2;
+      col = col & 3;
+      if (ret_col2)
+        *ret_col2 = col2;
+    }
+    else
+    {
+      col = ( pix[0] & 15);
+      if (ret_col2)
+        *ret_col2 = col;
+    }
+  }
+  else
+  {
+    len = pix[0]-128;
+    if (len > 64)
+    {
+      len -= 64;
+      if(gradient)
+        *gradient = 1;
+    }
+    col = pix[1];
+    encoded_length = 2;
+    if (ret_col2)
+      *ret_col2 = col;
+  }
+  if (length_px)
+    *length_px = len;
+  if (ret_col1)
+    *ret_col1 = col;
+  return encoded_length;
+}
+
+
+static inline int decode_pix_len (const uint8_t *pix, int *length_px)
+{
+  return decode_pix (pix, NULL, NULL, length_px, NULL);
+}
+
+
+static inline uint32_t color_diff (uint32_t a, uint32_t b)
+{
+  uint32_t sum_dist = 0;
+  for (int c = 0; c < 4; c++)
+  {
+    sum_dist += ((a&0xff)-(b&0xff))*((a&0xff)-(b&0xff));
+    a>>=8;
+    b>>=8;
+  }
+  return sum_dist;
+}
+
+static inline int is_b_good_middle (uint32_t a, uint32_t b, uint32_t c, int color_budget)
+{
+  uint32_t lerped = ctx_lerp_RGBA8 (a, c, 127);
+
+  if (a == c) return 0; // gradients are more expensive than not
+  uint32_t sum_dist = color_diff (lerped, b);
+  return (sum_dist < (GRADIENT_THRESHOLD*GRADIENT_THRESHOLD*3));
+}
+
+static inline int
+ctx_CBRLE_recompress (uint8_t *cbrle, int size, int width, int pos, int level);
+
+#define GRAYCOL(v) ((v) + (v) * 256 + (v) * 256 * 256 + (unsigned)255*256*256*256)
+static const uint32_t hard_pal[8]={
+        GRAYCOL(0*255/7),
+        GRAYCOL(1*255/7),
+        GRAYCOL(2*255/7),
+        GRAYCOL(3*255/7),
+        GRAYCOL(4*255/7),
+        GRAYCOL(5*255/7),
+        GRAYCOL(6*255/7),
+        GRAYCOL(7*255/7)
+};
+#include <math.h>
+#define pow2(a) ((a)*(a))
+#define ctx_sqrtf sqrtf
+
+
+
+static inline int
+ctx_CBRLE_get_color_mask (int gen)
+{
+  switch (gen)
+  {
+    case 0:
+    case 1:
+    default:
+      return 0xffffffff;
+    case 2:
+      return 0xfffefefe;
+    case 3:
+      return 0xfffcfcfc;
+    case 4:
+      return 0xfff8f8f8;
+    case 5:
+      return 0xfff0f0f0;
+    case 6:
+      return 0xffe0e0e0;
+  }
+  return 0xffe0e0e0;
+}
+
+
+static inline int
+ctx_CBRLE_get_color_idx (uint8_t *cbrle, int size, int color_budget, uint32_t color, int gen)
+{
+  int found = 0;
+  int colors = cbrle[2];
+  int idx = 0;
+    uint32_t threshold =
+       (uint32_t)
+       ctx_lerpf (COLOR_THRESHOLD_START*COLOR_THRESHOLD_START*3,
+                  COLOR_THRESHOLD_END*COLOR_THRESHOLD_END*3, 
+                  //((colors  / ( color_budget-1.0f))) );
+                  ctx_sqrtf((colors  / ( color_budget-1.0f))) );
+
+#if 0 // reduce color-depth of grays
+  if (//gen > 0 &&
+      (color&0xf0) == ((color >> 8) & 0xf0) &&
+      (color&0xf0) == ((color >> 16) & 0xf0))
+  {
+    color  &= 0xfff0f0f0u;
+  }
+#endif
+
+  color = color & ctx_CBRLE_get_color_mask (gen+2);
+
+  uint32_t best_diff = 255*255*3;
+
+
+#if PAL_GRAY_PREDEF // predefined 8 grays
+  if (!found)
+  {
+    uint32_t diff;
+    int best = -1;
+    for (;idx < 8; idx++)
+    if ((diff = color_diff (hard_pal[idx], color)) < best_diff)
+    {
+      best_diff = diff;
+      best = idx;
+    }
+    idx = best;
+    if (best_diff < threshold)
+    {
+      found = 1;
+    }
+  }
+#endif
+
+  if (!found)
+  {
+    uint32_t diff;
+    int best = -1;
+    for (;idx < colors; idx++)
+    if ((diff = color_diff (((uint32_t*)(&cbrle[size-4-(idx)*4]))[0], color)) < best_diff)
+    {
+      best_diff = diff;
+      best = idx;
+    }
+    if (best !=-1) idx = best + PAL_GRAY_OFFSET;
+
+    /* the color diff threshold is dynamic, as
+     * palette space gets tighter we are less eager to add*/
+    if (best_diff > threshold && colors < color_budget-1) // didn't find - store new color
+    {
+      idx = colors++;
+      ((uint32_t*)(&cbrle[size-4-idx*4]))[0] = color;
+      cbrle[2] = colors;
+      idx += PAL_GRAY_OFFSET;
+    }
+  }
+
+  return idx;
+}
+
+static inline uint32_t
+ctx_over_RGBA8 (uint32_t dst, uint32_t src, uint32_t cov);
+
+static inline uint32_t
+ctx_over_RGBA8_2 (uint32_t dst, uint32_t si_ga, uint32_t si_rb, uint32_t si_a, uint32_t cov);
+
+
+static inline uint32_t
+ctx_CBRLE_idx_to_color (const uint8_t *cbrle, int size, int idx)
+{
+#if PAL_GRAY_PREDEF
+  if (idx < 8)
+#if 0
+    return  (idx * 17 +
+             idx * 17 * 256 +
+             idx * 17 * 256 * 256 +
+             (unsigned)255*256*256*256);
+#else
+     return hard_pal[idx];
+#endif
+  else
+#endif
+     return ((uint32_t*)(&cbrle[size-4-(idx-PAL_GRAY_OFFSET)*4]))[0];
+}
+
+static inline int
+ctx_CBRLE_compute_color_budget (int width, int size)
+{
+  int color_budget = 256;
+  //return color_budget;
+  switch ((size*8/width)){
+      case 1:
+      case 2: color_budget  = 8;break;
+      case 3: color_budget  = 8;break;
+      case 4: color_budget  = 16;break;
+      case 5: color_budget  = 32;break;
+      case 6: color_budget  = 64;break;
+      case 7: color_budget  = 128;break;
+      case 8: color_budget  = 136;break;
+      case 9: 
+      case 10: color_budget = 196;break;
+      case 11:
+      case 12:
+      case 13:
+      case 14:
+      case 15:
+      case 16: color_budget = 256;break;
+              break;
+      case 17:case 18:case 19:case 20:case 21:case 22:case 23:
+      case 24:
+      case 32: color_budget = 256;break;
+              break;
+      default:
+              color_budget = ctx_mini(256,size/2/4);
+              break;
+  }
+  color_budget = ctx_maxi(color_budget,ctx_mini(256,size/5/4));
+  return color_budget;
+}
+
+static inline void
+ctx_CBRLE_compress (const uint8_t *rgba_in,
+                     uint8_t       *cbrle,
+                     int            width,
+                     int            size,
+                     int            skip,
+                     int            count,
+                     int            mode,
+                     uint8_t       *coverage,
+                     int            allow_recompress)
+{
+  const uint8_t *rgba = rgba_in;
+  int pos;
+
+  uint32_t prev_val;
+  int recompress = 0;
+
+  int repeats;
+  int colors = 0;
+
+  uint32_t src_rgba= ((uint32_t*)rgba_in)[0];
+  int color_budget = ctx_CBRLE_compute_color_budget (width, size);
+
+#if CBRLE_GRADIENT
+  int in_gradient = 0;
+#endif
+
+  if (mode == 0)
+  {
+#if 0
+  for (int round = 0; round < 1; round++)
+  for (int i = 1; i < width-1; i++)
+  {
+    int g0 = rgba[(i-1)*4+1];
+    int g1 = rgba[(i)*4+1];
+    int g2 = rgba[(i+1)*4+1];
+
+    if (abs(g0-g1) < abs(g1-g2))
+    {
+      for (int c = 0; c < 4; c++)
+      {
+        rgba[i*4+c]=(rgba[(i-1)*4+c]+rgba[i*4+c])/2;
+      }
+    }
+    else if (abs(g0-g1) == abs(g1-g2))
+    {
+    }
+    else
+    {
+      for (int c = 0; c < 4; c++)
+      {
+        rgba[i*4+c]=(rgba[(i+1)*4+c]+rgba[(i)*4+c])/2;
+      }
+    }
+  }
+#endif
+  }
+
+  uint8_t trailer[size+2];
+  int trailer_size = 0;
+
+  uint8_t copy[(mode>=1&&mode<=2)?count*2+2:1];
+  int copy_size = 0;
+
+#if 1
+  if (cbrle[0] == 0 &&
+      cbrle[1] == 0)
+  {
+    pos = 4;
+    for (int i =0; i < width/63;i++)
+    {
+      pos = encode_pix (cbrle, pos, 0, 63, 0, 0);
+    }
+    ((uint16_t*)cbrle)[0]=pos;
+    cbrle[2] = 0;
+    cbrle[3] = 16;
+  }
+#endif
+
+  rgba = rgba_in;
+
+  pos = 4;
+  prev_val = 0xc0ffee;
+  repeats = 0;
+  
+  int trailer_start = 0;
+
+  int x = 0;
+
+  if (skip || width != count)
+  {
+    int original_length = ((uint16_t*)cbrle)[0];
+    colors = cbrle[2];
+    pos = 4;
+
+    for (x = 0; x < skip + count;)
+    {
+       int repeat = 0;
+       int codelen = decode_pix_len (&cbrle[pos], &repeat);
+       if (x + repeat < skip + count && pos < original_length)
+       {
+         pos += codelen;
+         x   += repeat;
+       }
+       else
+       {
+         uint8_t idx;
+         uint8_t idx2;
+         int gradient;
+         decode_pix (&cbrle[pos], &idx, &idx2, &repeat, &gradient);
+         
+         trailer_start = pos + codelen;
+         if (x + repeat == skip + count)
+         {
+           trailer_size = original_length - trailer_start;
+           if (trailer_size > 0)
+           {
+             memcpy (&trailer[0], &cbrle[trailer_start], trailer_size);
+           }
+           else
+           {
+             trailer_size = 0;
+           }
+         }
+         else
+         {
+           repeat -= (skip + count - x);
+
+           if (repeat > 0)
+           {
+             trailer[0] = repeat + 128 + gradient * 64;
+             trailer[1] = idx;
+           }
+           trailer_size = original_length - trailer_start;
+           if (trailer_size > 0)
+           {
+             memcpy (&trailer[2], &cbrle[pos + codelen], trailer_size);
+             if (repeat>0)trailer_size += 2;
+           }
+           else
+           {
+             trailer_size = 0;
+           }
+         }
+         break;
+       }
+    }
+
+    pos  = 4;
+    rgba = rgba_in;
+
+    for (x = 0; x < skip && pos < original_length;)
+    {
+       int     repeat = 0;
+       uint8_t idx;
+       uint8_t idx2;
+       int     dec_repeat;
+       int     gradient;
+       //int len = decode_pix_len (&cbrle[pos], &repeat);
+       int len = decode_pix (&cbrle[pos], &idx, &idx2, &dec_repeat, &gradient);
+       if (x + dec_repeat < skip)
+       {
+         pos  += len;
+         x    += dec_repeat;
+         rgba += 4 * dec_repeat;
+       }
+       else
+       {
+         repeat = skip - x;
+
+         if (repeat>0)
+         {
+           x += repeat;
+
+           if (mode==CBRLE_MODE_COPY ||
+               mode==CBRLE_MODE_OVER)
+           {
+             int mpos = 0;
+             if (dec_repeat != repeat)
+               mpos = encode_pix (copy, 0, idx, dec_repeat-repeat, gradient, 0);
+             if (original_length)
+             {
+               if (trailer_start == 0) trailer_start = original_length;
+               copy_size = trailer_start - (pos + len);
+               if (copy_size <0)
+                  fprintf (stderr, "%i: uh? cs:%i %i | %i %i %i\n", __LINE__,
+                                  copy_size, (int)sizeof(copy),
+                                  trailer_start, pos, len);
+               if (copy_size<0)copy_size=0;
+               copy_size = ctx_mini(copy_size, sizeof(copy));
+               if (copy_size)
+               {
+                 memcpy (&copy[mpos], &cbrle[pos + len], copy_size);
+               }
+               copy_size += mpos;
+             }
+             else
+             {
+               copy_size = 0;
+             }
+           }
+           else
+           {
+             rgba += 4 * repeat;
+           }
+           gradient = 0;
+           pos += encode_pix (cbrle, pos, idx, repeat, gradient, 0);
+         }
+         else
+         {
+           if (mode != CBRLE_MODE_SET)
+           {
+             int mpos = 0;
+             copy_size = trailer_start - (pos + len);
+             fprintf (stderr, "csb:%i %i\n", copy_size, (int)sizeof(copy));
+             memcpy (&copy[mpos], &cbrle[pos + len], copy_size);
+           }
+         }
+  
+         break;
+       }
+    }
+  }
+  else
+  {
+    colors = 0;
+    cbrle[0]=0; // length
+    cbrle[1]=0; // length
+    cbrle[2]=0; // pal size
+    cbrle[3]=0; // alpha
+  }
+
+#if CBRLE_GRADIENT
+  int prev_in_gradient = 0;
+#endif
+
+  if (mode == CBRLE_MODE_OVER)
+  {
+     uint32_t si_ga      = (src_rgba & 0xff00ff00) >> 8;
+     uint32_t si_rb      = src_rgba & 0x00ff00ff;
+     uint32_t si_a       = si_ga >> 16;
+
+     for (int mpos = 0; mpos < copy_size && x < width && count > 0; )
+     {
+       uint8_t offsetA = 0;
+       uint8_t offset2 = 0;
+       int repeat = 0;
+       int gradient = 0;
+       mpos += decode_pix (&copy[mpos], &offsetA, &offset2, &repeat, &gradient);
+
+       uint32_t color = ctx_CBRLE_idx_to_color (cbrle, size, offsetA);
+
+       repeat = ctx_mini (repeat, count);
+       if (repeat)
+       {
+         do {
+            int part = 0;
+            int cov = coverage[0];
+            while (coverage[0]==cov && count >0 && repeat > 0 && x < width)
+            {
+              x        ++;
+              coverage ++;
+              part     ++;
+              count    --;
+              repeat   --;
+            }
+
+            {
+         uint32_t composited = ctx_over_RGBA8_2 (color, si_ga, si_rb, si_a, cov);
+         int idx = ctx_CBRLE_get_color_idx (cbrle, size,
+                              ctx_mini(color_budget,  size-pos-colors*4 - 2), // XXX expensive?
+                              composited, recompress);
+         colors = cbrle[2];
+
+            pos += encode_pix  (cbrle, pos, idx, part, gradient, 1);
+            }
+         } while (repeat > 0);
+       }
+     }
+  }
+  else if (mode == CBRLE_MODE_COPY)
+  {
+     uint32_t si_ga      = (src_rgba & 0xff00ff00) >> 8;
+     uint32_t si_rb      = src_rgba & 0x00ff00ff;
+     for (int mpos = 0; mpos < copy_size && x < width && count > 0; )
+     {
+       uint8_t offsetA = 0;
+       uint8_t offset2 = 0;
+       int repeat = 0;
+       int gradient = 0;
+       mpos += decode_pix (&copy[mpos], &offsetA, &offset2, &repeat, &gradient);
+
+       uint32_t color = ctx_CBRLE_idx_to_color (cbrle, size, offsetA);
+
+       repeat = ctx_mini (repeat, count);
+       if (repeat)
+       {
+         colors = cbrle[2];
+         do {
+            int part = 0;
+            int cov = coverage[0];
+            while (coverage[0]==cov && count >0 && repeat > 0 && x < width)
+            {
+              x++;
+              coverage++;
+              part++;
+              count --;
+              repeat--;
+            }
+
+            {
+         uint32_t composited;
+         composited = ctx_lerp_RGBA8_2 (color, si_ga, si_rb, cov);
+         int idx = ctx_CBRLE_get_color_idx (cbrle, size, ctx_mini(color_budget,  size-pos-colors*4 - 8), 
composited, recompress);
+            pos += encode_pix  (cbrle, pos, idx, part, gradient, 1);
+            }
+         } while (repeat > 0);
+       }
+     }
+  }
+  else
+  if (mode == CBRLE_MODE_SET_COLOR)
+  {
+     int idx = ctx_CBRLE_get_color_idx (cbrle, size, ctx_mini(color_budget,  size-pos-colors*4 ), src_rgba, 
recompress);
+     while (count > 0)
+     {
+        int repeat = ctx_mini (count, 63);
+        pos += encode_pix  (cbrle, pos, idx, repeat, 0, 1);
+        count -= repeat;
+        x += repeat;
+     }
+  }
+  else
+  {
+
+  for (; x < width && count--; x++)
+    {
+      uint32_t val = ((uint32_t*)rgba)[0] & 0xffffffff;
+      // NOTE: we could probably drop precision to known lower precision reached here,
+      //       but it requires more global state
+#if CBRLE_GRADIENT
+      uint32_t next_val = 0x23ff00ff;
+
+      if (x + 1 < width && count>1)
+        next_val = ((uint32_t*)rgba)[1] & 0xffffffffu;
+#endif
+
+      if (pos > size - BORDER - trailer_size - colors * 4)
+      {
+        ((uint16_t*)cbrle)[0]=pos;
+
+        if (allow_recompress)
+        do {
+          pos = ctx_CBRLE_recompress (cbrle, size, width, pos, recompress);
+          colors = cbrle[2];
+          recompress ++;
+        }
+        while (pos > size - BORDER - trailer_size - colors * 4
+
+                       
+                        && recompress < MAX_RECOMPRESS);
+        if (recompress >3) color_budget = 0;
+        if (pos > size - BORDER - trailer_size - colors * 4)
+           goto done;
+      }
+
+      if (val != prev_val || repeats>=63)
+      {
+        if (repeats)
+        {
+
+#if CBRLE_GRADIENT
+          if ((( repeats == 1 && in_gradient == 0) ||
+                ( repeats < MAX_GRADIENT_LENGTH && in_gradient == 1)) 
+
+              && is_b_good_middle (prev_val, val, next_val, color_budget)
+          )
+          {
+            in_gradient = 1;
+          }
+          else
+#endif
+          if (repeats) // got incoming pixels
+                            // of color to store
+          {
+            int idx = ctx_CBRLE_get_color_idx (cbrle, size, ctx_mini(color_budget,  size-pos-colors*4-BORDER 
), prev_val, recompress);
+            colors = cbrle[2];
+
+            pos += encode_pix (cbrle, pos, idx, repeats,
+                            
+#if CBRLE_GRADIENT
+                      ((prev_in_gradient==1) && (in_gradient == 1))
+#else
+                      0
+#endif
+                      
+                      
+                      , 1);
+
+#if CBRLE_GRADIENT
+            prev_in_gradient = in_gradient;
+            in_gradient = 0;
+#endif
+            repeats = 0;
+          }
+        }
+      }
+      repeats++;
+      prev_val = val;
+      if (!mode)
+        rgba +=4;
+    }
+
+    if (repeats && pos  < size - colors * 4 - BORDER)
+    {
+          int idx = ctx_CBRLE_get_color_idx (cbrle, size, ctx_mini(color_budget,  size-pos-colors*4-BORDER 
), prev_val, recompress);
+          colors = cbrle[2];
+  
+          if (repeats && pos + 4 < size - colors * 4 - BORDER)
+          {
+            pos += encode_pix (cbrle, pos, idx, repeats, 0, 1);
+            repeats = 0;
+          }
+    }
+    }
+
+    if (trailer_size)
+    {
+       for (int i = 0; i < trailer_size;i++)
+       {
+
+      if (pos > size - trailer_size - BORDER - colors * 4)
+      {
+        ((uint16_t*)cbrle)[0]=pos;
+        cbrle[2] = colors;
+
+        if (allow_recompress)
+        do {
+          pos = ctx_CBRLE_recompress (cbrle, size, width, pos, recompress);
+          colors = cbrle[2];
+          recompress ++;
+        }
+        while (pos > size - trailer_size - BORDER - colors * 4 && recompress < MAX_RECOMPRESS);
+        if (pos > size - trailer_size - BORDER - colors * 4)
+           goto done;
+      }
+
+         cbrle[pos++] = trailer[i];
+       }
+    }
+done:
+    ((uint16_t*)cbrle)[0]=pos;
+    cbrle[2] = colors;
+    //cbrle[3] = 16;
+}
+
+static inline void
+_ctx_CBRLE_decompress (const uint8_t *cbrle, uint8_t *rgba8, int width, int size, int skip, int count)
+{
+  int x = 0;
+  int pos = 4;
+  uint32_t pixA = 0;
+#if CBRLE_GRADIENT
+  uint32_t prev_pix = 0;
+#endif
+  const uint8_t *codepix=cbrle+4;
+
+  int length = ((uint16_t*)cbrle)[0];
+  //int colors = cbrle[2]; 
+
+  for (x = 0; x < skip;)
+  {
+     int repeat = 0;
+     if (pos < length)
+     {
+     int len = decode_pix_len (&cbrle[pos], &repeat);
+     if (x + repeat < skip)
+     {
+       pos += len;
+       codepix += len;
+       x+=repeat;
+     }
+     else
+       break;
+     }
+     else 
+       x++;
+  }
+  //x=skip;
+
+  for (; pos < length && x < width; )
+  {
+    uint8_t offsetA = 0;
+    uint8_t offset2 = 0;
+    int repeat = 0;
+    int gradient = 0;
+    int codelen = decode_pix (codepix, &offsetA, &offset2, &repeat, &gradient);
+    //fprintf (stderr, "{%i r%i%s}", offsetA, repeat, gradient?"g":"");
+
+    pixA = ctx_CBRLE_idx_to_color (cbrle, size, offsetA);
+
+#if CBRLE_GRADIENT
+    if (gradient)
+    {
+      for (int i = 0; i < repeat && x < width && count--; i++)
+      {
+        int has_head = 1;
+        int has_tail = 0;
+        float dt = (i+has_head+0.0f) / (repeat+ has_head + has_tail-1.0f);
+        ((uint32_t*)(&rgba8[(x++)*4]))[0] = ctx_lerp_RGBA8 (prev_pix, pixA, (uint8_t)(dt*255.0f));
+        //((uint32_t*)(&rgba8[(x++)*4]))[0] = (int)(dt * 255) | 0xff000000;
+      }
+    }
+    else
+#endif
+    {
+       if (offsetA != offset2 && repeat == 2)
+       {
+         uint32_t pixB = ctx_CBRLE_idx_to_color (cbrle, size, offset2);
+         ((uint32_t*)(&rgba8[(x++)*4]))[0] = pixA;
+         ((uint32_t*)(&rgba8[(x++)*4]))[0] = pixB;
+       }
+       else
+       {
+         for (int i = 0; i < repeat && x < width && count--; i++)
+           ((uint32_t*)(&rgba8[(x++)*4]))[0] = pixA;
+       }
+    }
+#if CBRLE_GRADIENT
+    prev_pix = pixA;
+#endif
+
+    codepix += codelen;
+    pos += codelen;
+  }
+  //fprintf (stderr, "\n");
+
+  // replicate last value
+  while (x < width && count--)
+    ((uint32_t*)(&rgba8[(x++)*4]))[0] = prev_pix;
+}
+
+
+static inline int
+ctx_CBRLE_recompress_sort_pal (uint8_t *cbrle, int size, int width, int length, int no)
+{
+  uint8_t temp[width*4 + 32];
+  int colors = cbrle[2];
+  //fprintf (stderr, "{%i %i %i}", size, colors, no);
+  uint32_t mask = ctx_CBRLE_get_color_mask (no);
+    for (int i = size - colors * 4; i < size-4; i+=4)
+    {
+      uint32_t *pix = (uint32_t*)(&cbrle[i]);
+      pix[i] &= mask;
+    }
+
+  _ctx_CBRLE_decompress (cbrle, temp, width, size, 0, width);
+  memset(cbrle, 0, size);
+  ctx_CBRLE_compress (temp, cbrle, width, size, 0, width, CBRLE_MODE_SET, NULL, 0);
+  return ((uint16_t*)cbrle)[0];
+}
+
+
+static inline int
+ctx_CBRLE_recompress_drop_bits (uint8_t *cbrle, int size, int width, int length, int no)
+{
+  uint8_t temp[width*4 + 32];
+  int colors = cbrle[2];
+  //fprintf (stderr, "{%i %i %i}", size, colors, no);
+  uint32_t mask = ctx_CBRLE_get_color_mask (no);
+    for (int i = size - colors * 4; i < size-4; i+=4)
+    {
+      uint32_t *pix = (uint32_t*)(&cbrle[i]);
+      pix[i] &= mask;
+    }
+  _ctx_CBRLE_decompress (cbrle, temp, width, size, 0, width);
+  memset(cbrle, 0, size);
+  ctx_CBRLE_compress (temp, cbrle, width, size, 0, width, CBRLE_MODE_SET, NULL, 0);
+  return ((uint16_t*)cbrle)[0];
+}
+
+static inline int
+ctx_CBRLE_recompress_merge_pairs (uint8_t *cbrle, int size, int width, int length)
+{
+  uint8_t temp[width*4];
+   // drop horizontal resolution
+      _ctx_CBRLE_decompress (cbrle, temp, width, size, 0, width);
+      for (int i = 0; i < width-1; i++)
+      if ((rand()%100<MERGE_CHANCE)
+       &&  color_diff ( ((uint32_t*)(&temp[i*4]))[0],
+                        ((uint32_t*)(&temp[(i+1)*4]))[0]) < MERGE_THRESHOLD*MERGE_THRESHOLD*3
+         )
+      for (int c = 0; c < 4; c++)
+        temp[i*4+c]=temp[(i+1)*4+c];
+
+      memset(cbrle, 0, size);
+      ctx_CBRLE_compress (temp, cbrle, width, size, 0, width, CBRLE_MODE_SET, NULL, 0);
+
+  return ((uint16_t*)cbrle)[0];
+}
+
+static inline int
+ctx_CBRLE_recompress_smoothen (uint8_t *cbrle, int size, int width, int length)
+{
+  uint8_t temp[width*4];
+  _ctx_CBRLE_decompress (cbrle, temp, width, size, 0, width);
+
+#if 0
+  for (int round = 0; round < 2; round++)
+  for (int i = 1; i < width-1; i++)
+  {
+    for (int c = 0; c < 4; c++)
+    {
+      temp[i*4+c]=(uint8_t)(temp[(i+1)*4+c]*0.10f+temp[i*4+c]*0.8f+temp[(i-1)*4+c]*0.10f);
+    }
+  }
+#endif
+
+#if 1
+  for (int round = 0; round < 2; round++)
+  for (int i = 1; i < width-1; i++)
+  {
+    int g0 = temp[(i-1)*4+1];
+    int g1 = temp[(i)*4+1];
+    int g2 = temp[(i+1)*4+1];
+
+    if (abs(g0-g1) < abs(g1-g2))
+    {
+      for (int c = 0; c < 4; c++)
+      {
+        temp[i*4+c]=(temp[(i-1)*4+c]+temp[i*4+c])/2;
+      }
+    }
+    else if (abs(g0-g1) == abs(g1-g2))
+    {
+#if 0
+      for (int c = 0; c < 4; c++)
+      {
+        temp[i*4+c]=(temp[(i+1)*4+c]+temp[i*4+c]+temp[(i-1)*4+c])/3;
+      }
+#endif
+    }
+    else
+    {
+      for (int c = 0; c < 4; c++)
+      {
+        temp[i*4+c]=(temp[(i+1)*4+c]+temp[(i)*4+c])/2;
+      }
+    }
+  }
+#else
+#endif
+
+  memset(cbrle, 0, size);
+  ctx_CBRLE_compress (temp, cbrle, width, size, 0, width, CBRLE_MODE_SET, NULL, 0);
+
+  return ((uint16_t*)cbrle)[0];
+}
+
+static inline int
+ctx_CBRLE_recompress (uint8_t *cbrle, int size, int width, int length, int no)
+{
+  //uint8_t temp[width*4];
+      length = ((uint16_t*)cbrle)[0];
+
+      //if (no>0)
+      //fprintf (stderr, "len: %i cols:%i i:%i\n", length, cbrle[2], no);
+
+#if 0
+//ctx_CBRLE_recompress_smoothen (cbrle, size, width, length);
+  ctx_CBRLE_recompress_smoothen (cbrle, size, width, length);
+  if (((uint16_t*)cbrle)[0] < length - 8 || no == 0)
+  {
+//  fprintf (stderr, "rlen: %i cols:%i i:%i\n", ((uint16_t*)cbrle)[0],
+//                      cbrle[2], no);
+    return ((uint16_t*)cbrle)[0];
+  }
+#endif
+#if 1
+  if (no == 0)
+  {
+    ctx_CBRLE_recompress_smoothen (cbrle, size, width, length);
+    if (((uint16_t*)cbrle)[0] < length -8)
+      return ((uint16_t*)cbrle)[0];
+  }
+#endif
+
+#if 0
+  ctx_CBRLE_recompress_drop_bits (cbrle, size, width, length, no);
+  if (((uint16_t*)cbrle)[0] < length -8)
+    return ((uint16_t*)cbrle)[0];
+#endif
+
+
+#if 0
+  ctx_CBRLE_recompress_merge_pairs (cbrle, size, width, length);
+  if (((uint16_t*)cbrle)[0] < length - 8 || no < 2)
+  {
+    return ((uint16_t*)cbrle)[0];
+  }
+#endif
+
+  return ((uint16_t*)cbrle)[0];
+}
+
+
+#endif
+#endif
 #ifndef CTX_DRAWLIST_H
 #define CTX_DRAWLIST_H
 
@@ -7744,7 +8947,7 @@ ctx_u8 (CtxCode code,
         uint8_t e, uint8_t f, uint8_t g, uint8_t h);
 
 #define CTX_PROCESS_VOID(cmd) do {\
-  CtxEntry commands[4] = {{cmd}};\
+  CtxEntry commands[4] = {{cmd,{{0}}}};\
   ctx_process (ctx, &commands[0]);}while(0) \
 
 #define CTX_PROCESS_F(cmd,x,y) do {\
@@ -7850,16 +9053,16 @@ ctx_edgelist_resize (CtxDrawlist *drawlist, int desired_size)
   if (drawlist->entries)
     {
       //printf ("grow %p to %d from %d\n", drawlist, new_size, drawlist->size);
-      CtxEntry *ne =  (CtxEntry *) malloc (item_size * new_size);
+      CtxEntry *ne =  (CtxEntry *) ctx_malloc (item_size * new_size);
       memcpy (ne, drawlist->entries, drawlist->size * item_size );
-      free (drawlist->entries);
+      ctx_free (drawlist->entries);
       drawlist->entries = ne;
-      //drawlist->entries = (CtxEntry*)malloc (drawlist->entries, item_size * new_size);
+      //drawlist->entries = (CtxEntry*)ctx_malloc (drawlist->entries, item_size * new_size);
     }
   else
     {
       //fprintf (stderr, "allocating for %p %d\n", drawlist, new_size);
-      drawlist->entries = (CtxEntry *) malloc (item_size * new_size);
+      drawlist->entries = (CtxEntry *) ctx_malloc (item_size * new_size);
     }
   drawlist->size = new_size;
     }
@@ -7912,10 +9115,6 @@ ctx_edgelist_add_single (CtxDrawlist *drawlist, CtxEntry *entry)
 #define CTX_RGBA8_RB_MASK  (CTX_RGBA8_R_MASK | CTX_RGBA8_B_MASK)
 #define CTX_RGBA8_GA_MASK  (CTX_RGBA8_G_MASK | CTX_RGBA8_A_MASK)
 
-static inline float ctx_fmod1f (float val)
-{
-  return ctx_fabsf (val - (int)(val));
-}
 
 
 CTX_INLINE static void
@@ -7998,7 +9197,7 @@ CTX_INLINE static uint32_t ctx_bi_RGBA8 (uint32_t isrc00, uint32_t isrc01, uint3
 
 inline static int ctx_grad_index (CtxRasterizer *rasterizer, float v)
 {
-  int ret = v * (rasterizer->gradient_cache_elements - 1) + 0.5f;
+  int ret = (int)(v * (rasterizer->gradient_cache_elements - 1) + 0.5f);
   ret = ctx_maxi (0, ret);
   ret = ctx_mini (rasterizer->gradient_cache_elements-1, ret);
   return ret;
@@ -8029,7 +9228,7 @@ _ctx_fragment_gradient_1d_RGBA8 (CtxRasterizer *rasterizer, float x, float y, ui
 
   if (g->n_stops == 0)
     {
-      rgba[0] = rgba[1] = rgba[2] = v * 255;
+      rgba[0] = rgba[1] = rgba[2] = (int)(v * 255);
       rgba[3] = 255;
       return;
     }
@@ -8060,7 +9259,7 @@ _ctx_fragment_gradient_1d_RGBA8 (CtxRasterizer *rasterizer, float x, float y, ui
       uint8_t next_rgba[4];
       ctx_color_get_rgba8 (rasterizer->state, & (stop->color), stop_rgba);
       ctx_color_get_rgba8 (rasterizer->state, & (next_stop->color), next_rgba);
-      int dx = (v - stop->pos) * 255 / (next_stop->pos - stop->pos);
+      int dx = (int)((v - stop->pos) * 255 / (next_stop->pos - stop->pos));
 #if 1
       ((uint32_t*)rgba)[0] = ctx_lerp_RGBA8 (((uint32_t*)stop_rgba)[0],
                                              ((uint32_t*)next_rgba)[0], dx);
@@ -8145,7 +9344,7 @@ ctx_gradient_cache_prime (CtxRasterizer *rasterizer)
      length = ctx_maxf (u, v);
   }
   
-    rasterizer->gradient_cache_elements = ctx_mini (length, CTX_GRADIENT_CACHE_ELEMENTS);
+    rasterizer->gradient_cache_elements = ctx_mini ((int)length, CTX_GRADIENT_CACHE_ELEMENTS);
   }
 
   for (int u = 0; u < rasterizer->gradient_cache_elements; u++)
@@ -8169,7 +9368,7 @@ ctx_fragment_gradient_1d_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, ui
   if (v > 1) { v = 1; }
   if (g->n_stops == 0)
     {
-      rgba[0] = rgba[1] = rgba[2] = v * 255;
+      rgba[0] = rgba[1] = rgba[2] = (int)(v * 255);
       rgba[1] = 255;
       return;
     }
@@ -8200,7 +9399,7 @@ ctx_fragment_gradient_1d_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, ui
       uint8_t next_rgba[4];
       ctx_color_get_graya_u8 (rasterizer->state, & (stop->color), stop_rgba);
       ctx_color_get_graya_u8 (rasterizer->state, & (next_stop->color), next_rgba);
-      int dx = (v - stop->pos) * 255 / (next_stop->pos - stop->pos);
+      int dx = (int)((v - stop->pos) * 255 / (next_stop->pos - stop->pos));
       for (int c = 0; c < 2; c++)
         { rgba[c] = ctx_lerp_u8 (stop_rgba[c], next_rgba[c], dx); }
       return;
@@ -8252,7 +9451,7 @@ ctx_fragment_gradient_1d_RGBAF (CtxRasterizer *rasterizer, float v, float y, flo
       float next_rgba[4];
       ctx_color_get_rgba (rasterizer->state, & (stop->color), stop_rgba);
       ctx_color_get_rgba (rasterizer->state, & (next_stop->color), next_rgba);
-      int dx = (v - stop->pos) / (next_stop->pos - stop->pos);
+      int dx = (int)((v - stop->pos) / (next_stop->pos - stop->pos));
       for (int c = 0; c < 4; c++)
         { rgba[c] = ctx_lerpf (stop_rgba[c], next_rgba[c], dx); }
       rgba[3] *= global_alpha;
@@ -8278,8 +9477,8 @@ ctx_fragment_image_RGBA8 (CtxRasterizer *rasterizer, float x, float y, float z,
   for (int i = 0; i < count; i ++)
   {
 
-  int u = x;
-  int v = y;
+  int u = (int)x;
+  int v = (int)y;
   int width = buffer->width;
   int height = buffer->height;
   if ( u < 0 || v < 0 ||
@@ -8307,27 +9506,29 @@ ctx_fragment_image_RGBA8 (CtxRasterizer *rasterizer, float x, float y, float z,
         src10 = src00 + buffer->stride;
         src11 = src01 + buffer->stride;
       }
-      float dx = (x-(int)(x)) * 255.9;
-      float dy = (y-(int)(y)) * 255.9;
+      float dx = (x-(int)(x)) * 255.9f;
+      float dy = (y-(int)(y)) * 255.9f;
+      uint8_t dxb = (uint8_t)dx;
+      uint8_t dyb = (uint8_t)dy;
 
       switch (bpp)
       {
       case 1:
-        rgba[0] = rgba[1] = rgba[2] = ctx_lerp_u8 (ctx_lerp_u8 (src00[0], src01[0], dx),
-                               ctx_lerp_u8 (src10[0], src11[0], dx), dy);
+        rgba[0] = rgba[1] = rgba[2] = ctx_lerp_u8 (ctx_lerp_u8 (src00[0], src01[0], dxb),
+                               ctx_lerp_u8 (src10[0], src11[0], dxb), dyb);
         rgba[3] = global_alpha_u8;
         break;
       case 2:
-        rgba[0] = rgba[1] = rgba[2] = ctx_lerp_u8 (ctx_lerp_u8 (src00[0], src01[0], dx),
-                               ctx_lerp_u8 (src10[0], src11[0], dx), dy);
-        rgba[3] = ctx_lerp_u8 (ctx_lerp_u8 (src00[1], src01[1], dx),
-                               ctx_lerp_u8 (src10[1], src11[1], dx), dy);
+        rgba[0] = rgba[1] = rgba[2] = ctx_lerp_u8 (ctx_lerp_u8 (src00[0], src01[0], dxb),
+                               ctx_lerp_u8 (src10[0], src11[0], dxb), dyb);
+        rgba[3] = ctx_lerp_u8 (ctx_lerp_u8 (src00[1], src01[1], dxb),
+                               ctx_lerp_u8 (src10[1], src11[1], dxb), dyb);
         rgba[3] = (rgba[3] * global_alpha_u8) / 255;
         break;
       case 3:
       for (int c = 0; c < bpp; c++)
-        { rgba[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dx),
-                                 ctx_lerp_u8 (src10[c], src11[c], dx), dy);
+        { rgba[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dxb),
+                                 ctx_lerp_u8 (src10[c], src11[c], dxb), dyb);
                 
         }
         rgba[3]=global_alpha_u8;
@@ -8335,8 +9536,8 @@ ctx_fragment_image_RGBA8 (CtxRasterizer *rasterizer, float x, float y, float z,
       break;
       case 4:
       for (int c = 0; c < bpp; c++)
-        { rgba[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dx),
-                                 ctx_lerp_u8 (src10[c], src11[c], dx), dy);
+        { rgba[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dxb),
+                                 ctx_lerp_u8 (src10[c], src11[c], dxb), dyb);
                 
         }
         rgba[3] = (rgba[3] * global_alpha_u8) / 255;
@@ -8476,7 +9677,7 @@ CTX_INLINE static void
 ctx_float_deassociate_alpha (int components, float *rgba, float *dst)
 {
   float ralpha = rgba[components-1];
-  if (ralpha != 0.0) ralpha = 1.0/ralpha;
+  if (ralpha != 0.0f) ralpha = 1.0f/ralpha;
 
   for (int c = 0; c < components-1; c++)
     dst[c] = (rgba[c] * ralpha);
@@ -8529,7 +9730,7 @@ ctx_fragment_image_rgb8_RGBA8_box (CtxRasterizer *rasterizer,
   int height = buffer->height;
   uint8_t global_alpha_u8 = rasterizer->state->gstate.global_alpha_u8;
   float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
-  int dim = (1.0 / factor) / 3;
+  int dim = (int)((1.0f / factor) / 3);
 
   int i = 0;
 
@@ -8547,8 +9748,8 @@ ctx_fragment_image_rgb8_RGBA8_box (CtxRasterizer *rasterizer,
        y + dim >= height); i++)
   {
 
-  int u = x;
-  int v = y;
+  int u = (int)x;
+  int v = (int)y;
     {
       int bpp = 3;
       rgba[3]=global_alpha_u8; // gets lost
@@ -8625,107 +9826,22 @@ ctx_RGBA8_apply_global_alpha_and_associate (CtxRasterizer *rasterizer,
 
 #if CTX_FRAGMENT_SPECIALIZE
 
+static void
+ctx_fragment_image_rgb8_RGBA8_nearest (CtxRasterizer *rasterizer,
+                                       float x, float y, float z,
+                                       void *out, int scount,
+                                       float dx, float dy, float dz);
 static inline void
 ctx_fragment_image_rgb8_RGBA8_bi (CtxRasterizer *rasterizer,
                                   float x, float y, float z,
                                   void *out, int scount,
                                   float dx, float dy, float dz)
 {
-  uint32_t count = scount;
-  uint8_t global_alpha_u8 = rasterizer->state->gstate.global_alpha_u8;
-  uint8_t *rgba = (uint8_t *) out;
-  CtxSource *g = &rasterizer->state->gstate.source_fill;
-  CtxBuffer *buffer = g->texture.buffer->color_managed?g->texture.buffer->color_managed:g->texture.buffer;
-  const int bwidth = buffer->width;
-  const int bheight = buffer->height;
-  unsigned int i = 0;
-
-  int yi_delta = dy * 65536;
-  int xi_delta = dx * 65536;
-  int zi_delta = dz * 65536;
-  int32_t yi = y * 65536;
-  int32_t xi = x * 65536;
-  int32_t zi = z * 65536;
-  {
-    int32_t u1 = xi + xi_delta* (count-1);
-    int32_t v1 = yi + yi_delta* (count-1);
-    int32_t z1 = zi + zi_delta* (count-1);
-    uint32_t *edst = ((uint32_t*)out)+(count-1);
-    for (; i < count; )
-    {
-      float z_recip = (z1!=0) * (1.0/z1);
-      if ((u1*z_recip) <0 ||
-          (v1*z_recip) <0 ||
-          (u1*z_recip) >= (bwidth) - 1 ||
-          (v1*z_recip) >= (bheight) - 1)
-      {
-        *edst-- = 0;
-        count --;
-        u1 -= xi_delta;
-        v1 -= yi_delta;
-        z1 -= zi_delta;
-      }
-      else break;
-    }
-  }
-
-  for (i= 0; i < count; i ++)
-  {
-    float z_recip = (zi!=0) * (1.0/zi);
-    int u = xi * z_recip;
-    int v = yi * z_recip;
-    if ( u  <= 0 || v  <= 0 || u+1 >= bwidth-1 || v+1 >= bheight-1)
-    {
-      *((uint32_t*)(rgba))= 0;
-    }
-    else
-      break;
-    xi += xi_delta;
-    yi += yi_delta;
-    zi += zi_delta;
-    rgba += 4;
-  }
-
-  int stride = buffer->stride;
-  uint8_t *data = (uint8_t*)buffer->data;
-  while (i < count)
-  {
-    float zr = (zi!=0)*(1.0/zi) * 256;
-    int du = xi * zr;
-    int u = du >> 8;
-    int dv = yi * zr;
-    int v = dv >> 8;
-      int bpp = 3;
-      uint8_t *src00 = data;
-      src00 += v * stride + u * bpp;
-      uint8_t *src01 = src00;
-      if ( u + 1 < bwidth)
-      {
-        src01 = src00 + bpp;
-      }
-      uint8_t *src11 = src01;
-      uint8_t *src10 = src00;
-      if ( v + 1 < bheight)
-      {
-        src10 = src00 + stride;
-        src11 = src01 + stride;
-      }
-      float dx = (x-(int)(x)) * 255.9f;
-      float dy = (y-(int)(y)) * 255.9f;
-      for (int c = 0; c < bpp; c++)
-      {
-        rgba[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dx),
-                               ctx_lerp_u8 (src10[c], src11[c], dx), dy);
-      }
-      rgba[3] = global_alpha_u8;
-      ctx_RGBA8_associate_alpha_probably_opaque (rgba);
-
-    xi += xi_delta;
-    yi += yi_delta;
-    zi += zi_delta;
-    rgba += 3;
-    i++;
-  }
+  ctx_fragment_image_rgb8_RGBA8_nearest (rasterizer,
+                                         x, y, z,
+                                         out, scount,
+                                         dx, dy, dz);
+  return;
 }
 
 static void
@@ -8744,12 +9860,12 @@ ctx_fragment_image_rgb8_RGBA8_nearest (CtxRasterizer *rasterizer,
   unsigned int i = 0;
   uint8_t *data = ((uint8_t*)buffer->data);
 
-  int yi_delta = dy * 65536;
-  int xi_delta = dx * 65536;
-  int zi_delta = dz * 65536;
-  int32_t yi = y * 65536;
-  int32_t xi = x * 65536;
-  int32_t zi = z * 65536;
+  int yi_delta = (int)(dy * 65536);
+  int xi_delta = (int)(dx * 65536);
+  int zi_delta = (int)(dz * 65536);
+  int32_t yi = (int)(y * 65536);
+  int32_t xi = (int)(x * 65536);
+  int32_t zi = (int)(z * 65536);
   {
     int32_t u1 = xi + xi_delta* (count-1);
     int32_t v1 = yi + yi_delta* (count-1);
@@ -8757,7 +9873,7 @@ ctx_fragment_image_rgb8_RGBA8_nearest (CtxRasterizer *rasterizer,
     uint32_t *edst = ((uint32_t*)out)+(count-1);
     for (; i < count; )
     {
-      float z_recip = (z1!=0) * (1.0/z1);
+      float z_recip = (z1!=0) * (1.0f/z1);
       if ((u1*z_recip) <0 ||
           (v1*z_recip) <0 ||
           (u1*z_recip) >= (bwidth) - 1 ||
@@ -8775,9 +9891,9 @@ ctx_fragment_image_rgb8_RGBA8_nearest (CtxRasterizer *rasterizer,
 
   for (i= 0; i < count; i ++)
   {
-    float z_recip = (zi!=0) * (1.0/zi);
-    int u = xi * z_recip;
-    int v = yi * z_recip;
+    float z_recip = (zi!=0) * (1.0f/zi);
+    int u = (int)(xi * z_recip);
+    int v = (int)(yi * z_recip);
     if ( u  <= 0 || v  <= 0 || u+1 >= bwidth-1 || v+1 >= bheight-1)
     {
       *((uint32_t*)(rgba))= 0;
@@ -8792,9 +9908,9 @@ ctx_fragment_image_rgb8_RGBA8_nearest (CtxRasterizer *rasterizer,
 
   while (i < count)
   {
-    float z_recip = (zi!=0) * (1.0/zi);
-    int u = xi * z_recip;
-    int v = yi * z_recip;
+    float z_recip = (zi!=0) * (1.0f/zi);
+    int u = (int)(xi * z_recip);
+    int v = (int)(yi * z_recip);
     for (unsigned int c = 0; c < 3; c++)
       rgba[c] = data[(bwidth *v +u)*3+c];
     rgba[3] = global_alpha_u8;
@@ -8814,7 +9930,7 @@ CTX_DECLARE_SWAP_RED_GREEN_FRAGMENT(ctx_fragment_image_rgb8_RGBA8_bi)
 CTX_DECLARE_SWAP_RED_GREEN_FRAGMENT(ctx_fragment_image_rgb8_RGBA8_nearest)
 
 
-static void
+static inline void
 ctx_fragment_image_rgb8_RGBA8 (CtxRasterizer *rasterizer,
                                float x,
                                float y,
@@ -8881,7 +9997,7 @@ ctx_fragment_image_rgba8_RGBA8_box (CtxRasterizer *rasterizer,
   int height = buffer->height;
   uint8_t global_alpha_u8 = rasterizer->state->gstate.global_alpha_u8;
   float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
-  int dim = (1.0 / factor) / 3;
+  int dim = (int)((1.0f / factor) / 3);
 
   int i = 0;
 
@@ -8899,8 +10015,8 @@ ctx_fragment_image_rgba8_RGBA8_box (CtxRasterizer *rasterizer,
        y + dim >= height); i++)
   {
 
-  int u = x;
-  int v = y;
+  int u = (int)x;
+  int v = (int)y;
     {
       int bpp = 4;
           uint64_t sum[4]={0,0,0,0};
@@ -8962,8 +10078,8 @@ ctx_fragment_image_rgba8_RGBA8_nearest_copy (CtxRasterizer *rasterizer,
 #endif
   int bwidth  = buffer->width;
   int bheight = buffer->height;
-  int u = x;// + 0.5f;
-  int v = y;// + 0.5f;
+  int u = (int)x;
+  int v = (int)y;
 
   uint32_t *src = ((uint32_t*)buffer->data) + bwidth * v + u;
   if (CTX_UNLIKELY(!(v >= 0 && v < bheight)))
@@ -9012,8 +10128,8 @@ ctx_fragment_image_rgba8_RGBA8_nearest_copy_repeat (CtxRasterizer *rasterizer,
   uint32_t *dst = (uint32_t*)out;
   int bwidth  = buffer->width;
   int bheight = buffer->height;
-  int u = x;
-  int v = y;
+  int u = (int)x;
+  int v = (int)y;
   if (v < 0) v += bheight * 8192;
   if (u < 0) u += bwidth * 8192;
   v %= bheight;
@@ -9105,10 +10221,10 @@ ctx_fragment_image_rgba8_RGBA8_nearest_affine (CtxRasterizer *rasterizer,
   unsigned int i = 0;
   uint32_t *data = ((uint32_t*)buffer->data);
 
-  int yi_delta = dy * 65536;
-  int xi_delta = dx * 65536;
-  int32_t yi = y * 65536;
-  int32_t xi = x * 65536;
+  int yi_delta = (int)(dy * 65536);
+  int xi_delta = (int)(dx * 65536);
+  int32_t yi = (int)(y * 65536);
+  int32_t xi = (int)(x * 65536);
   switch (extend){
           case CTX_EXTEND_NONE:
                   {
@@ -9191,7 +10307,7 @@ ctx_fragment_image_rgba8_RGBA8_nearest_scale (CtxRasterizer *rasterizer,
   CtxExtend  extend = rasterizer->state->gstate.extend;
   uint32_t *src = NULL;
   buffer = g->texture.buffer->color_managed?g->texture.buffer->color_managed:g->texture.buffer;
-  int ideltax = dx * 65536;
+  int ideltax = (int)(dx * 65536);
   uint32_t *dst = (uint32_t*)out;
   int bwidth  = buffer->width;
   int bheight = buffer->height;
@@ -9205,8 +10321,8 @@ ctx_fragment_image_rgba8_RGBA8_nearest_scale (CtxRasterizer *rasterizer,
 
   {
     unsigned int i = 0;
-    int32_t ix = x * 65536;
-    int32_t iy = y * 65536;
+    int32_t ix = (int)(x * 65536);
+    int32_t iy = (int)(y * 65536);
 
     if (extend == CTX_EXTEND_NONE)
     {
@@ -9280,12 +10396,12 @@ ctx_fragment_image_rgba8_RGBA8_nearest_generic (CtxRasterizer *rasterizer,
   unsigned int i = 0;
   uint32_t *data = ((uint32_t*)buffer->data);
 
-  int yi_delta = dy * 65536;
-  int xi_delta = dx * 65536;
-  int zi_delta = dz * 65536;
-  int32_t yi = y * 65536;
-  int32_t xi = x * 65536;
-  int32_t zi = z * 65536;
+  int yi_delta = (int)(dy * 65536);
+  int xi_delta = (int)(dx * 65536);
+  int zi_delta = (int)(dz * 65536);
+  int32_t yi = (int)(y * 65536);
+  int32_t xi = (int)(x * 65536);
+  int32_t zi = (int)(z * 65536);
   switch (extend){
           case CTX_EXTEND_NONE:
                   {
@@ -9296,7 +10412,7 @@ ctx_fragment_image_rgba8_RGBA8_nearest_generic (CtxRasterizer *rasterizer,
     uint32_t *edst = ((uint32_t*)out)+(count-1);
     for (; i < count; )
     {
-      float z_recip = (z1!=0) * (1.0/z1);
+      float z_recip = (z1!=0) * (1.0f/z1);
       if ((u1*z_recip) <0 ||
           (v1*z_recip) <0 ||
           (u1*z_recip) >= (bwidth) - 1 ||
@@ -9313,9 +10429,9 @@ ctx_fragment_image_rgba8_RGBA8_nearest_generic (CtxRasterizer *rasterizer,
 
   for (i= 0; i < count; i ++)
   {
-    float z_recip = (zi!=0) * (1.0/zi);
-    int u = xi * z_recip;
-    int v = yi * z_recip;
+    float z_recip = (zi!=0) * (1.0f/zi);
+    int u = (int)(xi * z_recip);
+    int v = (int)(yi * z_recip);
     if ( u  <= 0 || v  <= 0 || u+1 >= bwidth-1 || v+1 >= bheight-1)
     {
       *((uint32_t*)(rgba))= 0;
@@ -9330,9 +10446,9 @@ ctx_fragment_image_rgba8_RGBA8_nearest_generic (CtxRasterizer *rasterizer,
 
   while (i < count)
   {
-    float z_recip = (zi!=0) * (1.0/zi);
-    int u = xi * z_recip;
-    int v = yi * z_recip;
+    float z_recip = (zi!=0) * (1.0f/zi);
+    int u = (int)(xi * z_recip);
+    int v = (int)(yi * z_recip);
     //((uint32_t*)(&rgba[0]))[0] =
     //  ctx_RGBA8_associate_global_alpha_u32 (data[bwidth *v +u], global_alpha_u8);
     ((uint32_t*)(&rgba[0]))[0] = data[bwidth *v +u];
@@ -9347,9 +10463,9 @@ ctx_fragment_image_rgba8_RGBA8_nearest_generic (CtxRasterizer *rasterizer,
   default:
     while (i < count)
     {
-      float z_recip = (zi!=0) * (1.0/zi);
-      int u = xi * z_recip;
-      int v = yi * z_recip;
+      float z_recip = (zi!=0) * (1.0f/zi);
+      int u = (int)(xi * z_recip);
+      int v = (int)(yi * z_recip);
       _ctx_coords_restrict (extend, &u, &v, bwidth, bheight);
       //((uint32_t*)(&rgba[0]))[0] =
       //  ctx_RGBA8_associate_global_alpha_u32 (data[bwidth *v +u], global_alpha_u8);
@@ -9373,7 +10489,7 @@ ctx_fragment_image_rgba8_RGBA8_nearest (CtxRasterizer *rasterizer,
   CtxExtend extend = rasterizer->state->gstate.extend;
   if (z == 1.0f && dz == 0.0f) // this also catches other constant z!
   {
-    if (dy == 0.0f && dx == 1.0 && extend == CTX_EXTEND_NONE)
+    if (dy == 0.0f && dx == 1.0f && extend == CTX_EXTEND_NONE)
       ctx_fragment_image_rgba8_RGBA8_nearest_copy (rasterizer, x, y, z, out, count, dx, dy, dz);
     else
       ctx_fragment_image_rgba8_RGBA8_nearest_affine (rasterizer, x, y, z, out, count, dx, dy, dz);
@@ -9415,9 +10531,10 @@ ctx_fragment_image_rgba8_RGBA8_bi_scale (CtxRasterizer *rasterizer,
 
     //x+=1; // XXX off by one somewhere? ,, needed for alignment with nearest
 
-    int32_t yi = y * 65536;
-    int32_t xi = x * 65536;
-    int xi_delta = dx * 65536;
+    int32_t yi = (int)(y * 65536);
+    int32_t xi = (int)(x * 65536);
+
+    int xi_delta = (int)(dx * 65536);
 
     if (!extend)
     {
@@ -9591,8 +10708,8 @@ ctx_fragment_image_rgba8_RGBA8_bi_affine (CtxRasterizer *rasterizer,
                                           void *out, int scount,
                                           float dx, float dy, float dz)
 {
-        x-=0.5;
-        y-=0.5;
+        x-=0.5f;
+        y-=0.5f;
   uint32_t count = scount;
   uint8_t global_alpha_u8 = rasterizer->state->gstate.global_alpha_u8;
   uint8_t *rgba = (uint8_t *) out;
@@ -9604,10 +10721,10 @@ ctx_fragment_image_rgba8_RGBA8_bi_affine (CtxRasterizer *rasterizer,
   unsigned int i = 0;
   uint32_t *data = ((uint32_t*)buffer->data);
 
-  int yi_delta = dy * 65536;
-  int xi_delta = dx * 65536;
-  int32_t yi = y * 65536;
-  int32_t xi = x * 65536;
+  int yi_delta = (int)(dy * 65536);
+  int xi_delta = (int)(dx * 65536);
+  int32_t yi = (int)(y * 65536);
+  int32_t xi = (int)(x * 65536);
 
   if (extend == CTX_EXTEND_NONE)
   {
@@ -9694,8 +10811,8 @@ ctx_fragment_image_rgba8_RGBA8_bi_generic (CtxRasterizer *rasterizer,
                                            void *out, int scount,
                                            float dx, float dy, float dz)
 {
-        x-=0.5;
-        y-=0.5;
+        x-=0.5f;
+        y-=0.5f;
   uint32_t count = scount;
   uint8_t global_alpha_u8 = rasterizer->state->gstate.global_alpha_u8;
   uint8_t *rgba = (uint8_t *) out;
@@ -9707,12 +10824,12 @@ ctx_fragment_image_rgba8_RGBA8_bi_generic (CtxRasterizer *rasterizer,
   unsigned int i = 0;
   uint32_t *data = ((uint32_t*)buffer->data);
 
-  int yi_delta = dy * 65536;
-  int xi_delta = dx * 65536;
-  int zi_delta = dz * 65536;
-  int32_t yi = y * 65536;
-  int32_t xi = x * 65536;
-  int32_t zi = z * 65536;
+  int yi_delta = (int)(dy * 65536);
+  int xi_delta = (int)(dx * 65536);
+  int zi_delta = (int)(dz * 65536);
+  int32_t yi = (int)(y * 65536);
+  int32_t xi = (int)(x * 65536);
+  int32_t zi = (int)(z * 65536);
   if (extend == CTX_EXTEND_NONE) {
     int32_t u1 = xi + xi_delta* (count-1);
     int32_t v1 = yi + yi_delta* (count-1);
@@ -9720,7 +10837,7 @@ ctx_fragment_image_rgba8_RGBA8_bi_generic (CtxRasterizer *rasterizer,
     uint32_t *edst = ((uint32_t*)out)+(count-1);
     for (; i < count; )
     {
-      float z_recip = (z1!=0) * (1.0/z1);
+      float z_recip = (z1!=0) * (1.0f/z1);
       if ((u1*z_recip) <0 ||
           (v1*z_recip) <0 ||
           (u1*z_recip) >= (bwidth) - 1 ||
@@ -9737,9 +10854,9 @@ ctx_fragment_image_rgba8_RGBA8_bi_generic (CtxRasterizer *rasterizer,
 
   for (i= 0; i < count; i ++)
   {
-    float z_recip = (zi!=0) * (1.0/zi);
-    int u = xi * z_recip;
-    int v = yi * z_recip;
+    float z_recip = (zi!=0) * (1.0f/zi);
+    int u = (int)(xi * z_recip);
+    int v = (int)(yi * z_recip);
     if ( u  <= 0 || v  <= 0 || u+1 >= bwidth-1 || v+1 >= bheight-1)
     {
       *((uint32_t*)(rgba))= 0;
@@ -9760,10 +10877,10 @@ ctx_fragment_image_rgba8_RGBA8_bi_generic (CtxRasterizer *rasterizer,
 
   while (i < count)
   {
-    float zr = (zi!=0)*(1.0/zi) * 256;
-    int du = xi * zr;
+    float zr = (zi!=0)*(1.0f/zi) * 256;
+    int du = (int)(xi * zr);
     int u = du >> 8;
-    int dv = yi * zr;
+    int dv = (int)(yi * zr);
     int v = dv >> 8;
     if (CTX_UNLIKELY(u < 0 || v < 0 || u+1 >= bwidth || v+1 >=bheight)) // default to next sample down and 
to right
     {
@@ -9875,8 +10992,8 @@ ctx_fragment_image_yuv420_RGBA8_nearest (CtxRasterizer *rasterizer,
 
     for (; i < count; i ++)
     {
-      int u = x;
-      int v = y;
+      int u = (int)x;
+      int v = (int)y;
       if ((u < 0 || v < 0 || u >= bwidth || v >= bheight))
       {
         *((uint32_t*)(rgba))= 0;
@@ -9901,10 +11018,10 @@ ctx_fragment_image_yuv420_RGBA8_nearest (CtxRasterizer *rasterizer,
 
     // XXX this is incorrect- but fixes some bug!
     int ix = 65536;//x * 65536;
-    int iy = y * 65536;
+    int iy = (int)(y * 65536);
 
-    int ideltax = dx * 65536;
-    int ideltay = dy * 65536;
+    int ideltax = (int)(dx * 65536);
+    int ideltay = (int)(dy * 65536);
 
     if (ideltay == 0)
     {
@@ -9987,7 +11104,7 @@ CTX_DECLARE_SWAP_RED_GREEN_FRAGMENT(ctx_fragment_image_rgba8_RGBA8_bi_scale)
 CTX_DECLARE_SWAP_RED_GREEN_FRAGMENT(ctx_fragment_image_rgba8_RGBA8_bi_affine)
 CTX_DECLARE_SWAP_RED_GREEN_FRAGMENT(ctx_fragment_image_rgba8_RGBA8_bi_generic)
 
-static void
+static inline void
 ctx_fragment_image_rgba8_RGBA8 (CtxRasterizer *rasterizer,
                                 float x, float y, float z,
                                 void *out, int count, float dx, float dy, float dz)
@@ -10046,8 +11163,8 @@ ctx_fragment_image_gray1_RGBA8 (CtxRasterizer *rasterizer, float x, float y, flo
   CtxBuffer *buffer = g->texture.buffer;
   for (int i = 0; i < count; i ++)
   {
-  int u = x;
-  int v = y;
+  int u = (int)x;
+  int v = (int)y;
   if ( u < 0 || v < 0 ||
        u >= buffer->width ||
        v >= buffer->height)
@@ -10085,7 +11202,7 @@ ctx_fragment_radial_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y,
   CtxSource *g = &rasterizer->state->gstate.source_fill;
 #if CTX_DITHER
   int scan = rasterizer->scanline / CTX_FULL_AA;
-  int ox = x;
+  int ox = (int)x;
 #endif
   for (int i = 0; i <  count; i ++)
   {
@@ -10150,7 +11267,7 @@ ctx_fragment_linear_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y,
   int dither_red_blue = rasterizer->format->dither_red_blue;
   int dither_green = rasterizer->format->dither_green;
   int scan = rasterizer->scanline / CTX_FULL_AA;
-  int ox = x;
+  int ox = (int)x;
 #endif
 
   u0 *= linear_gradient_dx;
@@ -10159,8 +11276,8 @@ ctx_fragment_linear_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y,
   vd *= linear_gradient_dy;
 
 #if CTX_GRADIENT_CACHE
-  int vv = ((u0 + v0) - linear_gradient_start) * (rasterizer->gradient_cache_elements-1) * 256;
-  int ud_plus_vd = (ud + vd) * (rasterizer->gradient_cache_elements-1) * 256;
+  int vv = (int)(((u0 + v0) - linear_gradient_start) * (rasterizer->gradient_cache_elements-1) * 256);
+  int ud_plus_vd = (int)((ud + vd) * (rasterizer->gradient_cache_elements-1) * 256);
 #else
   float vv = ((u0 + v0) - linear_gradient_start);
   float ud_plus_vd = (ud + vd);
@@ -10260,7 +11377,7 @@ ctx_fragment_color_RGBAF (CtxRasterizer *rasterizer, float x, float y, float z,
 static void ctx_fragment_image_RGBAF (CtxRasterizer *rasterizer, float x, float y, float z, void *out, int 
count, float dx, float dy, float dz)
 {
   float *outf = (float *) out;
-  uint8_t rgba[4];
+  uint8_t rgba[4 * count];
   CtxSource *g = &rasterizer->state->gstate.source_fill;
   CtxBuffer *buffer = g->texture.buffer->color_managed?g->texture.buffer->color_managed:g->texture.buffer;
   switch (buffer->format->bpp)
@@ -10519,7 +11636,7 @@ ctx_init_uv (CtxRasterizer *rasterizer,
   *wd = transform->m[2][0];
 }
 
-static void
+static inline void
 ctx_u8_copy_normal (int components, CTX_COMPOSITE_ARGUMENTS)
 {
   if (CTX_UNLIKELY(rasterizer->fragment))
@@ -10647,7 +11764,7 @@ ctx_porter_duff_factors(mode, foo, bar)\
   }\
 }
 
-static void
+static inline void
 ctx_u8_source_over_normal_color (int components,
                                  CtxRasterizer         *rasterizer,
                                  uint8_t * __restrict__ dst,
@@ -10661,15 +11778,14 @@ ctx_u8_source_over_normal_color (int components,
 
   while (count--)
   {
+    uint8_t cov = *coverage++;
     for (int c = 0; c < components; c++)
-      //dst[c] =  ((tsrc[c] * *coverage)>>8) + (dst[c] * (((65536)-(tsrc[components-1] * *coverage)))>>16);
-      dst[c] =  ((((tsrc[c] * *coverage)) + (dst[c] * (((255)-(((255+(tsrc[components-1] * 
*coverage))>>8))))))>>8);
-    coverage ++;
+      dst[c] =  ((((tsrc[c] * cov)) + (dst[c] * (((((255+(tsrc[components-1] * cov))>>8))^255 ))))>>8);
     dst+=components;
   }
 }
 
-static void
+static inline void
 ctx_u8_source_copy_normal_color (int components, CTX_COMPOSITE_ARGUMENTS)
 {
   while (count--)
@@ -10945,7 +12061,7 @@ ctx_u8_blend_define_seperable(soft_light,
     if (b[c] <= 255/4)
       d = (((16 * b[c] - 12 * 255)/255 * b[c] + 4 * 255) * b[c])/255;
     else
-      d = ctx_sqrtf(b[c]/255.0) * 255.4;
+      d = (int)(ctx_sqrtf(b[c]/255.0f) * 255.4f);
     blended[c] = (b[c] + (2 * s[c] - 255) * (d - b[c]))/255;
   }
 )
@@ -10976,7 +12092,7 @@ static int ctx_int_get_lum (int components, int *c)
   {
     case 3:
     case 4:
-            return CTX_CSS_RGB_TO_LUMINANCE(c);
+            return (int)(CTX_CSS_RGB_TO_LUMINANCE(c));
     case 1:
     case 2:
             return c[0];
@@ -11000,7 +12116,7 @@ static int ctx_u8_get_lum (int components, uint8_t *c)
   {
     case 3:
     case 4:
-            return CTX_CSS_RGB_TO_LUMINANCE(c);
+            return (int)(CTX_CSS_RGB_TO_LUMINANCE(c));
     case 1:
     case 2:
             return c[0];
@@ -11351,7 +12467,7 @@ ctx_u8_porter_duff(RGBA8, 4,image,           ctx_fragment_image_RGBA8,
 #endif
 
 
-static void
+static inline void
 ctx_RGBA8_nop (CTX_COMPOSITE_ARGUMENTS)
 {
 }
@@ -11361,10 +12477,12 @@ static inline void
 ctx_setup_native_color (CtxRasterizer *rasterizer)
 {
   if (rasterizer->state->gstate.source_fill.type == CTX_SOURCE_COLOR)
+  {
     rasterizer->format->from_comp (rasterizer, 0,
       &rasterizer->color[0],
       &rasterizer->color_native,
       1);
+  }
 }
 
 static void
@@ -11530,7 +12648,7 @@ ctx_setup_RGBA8 (CtxRasterizer *rasterizer)
 }
 
 
-static void
+static inline void
 ctx_setup_RGB (CtxRasterizer *rasterizer)
 {
   ctx_setup_RGBA8 (rasterizer);
@@ -11539,6 +12657,24 @@ ctx_setup_RGB (CtxRasterizer *rasterizer)
   rasterizer->comp = CTX_COV_PATH_FALLBACK;
 }
 
+
+#if CTX_ENABLE_CBRLE
+static void
+ctx_setup_CBRLE (CtxRasterizer *rasterizer)
+{
+  ctx_setup_RGBA8 (rasterizer);
+  //ctx_setup_native_color (rasterizer);
+
+#if 0
+  if (rasterizer->comp == CTX_COV_PATH_RGBA8_COPY)
+    rasterizer->comp = CTX_COV_PATH_CBRLE_COPY;
+  else
+#endif
+    rasterizer->comp = CTX_COV_PATH_FALLBACK;
+}
+#endif
+
+#if CTX_ENABLE_RGB332
 static void
 ctx_setup_RGB332 (CtxRasterizer *rasterizer)
 {
@@ -11550,7 +12686,9 @@ ctx_setup_RGB332 (CtxRasterizer *rasterizer)
   else
     rasterizer->comp = CTX_COV_PATH_FALLBACK;
 }
+#endif
 
+#if CTX_ENABLE_RGB565
 static void
 ctx_setup_RGB565 (CtxRasterizer *rasterizer)
 {
@@ -11562,7 +12700,9 @@ ctx_setup_RGB565 (CtxRasterizer *rasterizer)
   else
     rasterizer->comp = CTX_COV_PATH_FALLBACK;
 }
+#endif
 
+#if CTX_ENABLE_RGB8
 static void
 ctx_setup_RGB8 (CtxRasterizer *rasterizer)
 {
@@ -11574,6 +12714,7 @@ ctx_setup_RGB8 (CtxRasterizer *rasterizer)
   else
     rasterizer->comp = CTX_COV_PATH_FALLBACK;
 }
+#endif
 
 static void
 ctx_composite_convert (CTX_COMPOSITE_ARGUMENTS)
@@ -11585,7 +12726,7 @@ ctx_composite_convert (CTX_COMPOSITE_ARGUMENTS)
 }
 
 #if CTX_ENABLE_FLOAT
-static void
+static inline void
 ctx_float_copy_normal (int components, CTX_COMPOSITE_ARGUMENTS)
 {
   float *dstf = (float*)dst;
@@ -11601,13 +12742,13 @@ ctx_float_copy_normal (int components, CTX_COMPOSITE_ARGUMENTS)
     uint8_t cov = *coverage;
     float covf = ctx_u8_to_float (cov);
     for (int c = 0; c < components; c++)
-      dstf[c] = dstf[c]*(1.0-covf) + srcf[c]*covf;
+      dstf[c] = dstf[c]*(1.0f-covf) + srcf[c]*covf;
     dstf += components;
     coverage ++;
   }
 }
 
-static void
+static inline void
 ctx_float_clear_normal (int components, CTX_COMPOSITE_ARGUMENTS)
 {
   float *dstf = (float*)dst;
@@ -11638,7 +12779,7 @@ ctx_float_clear_normal (int components, CTX_COMPOSITE_ARGUMENTS)
     }
     else
     {
-      float ralpha = 1.0 - ctx_u8_to_float (cov);
+      float ralpha = 1.0f - ctx_u8_to_float (cov);
       for (int c = 0; c < components; c++)
         { dstf[c] = (dstf[c] * ralpha); }
     }
@@ -11666,7 +12807,7 @@ ctx_float_source_over_normal_color (int components, CTX_COMPOSITE_ARGUMENTS)
   }
 }
 
-static void
+static inline void
 ctx_float_source_copy_normal_color (int components, CTX_COMPOSITE_ARGUMENTS)
 {
   float *dstf = (float*)dst;
@@ -12310,7 +13451,7 @@ ctx_fragment_linear_gradient_GRAYAF (CtxRasterizer *rasterizer, float x, float y
   float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
                 g->linear_gradient.length) -
               g->linear_gradient.start) * (g->linear_gradient.rdelta);
-  ctx_fragment_gradient_1d_RGBAF (rasterizer, v, 1.0, rgba);
+  ctx_fragment_gradient_1d_RGBAF (rasterizer, v, 1.0f, rgba);
   ((float*)out)[0] = ctx_float_color_rgb_to_gray (rasterizer->state, rgba);
   ((float*)out)[1] = rgba[3];
      out = ((float*)(out)) + 2;
@@ -12357,8 +13498,8 @@ ctx_fragment_color_GRAYAF (CtxRasterizer *rasterizer, float x, float y, float z,
 
 static void ctx_fragment_image_GRAYAF (CtxRasterizer *rasterizer, float x, float y, float z, void *out, int 
count, float dx, float dy, float dz)
 {
-  uint8_t rgba[4];
-  float rgbaf[4];
+  uint8_t rgba[4*count];
+  float rgbaf[4*count];
   CtxSource *g = &rasterizer->state->gstate.source_fill;
   CtxBuffer *buffer = g->texture.buffer->color_managed?g->texture.buffer->color_managed:g->texture.buffer;
   switch (buffer->format->bpp)
@@ -12570,7 +13711,7 @@ ctx_composite_BGRA8 (CTX_COMPOSITE_ARGUMENTS)
 
 
 #endif
-static void
+static inline void
 ctx_composite_direct (CTX_COMPOSITE_ARGUMENTS)
 {
   // for better performance, this could be done without a pre/post conversion,
@@ -12874,10 +14015,10 @@ ctx_CMYKAF_to_CMYK8 (CtxRasterizer *rasterizer, float *src, uint8_t *dst, int co
           y *= recip;
           k *= recip;
         }
-      c = 1.0 - c;
-      m = 1.0 - m;
-      y = 1.0 - y;
-      k = 1.0 - k;
+      c = 1.0f - c;
+      m = 1.0f - m;
+      y = 1.0f - y;
+      k = 1.0f - k;
       dst[0] = ctx_float_to_u8 (c);
       dst[1] = ctx_float_to_u8 (m);
       dst[2] = ctx_float_to_u8 (y);
@@ -12933,17 +14074,37 @@ ctx_RGBA8_to_RGB8 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *
 
 #if CTX_NATIVE_GRAYA8
 inline static void
-ctx_GRAY1_to_GRAYA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
+ctx_GRAY1_to_GRAYA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *graya, int count)
 {
   const uint8_t *pixel = (uint8_t *) buf;
   while (count--)
     {
       int bitno = x&7;
-      rgba[0] = 255 * ((*pixel) & (1<<bitno));
-      rgba[1] = 255;
+      if (bitno == 0 && count >= 7)
+      {
+        if (*pixel == 0)
+        {
+          for (int i = 0; i < 8; i++)
+          {
+            *graya++ = 0; *graya++ = 255;
+          }
+          x+=8; count-=7; pixel++;
+          continue;
+        }
+        else if (*pixel == 0xff)
+        {
+          for (int i = 0; i < 8 * 2; i++)
+          {
+            *graya++ = 255;
+          }
+          x+=8; count-=7; pixel++;
+          continue;
+        }
+      }
+      *graya++ = 255 * ((*pixel) & (1<<bitno));
+      *graya++ = 255;
       pixel+= (bitno ==7);
       x++;
-      rgba +=2;
     }
 }
 
@@ -12971,13 +14132,83 @@ inline static void
 ctx_GRAY1_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
 {
   const uint8_t *pixel = (uint8_t *) buf;
+  uint32_t *dst = (uint32_t*)rgba;
   while (count--)
     {
       int bitno = x&7;
-      *((uint32_t*)(rgba))=0xff000000 + 0x00ffffff * ((*pixel & (1<< bitno ) )!=0);
+
+      if ((bitno) == 0 && count >=7)
+      {
+        /* special case some bit patterns when decoding */
+        if (*pixel == 0)
+        {
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          x+=8; count-=7; pixel++;
+          continue;
+        }
+        else if (*pixel == 0xff)
+        {
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          x+=8; count-=7; pixel++;
+          continue;
+        }
+        else if (*pixel == 0x0f)
+        {
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          x+=8; count-=7; pixel++;
+          continue;
+        }
+        else if (*pixel == 0xfc)
+        {
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          x+=8; count-=7; pixel++;
+          continue;
+        }
+        else if (*pixel == 0x3f)
+        {
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          x+=8; count-=7; pixel++;
+          continue;
+        }
+      }
+      *dst++=0xff000000 + 0x00ffffff * ((*pixel & (1<< bitno ) )!=0);
       pixel += (bitno ==7);
       x++;
-      rgba +=4;
     }
 }
 
@@ -13011,8 +14242,7 @@ ctx_GRAY2_to_GRAYA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t
   const uint8_t *pixel = (uint8_t *) buf;
   while (count--)
     {
-      int val = (*pixel & (3 << ( (x & 3) <<1) ) ) >> ( (x&3) <<1);
-      val <<= 6;
+      uint8_t val = (((*pixel) >> ( (x&3) <<1)) & 3) * 85;
       rgba[0] = val;
       rgba[1] = 255;
       if ( (x&3) ==3)
@@ -13029,9 +14259,9 @@ ctx_GRAYA8_to_GRAY2 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void
   while (count--)
     {
       int val = rgba[0];
-      val >>= 6;
-      *pixel = *pixel & (~ (3 << ( (x&3) <<1) ) );
-      *pixel = *pixel | ( (val << ( (x&3) <<1) ) );
+      val = ctx_sadd8 (val, 40) >> 6;
+      *pixel = (*pixel & (~ (3 << ( (x&3) <<1) ) ))
+                      | ( (val << ( (x&3) <<1) ) );
       if ( (x&3) ==3)
         { pixel+=1; }
       x++;
@@ -13044,18 +14274,85 @@ inline static void
 ctx_GRAY2_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
 {
   const uint8_t *pixel = (uint8_t *) buf;
+  uint32_t *dst = (uint32_t*)rgba;
   while (count--)
     {
-      int val = (*pixel & (3 << ( (x & 3) <<1) ) ) >> ( (x&3) <<1);
-      val <<= 6;
-      rgba[0] = val;
-      rgba[1] = val;
-      rgba[2] = val;
-      rgba[3] = 255;
-      if ( (x&3) ==3)
-        { pixel+=1; }
-      x++;
-      rgba +=4;
+      int bitno = x & 3;
+      if ((bitno) == 0 && count >=3)
+      {
+        /* special case some bit patterns when decoding */
+        if (*pixel == 0)
+        {
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          x+=4; count-=3; pixel++;
+          continue;
+        }
+        else if (*pixel == 0xff)
+        {
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          x+=4; count-=3; pixel++;
+          continue;
+        }
+        else if (*pixel == 0x55)
+        {
+          *dst++ = 0xff555555;
+          *dst++ = 0xff555555;
+          *dst++ = 0xff555555;
+          *dst++ = 0xff555555;
+          x+=4; count-=3; pixel++;
+          continue;
+        }
+        else if (*pixel == 0xaa)
+        {
+          *dst++ = 0xffaaaaaa;
+          *dst++ = 0xffaaaaaa;
+          *dst++ = 0xffaaaaaa;
+          *dst++ = 0xffaaaaaa;
+          x+=4; count-=3; pixel++;
+          continue;
+        }
+        else if (*pixel == 0x0f)
+        {
+          *dst++ = 0xff000000;
+          *dst++ = 0xff000000;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          x+=4; count-=3; pixel++;
+          continue;
+        }
+        else if (*pixel == 0xfc)
+        {
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xff000000;
+          x+=4; count-=3; pixel++;
+          continue;
+        }
+        else if (*pixel == 0x3f)
+        {
+          *dst++ = 0xff000000;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          *dst++ = 0xffffffff;
+          x+=4; count-=3; pixel++;
+          continue;
+        }
+      }
+      {
+        uint8_t val = (((*pixel) >> ( (bitno) <<1)) & 3) * 85;
+        *dst = val + val * 256u + val * 256u * 256u + 255u * 256u * 256u * 256u;
+        if (bitno==3)
+          { pixel+=1; }
+        x++;
+        dst++;
+      }
     }
 }
 
@@ -13067,8 +14364,8 @@ ctx_RGBA8_to_GRAY2 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void
     {
       int val = ctx_u8_color_rgb_to_gray (rasterizer->state, rgba);
       val >>= 6;
-      *pixel = *pixel & (~ (3 << ( (x&3) <<1) ) );
-      *pixel = *pixel | ( (val << ( (x&3) <<1) ) );
+      *pixel = (*pixel & (~ (3 << ((x&3) <<1) ) ))
+                      | ( (val << ((x&3) <<1) ) );
       if ( (x&3) ==3)
         { pixel+=1; }
       x++;
@@ -13253,7 +14550,7 @@ ctx_fragment_linear_gradient_GRAYA8 (CtxRasterizer *rasterizer, float x, float y
         uint8_t *dst = (uint8_t*)out;
 #if CTX_DITHER
   int scan = rasterizer->scanline / CTX_FULL_AA;
-  int ox = x;
+  int ox = (int)x;
 #endif
   for (int i = 0; i < count;i ++)
   {
@@ -13262,7 +14559,7 @@ ctx_fragment_linear_gradient_GRAYA8 (CtxRasterizer *rasterizer, float x, float y
               g->linear_gradient.start) * (g->linear_gradient.rdelta);
   {
     uint8_t rgba[4];
-    ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 1.0, rgba);
+    ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 1.0f, rgba);
     ctx_rgba_to_graya_u8 (rasterizer->state, rgba, dst);
    
   }
@@ -13283,7 +14580,7 @@ ctx_fragment_radial_gradient_GRAYA8 (CtxRasterizer *rasterizer, float x, float y
   uint8_t *dst = (uint8_t*)out;
 #if CTX_DITHER
   int scan = rasterizer->scanline / CTX_FULL_AA;
-  int ox = x;
+  int ox = (int)x;
 #endif
 
   for (int i = 0; i < count;i ++)
@@ -13373,7 +14670,21 @@ ctx_GRAYA8_clear_normal (CTX_COMPOSITE_ARGUMENTS)
 static void
 ctx_GRAYA8_source_over_normal_color (CTX_COMPOSITE_ARGUMENTS)
 {
+#if 0
   ctx_u8_source_over_normal_color (2, rasterizer, dst, rasterizer->color, x0, coverage, count);
+#else
+  uint8_t tsrc[5];
+  *((uint32_t*)tsrc) = *((uint32_t*)src);
+
+  while (count--)
+  {
+    uint32_t cov = *coverage++;
+    uint32_t common =(((((255+(tsrc[1] * cov))>>8))^255 ));
+    dst[0] =  ((((tsrc[0] * cov)) + (dst[0] * common ))>>8);
+    dst[1] =  ((((tsrc[1] * cov)) + (dst[1] * common ))>>8);
+    dst+=2;
+  }
+#endif
 }
 
 static void
@@ -13482,20 +14793,31 @@ ctx_setup_GRAYA8 (CtxRasterizer *rasterizer)
   ctx_setup_apply_coverage (rasterizer);
 }
 
+#if CTX_ENABLE_GRAY4
 static void
 ctx_setup_GRAY4 (CtxRasterizer *rasterizer)
 {
   ctx_setup_GRAYA8 (rasterizer);
+  if (rasterizer->comp == CTX_COV_PATH_GRAYA8_COPY)
+    rasterizer->comp = CTX_COV_PATH_GRAY4_COPY;
+  else
   rasterizer->comp = CTX_COV_PATH_FALLBACK;
 }
+#endif
 
+#if CTX_ENABLE_GRAY2
 static void
 ctx_setup_GRAY2 (CtxRasterizer *rasterizer)
 {
   ctx_setup_GRAYA8 (rasterizer);
-  rasterizer->comp = CTX_COV_PATH_FALLBACK;
+  if (rasterizer->comp == CTX_COV_PATH_GRAYA8_COPY)
+    rasterizer->comp = CTX_COV_PATH_GRAY2_COPY;
+  else
+    rasterizer->comp = CTX_COV_PATH_FALLBACK;
 }
+#endif
 
+#if CTX_ENABLE_GRAY1
 static void
 ctx_setup_GRAY1 (CtxRasterizer *rasterizer)
 {
@@ -13505,6 +14827,7 @@ ctx_setup_GRAY1 (CtxRasterizer *rasterizer)
   else
     rasterizer->comp = CTX_COV_PATH_FALLBACK;
 }
+#endif
 
 static void
 ctx_setup_GRAY8 (CtxRasterizer *rasterizer)
@@ -13526,19 +14849,9 @@ ctx_332_unpack (uint8_t pixel,
                 uint8_t *green,
                 uint8_t *blue)
 {
-  uint32_t b = (pixel & 3) <<6;
-  uint32_t g = ( (pixel >> 2) & 7) <<5;
-  uint32_t r = ( (pixel >> 5) & 7) <<5;
-
-#if 1
-  *blue  = (b > 224) * 255 + (b <= 224) * b;
-  *green = (g > 224) * 255 + (g <= 224) * g;
-  *red   = (r > 224) * 255 + (r <= 224) * r;
-#else
-  *blue  =  b;
-  *green =  g;
-  *red   =  r;
-#endif
+  *green = (((pixel >> 2) & 7)*255)/7;
+  *red   = (((pixel >> 5) & 7)*255)/7;
+  *blue  = ((((pixel & 3) << 1) | ((pixel >> 2) & 1))*255)/7;
 }
 
 static inline uint8_t
@@ -13546,10 +14859,9 @@ ctx_332_pack (uint8_t red,
               uint8_t green,
               uint8_t blue)
 {
-  uint8_t c  = (red >> 5) << 5;
-  c |= (green >> 5) << 2;
-  c |= (blue >> 6);
-  return c;
+  return ((ctx_sadd8(red,15) >> 5) << 5)
+        |((ctx_sadd8(green,15) >> 5) << 2)
+        |(ctx_sadd8(blue,15) >> 6);
 }
 #if CTX_ENABLE_RGB332
 
@@ -13569,7 +14881,7 @@ ctx_332_to_888 (uint8_t in)
                   &rgba[0],
                   &rgba[1],
                   &rgba[2]);
-  //rgba[3] = 255;
+  rgba[3] = 255;
   return ret;
 }
 
@@ -13611,43 +14923,28 @@ ctx_RGBA8_to_RGB332 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void
 static void
 ctx_composite_RGB332 (CTX_COMPOSITE_ARGUMENTS)
 {
+#if 1
   if (CTX_LIKELY(rasterizer->comp_op == ctx_RGBA8_source_over_normal_color))
   {
     uint32_t si_ga = ((uint32_t*)rasterizer->color)[1];
     uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
     uint32_t si_a  = si_ga >> 16;
 
-    uint32_t si_gaf = (((uint32_t*)rasterizer->color)[1] << 8) + 255;
-    uint32_t si_rbf = (((uint32_t*)rasterizer->color)[2] << 8) + 255;
-
     while (count--)
     {
-      if (CTX_LIKELY(*coverage == 255))
-      {
-        uint32_t rcov  = 255-*coverage++;
-        uint32_t di    = ctx_332_to_888 (*((uint8_t*)dst));
-        uint32_t di_ga = ((di & 0xff00ff00) >> 8);
-        uint32_t di_rb = (di & 0x00ff00ff);
-        *((uint16_t*)(dst)) =
-        ctx_888_to_332((((si_rbf + di_rb * rcov) & 0xff00ff00) >> 8)  |
-         (((si_gaf) + di_ga * rcov) & 0xff00ff00));
-         dst+=1;
-      }
-      else
-      {
-        uint32_t cov   = *coverage++;
-        uint32_t rcov  = (((255+si_a * cov)>>8))^255;
-        uint32_t di    = ctx_332_to_888 (*((uint8_t*)dst));
-        uint32_t di_ga = ((di & 0xff00ff00) >> 8);
-        uint32_t di_rb = (di & 0x00ff00ff);
-        *((uint16_t*)(dst)) =
-        ctx_888_to_332((((si_rb * cov + 0xff00ff + di_rb * rcov) & 0xff00ff00) >> 8)  |
-         ((si_ga * cov + 0xff00ff + di_ga * rcov) & 0xff00ff00));
-         dst+=1;
-      }
+      uint32_t cov   = *coverage++;
+      uint32_t rcov  = (((255+si_a * cov)>>8))^255;
+      uint32_t di    = ctx_332_to_888 (*((uint8_t*)dst));
+      uint32_t di_ga = ((di & 0xff00ff00) >> 8);
+      uint32_t di_rb = (di & 0x00ff00ff);
+      *((uint8_t*)(dst)) =
+      ctx_888_to_332((((si_rb * cov + 0xff00ff + di_rb * rcov) & 0xff00ff00) >> 8)  |
+       ((si_ga * cov + 0xff00ff + di_ga * rcov) & 0xff00ff00));
+       dst+=1;
     }
     return;
   }
+#endif
   uint8_t pixels[count * 4];
   ctx_RGB332_to_RGBA8 (rasterizer, x0, dst, &pixels[0], count);
   rasterizer->comp_op (rasterizer, &pixels[0], rasterizer->color, x0, coverage, count);
@@ -13656,11 +14953,20 @@ ctx_composite_RGB332 (CTX_COMPOSITE_ARGUMENTS)
 
 #endif
 static inline uint16_t
-ctx_565_pack (const uint8_t  red,
-              const uint8_t  green,
-              const uint8_t  blue,
+ctx_565_pack (uint8_t  red,
+              uint8_t  green,
+              uint8_t  blue,
               const int      byteswap)
 {
+#if 0
+  // is this extra precision warranted?
+  // for 332 it gives more pure white..
+  // it might be the case also for generic 565
+  red = ctx_sadd8 (red, 4);
+  green = ctx_sadd8 (green, 3);
+  blue = ctx_sadd8 (blue, 4);
+#endif
+
   uint32_t c = (red >> 3) << 11;
   c |= (green >> 2) << 5;
   c |= blue >> 3;
@@ -13668,6 +14974,93 @@ ctx_565_pack (const uint8_t  red,
     { return (c>>8) | (c<<8); } /* swap bytes */
   return c;
 }
+
+ // ARGB - 
+#if CTX_ENABLE_CBRLE
+
+
+static inline void
+ctx_RGBA8_to_CBRLE (CtxRasterizer *rasterizer, int u, const uint8_t *rgba, void *buf, int count)
+{
+  uint8_t *pixel = (uint8_t *) buf;
+  int width = rasterizer->blit_width;
+  int format_bits = rasterizer->format->bpp;
+  pixel-= (u *format_bits)/8;
+  int size = (width * format_bits)/8;
+
+  ctx_CBRLE_compress (&rgba[-u*4], pixel, width, size, u, count, CBRLE_MODE_SET, NULL, 1);
+}
+
+static inline void
+ctx_CBRLE_to_RGBA8 (CtxRasterizer *rasterizer, int u, const void *buf, uint8_t *rgba, int count)
+{
+  const uint8_t *pixel = (uint8_t *) buf;
+  int width = rasterizer->blit_width;
+  uint8_t temp[width * 4];
+  int format_bits = rasterizer->format->bpp;
+  pixel-= (u *format_bits)/8;
+  int size = (width * format_bits)/8;
+
+  _ctx_CBRLE_decompress (pixel, &temp[0], width, size, u, ctx_mini(count, width-u));//count);
+
+  uint32_t *src = (uint32_t*)&temp[4*u];
+  while (count--)
+  {
+      ((uint32_t*)rgba)[0] = *src++;
+      rgba += 4;
+  }
+}
+
+
+static void
+ctx_composite_CBRLE (CTX_COMPOSITE_ARGUMENTS)
+{
+  uint8_t *pixel = (uint8_t*)dst;
+  int format_bits = rasterizer->format->bpp;
+  pixel-= (x0 *format_bits)/8;
+
+#if 0
+  if (pixel[0] || pixel[1])
+  {
+
+  if (CTX_LIKELY(rasterizer->comp_op == ctx_RGBA8_source_over_normal_color))
+  {
+    int width = rasterizer->blit_width;
+    int size = (width * format_bits)/8;
+    ctx_CBRLE_compress (rasterizer->color, pixel, width, size, x0, count,
+                         CBRLE_MODE_OVER, coverage, 1);
+    return;
+  }
+  else if (CTX_LIKELY(rasterizer->comp_op == ctx_RGBA8_source_copy_normal_color) &&
+           getenv("CTX_CBRLE_COPY"))
+  {
+    int width = rasterizer->blit_width;
+    int size = (width * format_bits)/8;
+    ctx_CBRLE_compress (rasterizer->color, pixel, width, size, x0, count, 
+                         CBRLE_MODE_COPY, coverage, 1);
+    return;
+  }
+  }
+
+#endif
+
+  uint8_t pixels[count * 4];
+  ctx_CBRLE_to_RGBA8 (rasterizer, x0, dst, &pixels[0], count);
+  rasterizer->comp_op (rasterizer, &pixels[0], rasterizer->color, x0, coverage, count);
+  ctx_RGBA8_to_CBRLE (rasterizer, x0, &pixels[0], dst, count);
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
 #if CTX_ENABLE_RGB565 | CTX_ENABLE_RGB565_BYTESWAPPED
 
 static inline void
@@ -13793,24 +15186,8 @@ ctx_composite_RGB565 (CTX_COMPOSITE_ARGUMENTS)
     uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
     uint32_t si_a  = si_ga >> 16;
 
-    uint32_t si_gaf = (((uint32_t*)rasterizer->color)[1] << 8) + 255;
-    uint32_t si_rbf = (((uint32_t*)rasterizer->color)[2] << 8) + 255;
-
     while (count--)
     {
-      if (CTX_LIKELY(*coverage == 255)) // not vectorizable but we probably
-      {                                 // want to keep it like this
-        uint32_t rcov  = 255-*coverage++;
-        uint32_t di    = ctx_565_to_888 (*((uint16_t*)dst), 0);
-        uint32_t di_ga = ((di & 0xff00ff00) >> 8);
-        uint32_t di_rb = (di & 0x00ff00ff);
-        *((uint16_t*)(dst)) =
-        ctx_888_to_565((((si_rbf + di_rb * rcov) & 0xff00ff00) >> 8)  |
-         (((si_gaf) + di_ga * rcov) & 0xff00ff00), 0);
-         dst+=2;
-      }
-      else
-      {
         uint32_t cov   = *coverage++;
         uint32_t rcov  = (((255+si_a * cov)>>8))^255;
         uint32_t di    = ctx_565_to_888 (*((uint16_t*)dst), 0);
@@ -13820,7 +15197,6 @@ ctx_composite_RGB565 (CTX_COMPOSITE_ARGUMENTS)
         ctx_888_to_565((((si_rb * cov + 0xff00ff + di_rb * rcov) & 0xff00ff00) >> 8)  |
          ((si_ga * cov + 0xff00ff + di_ga * rcov) & 0xff00ff00), 0);
          dst+=2;
-      }
     }
     return;
   }
@@ -13880,34 +15256,17 @@ ctx_composite_RGB565_BS (CTX_COMPOSITE_ARGUMENTS)
     uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
     uint32_t si_a  = si_ga >> 16;
 
-    uint32_t si_gaf = (((uint32_t*)rasterizer->color)[1] << 8) + 255;
-    uint32_t si_rbf = (((uint32_t*)rasterizer->color)[2] << 8) + 255;
-
     while (count--)
     {
-      if (CTX_LIKELY(*coverage == 255))
-      {
-        uint32_t rcov  = 255-*coverage++;
-        uint32_t di    = ctx_565_to_888 (*((uint16_t*)dst), 1);
-        uint32_t di_ga = ((di & 0xff00ff00) >> 8);
-        uint32_t di_rb = (di & 0x00ff00ff);
-        *((uint16_t*)(dst)) =
-        ctx_888_to_565((((si_rbf + di_rb * rcov) & 0xff00ff00) >> 8)  |
-         (((si_gaf) + di_ga * rcov) & 0xff00ff00), 1);
-         dst+=2;
-      }
-      else
-      {
-        uint32_t cov   = *coverage++;
-        uint32_t rcov  = (((255+si_a * cov)>>8))^255;
-        uint32_t di    = ctx_565_to_888 (*((uint16_t*)dst), 1);
-        uint32_t di_ga = ((di & 0xff00ff00) >> 8);
-        uint32_t di_rb = (di & 0x00ff00ff);
-        *((uint16_t*)(dst)) =
-        ctx_888_to_565((((si_rb * cov + 0xff00ff + di_rb * rcov) & 0xff00ff00) >> 8)  |
-         ((si_ga * cov + 0xff00ff + di_ga * rcov) & 0xff00ff00), 1);
-         dst+=2;
-      }
+      uint32_t cov   = *coverage++;
+      uint32_t rcov  = (((255+si_a * cov)>>8))^255;
+      uint32_t di    = ctx_565_to_888 (*((uint16_t*)dst), 1);
+      uint32_t di_ga = ((di & 0xff00ff00) >> 8);
+      uint32_t di_rb = (di & 0x00ff00ff);
+      *((uint16_t*)(dst)) =
+      ctx_888_to_565((((si_rb * cov + 0xff00ff + di_rb * rcov) & 0xff00ff00) >> 8)  |
+       ((si_ga * cov + 0xff00ff + di_ga * rcov) & 0xff00ff00), 1);
+       dst+=2;
     }
     return;
   }
@@ -14012,8 +15371,8 @@ static inline void ctx_RGBA8_image_rgba8_RGBA8_bi_scaled_fill_rect (CtxRasterize
   float ud = 0; float vd = 0;
   float w0 = 1; float wd = 0;
   ctx_init_uv (rasterizer, x0, rasterizer->scanline/CTX_FULL_AA,&u0, &v0, &w0, &ud, &vd, &wd);
-  u0-=0.5;
-  v0-=0.5;
+  u0-=0.5f;
+  v0-=0.5f;
 
   uint8_t *dst = ( (uint8_t *) rasterizer->buf);
   int blit_stride = rasterizer->blit_stride;
@@ -14035,10 +15394,10 @@ static inline void ctx_RGBA8_image_rgba8_RGBA8_bi_scaled_fill_rect (CtxRasterize
   uint32_t rb_row[2][width*2];
   //uint32_t ga_row[2][width];
 
-  int32_t row_u = u0 * 65536;
-  int32_t row_v = v0 * 65536;
-  int   ui_delta = ud * 65536;
-  int   vi_delta = vd * 65536;
+  int32_t row_u = (int)(u0 * 65536);
+  int32_t row_v = (int)(v0 * 65536);
+  int   ui_delta = (int)(ud * 65536);
+  int   vi_delta = (int)(vd * 65536);
 
   int iter = 0;
 
@@ -14068,7 +15427,8 @@ static inline void ctx_RGBA8_image_rgba8_RGBA8_bi_scaled_fill_rect (CtxRasterize
           src1 = data + u1 + bwidth * (v);
         }
     
-        ctx_lerp_RGBA8_split (*src0, *src1, ui>>8, &rb_row[!top][xa], &rb_row[!top][xa+1]);
+        ctx_lerp_RGBA8_split (*src0, *src1, ui>>8, &rb_row[!top][xa],
+                                                   &rb_row[!top][xa+1]);
         ui += ui_delta;
         vi += vi_delta;
       }
@@ -14140,8 +15500,8 @@ static inline void ctx_RGBA8_image_rgba8_RGBA8_bi_affine_fill_rect (CtxRasterize
   float ud = 0; float vd = 0;
   float w0 = 1; float wd = 0;
   ctx_init_uv (rasterizer, x0, rasterizer->scanline/CTX_FULL_AA,&u0, &v0, &w0, &ud, &vd, &wd);
-  u0-=0.5;
-  v0-=0.5;
+  u0-=0.5f;
+  v0-=0.5f;
 
   uint8_t *dst = ( (uint8_t *) rasterizer->buf);
   int blit_stride = rasterizer->blit_stride;
@@ -14163,10 +15523,10 @@ static inline void ctx_RGBA8_image_rgba8_RGBA8_bi_affine_fill_rect (CtxRasterize
   uint32_t rb_row[2][width*2];
   //uint32_t ga_row[2][width];
 
-  uint32_t row_u = u0 * 65536;
-  uint32_t row_v = v0 * 65536;
-  int   ui_delta = ud * 65536;
-  int   vi_delta = vd * 65536;
+  uint32_t row_u = (int)(u0 * 65536);
+  uint32_t row_v = (int)(v0 * 65536);
+  int   ui_delta = (int)(ud * 65536);
+  int   vi_delta = (int)(vd * 65536);
 
   int iter = 0;
 
@@ -14243,7 +15603,8 @@ static inline void ctx_RGBA8_image_rgba8_RGBA8_bi_affine_fill_rect (CtxRasterize
                src1 = src0 + 1;
            }
          }
-         ctx_lerp_RGBA8_split (*src0, *src1, ui>>8, &rb_row[top][xa], &rb_row[top][xa+1]);
+         ctx_lerp_RGBA8_split (*src0, *src1, ui>>8, &rb_row[top][xa],
+                                                    &rb_row[top][xa+1]);
          ui += ui_delta;
          vi += vi_delta;
        }
@@ -14751,7 +16112,7 @@ CTX_SIMD_SUFFIX (ctx_composite_fill_rect) (CtxRasterizer *rasterizer,
      (ctx_fmod1f (y1) < 0.01f || ctx_fmod1f(y1) > 0.99f))
   {
     /* best-case scenario axis aligned rectangle */
-    ctx_composite_fill_rect_aligned (rasterizer, x0, y0, x1-1, y1-1, 255);
+    ctx_composite_fill_rect_aligned (rasterizer, (int)x0, (int)y0, (int)(x1-1), (int)(y1-1), 255);
     return;
   }
 
@@ -14763,34 +16124,37 @@ CTX_SIMD_SUFFIX (ctx_composite_fill_rect) (CtxRasterizer *rasterizer,
 
   x0 = ctx_maxf (x0, blit_x);
   y0 = ctx_maxf (y0, blit_y);
-  x1 = ctx_minf (x1, blit_x + blit_width );
-  y1 = ctx_minf (y1, blit_y + blit_height );
+  x1 = ctx_minf (x1, blit_x + blit_width);
+  y1 = ctx_minf (y1, blit_y + blit_height);
 
-  uint8_t left = 255-ctx_fmod1f (x0) * 255;
-  uint8_t top  = 255-ctx_fmod1f (y0) * 255;
-  uint8_t right  = ctx_fmod1f (x1) * 255;
-  uint8_t bottom = ctx_fmod1f (y1) * 255;
+  uint8_t left = (int)(255-ctx_fmod1f (x0) * 255);
+  uint8_t top  = (int)(255-ctx_fmod1f (y0) * 255);
+  uint8_t right  = (int)(ctx_fmod1f (x1) * 255);
+  uint8_t bottom = (int)(ctx_fmod1f (y1) * 255);
 
   x0 = ctx_floorf (x0);
   y0 = ctx_floorf (y0);
-  x1 = ctx_floorf (x1+7/8.0);
-  y1 = ctx_floorf (y1+15/15.0);
+  x1 = ctx_floorf (x1+7/8.0f);
+  y1 = ctx_floorf (y1+15/15.0f);
 
   int has_top    = (top < 255);
   int has_bottom = (bottom <255);
   int has_right  = (right >0);
   int has_left   = (left >0);
 
-  int width = x1 - x0;
+  if (x1 >= blit_x + blit_width) has_right = 0;
+  if (y1 >= blit_y + blit_height) has_bottom = 0;
+
+  int width = (int)(x1 - x0);
 
   if ((width >0))
   {
      uint8_t *dst = ( (uint8_t *) rasterizer->buf);
      uint8_t coverage[width+2];
-     uint32_t x0i = x0+has_left;
-     uint32_t x1i = x1-has_right;
-     uint32_t y0i = y0+has_top;
-     uint32_t y1i = y1-has_bottom;
+     uint32_t x0i = (int)x0+has_left;
+     uint32_t x1i = (int)x1-has_right;
+     uint32_t y0i = (int)y0+has_top;
+     uint32_t y1i = (int)y1-has_bottom;
      dst += (((int)y0) - blit_y) * blit_stride;
      dst += ((int)x0) * rasterizer->format->bpp/8;
 
@@ -14806,18 +16170,18 @@ CTX_SIMD_SUFFIX (ctx_composite_fill_rect) (CtxRasterizer *rasterizer,
        if (has_right)
          coverage[i++]= (top * right + 255) >> 8;
 
-       rasterizer->apply_coverage (rasterizer, dst, rasterizer->color, x0, coverage, width);
+       rasterizer->apply_coverage (rasterizer, dst, rasterizer->color, (int)x0, coverage, width);
        dst += blit_stride;
      }
 
   if (y1-y0-has_top-has_bottom > 0)
   {
     if (has_left)
-      ctx_composite_fill_rect_aligned (rasterizer, x0, y0i,
-                                                   x0, y1i-1, left);
+      ctx_composite_fill_rect_aligned (rasterizer, (int)x0, y0i,
+                                                   (int)x0, y1i-1, left);
     if (has_right)
-      ctx_composite_fill_rect_aligned (rasterizer, x1-1, y0i,
-                                                   x1-1, y1i-1, right);
+      ctx_composite_fill_rect_aligned (rasterizer, (int)x1-1, y0i,
+                                                   (int)x1-1, y1i-1, right);
 
     if (width - has_left - has_right > 0)
       ctx_composite_fill_rect_aligned (rasterizer, x0i,y0i,
@@ -14834,7 +16198,7 @@ CTX_SIMD_SUFFIX (ctx_composite_fill_rect) (CtxRasterizer *rasterizer,
         coverage[i++] = bottom;
       coverage[i++]= (bottom * right + 255) >> 8;
 
-      rasterizer->apply_coverage (rasterizer,dst, rasterizer->color, x0, coverage, width);
+      rasterizer->apply_coverage (rasterizer,dst, rasterizer->color, (int)x0, coverage, width);
     }
   }
 }
@@ -14856,9 +16220,9 @@ CTX_SIMD_SUFFIX(ctx_composite_stroke_rect) (CtxRasterizer *rasterizer,
                            float          line_width)
 {
       float lwmod = ctx_fmod1f (line_width);
-      int lw = ctx_floorf (line_width + 0.5f);
-      int is_compat_even = (lw % 2 == 0) && (lwmod < 0.1); // only even linewidths implemented properly
-      int is_compat_odd = (lw % 2 == 1) && (lwmod < 0.1); // only even linewidths implemented properly
+      int lw = (int)ctx_floorf (line_width + 0.5f);
+      int is_compat_even = (lw % 2 == 0) && (lwmod < 0.1f); // only even linewidths implemented properly
+      int is_compat_odd = (lw % 2 == 1) && (lwmod < 0.1f); // only even linewidths implemented properly
 
       float off_x = 0;
       float off_y = 0;
@@ -14866,7 +16230,7 @@ CTX_SIMD_SUFFIX(ctx_composite_stroke_rect) (CtxRasterizer *rasterizer,
       if (is_compat_odd)
       {
         off_x = 0.5f;
-        off_y = (CTX_FULL_AA/2)*1.0 / (CTX_FULL_AA);
+        off_y = (CTX_FULL_AA/2)*1.0f / (CTX_FULL_AA);
       }
 
       if((is_compat_odd || is_compat_even) &&
@@ -14887,21 +16251,21 @@ CTX_SIMD_SUFFIX(ctx_composite_stroke_rect) (CtxRasterizer *rasterizer,
         }
         /* top */
         ctx_composite_fill_rect_aligned (rasterizer,
-                                         x0-bwb, y0-bwb,
-                                         x1+bw-1, y0+bw-1, 255);
+                                         (int)x0-bwb, (int)y0-bwb,
+                                         (int)x1+bw-1, (int)y0+bw-1, 255);
         /* bottom */
         ctx_composite_fill_rect_aligned (rasterizer,
-                                         x0-bwb, y1-bwb,
-                                         x1-bwb-1, y1+bw-1, 255);
+                                         (int)x0-bwb, (int)y1-bwb,
+                                         (int)x1-bwb-1, (int)y1+bw-1, 255);
 
         /* left */
         ctx_composite_fill_rect_aligned (rasterizer,
-                                         x0-bwb, y0+1,
-                                         x0+bw-1, y1-bwb, 255);
+                                         (int)x0-bwb, (int)y0+1,
+                                         (int)x0+bw-1, (int)y1-bwb, 255);
         /* right */
         ctx_composite_fill_rect_aligned (rasterizer,
-                                         x1-bwb, y0+1,
-                                         x1+bw-1, y1+bw-1, 255);
+                                         (int)x1-bwb, (int)y0+1,
+                                         (int)x1+bw-1, (int)y1+bw-1, 255);
       }
       else
       {
@@ -14965,9 +16329,10 @@ CTX_SIMD_SUFFIX (ctx_composite_setup) (CtxRasterizer *rasterizer)
       _ctx_matrix_multiply (&rasterizer->state->gstate.source_fill.transform,
                             &rasterizer->state->gstate.source_fill.set_transform,
                             &rasterizer->state->gstate.transform);
-
+#if 0
       rasterizer->state->gstate.source_fill.transform_inv =
                            rasterizer->state->gstate.source_fill.transform;
+#endif
       ctx_matrix_invert (&rasterizer->state->gstate.source_fill.transform);
 
 #if 0
@@ -15082,15 +16447,151 @@ CtxPixelFormatInfo CTX_SIMD_SUFFIX(ctx_pixel_formats)[]=
 #endif
 #if CTX_ENABLE_RGB332
   {
-    CTX_FORMAT_RGB332, 3, 8, 4, 10, 12, CTX_FORMAT_RGBA8,
-    ctx_RGB332_to_RGBA8, ctx_RGBA8_to_RGB332,
+    CTX_FORMAT_RGB332, 3, 8, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_RGB332_to_RGBA8,  ctx_RGBA8_to_RGB332,
     ctx_composite_RGB332, ctx_setup_RGB332,
   },
 #endif
+#if CTX_ENABLE_CBRLE
+  {
+    CTX_FORMAT_CBRLE_1, 4, 1, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_3, 4, 3, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_2, 4, 2, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_4, 4, 4, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_5, 4, 5, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_6, 4, 6, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_7, 4, 7, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_8, 4, 8, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_9, 4, 9, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_10, 4, 10, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_11, 4, 11, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_12, 4, 12, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_13, 4, 13, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_14, 4, 14, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_15, 4, 15, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_16, 4, 16, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+
+  {
+    CTX_FORMAT_CBRLE_17, 4, 17, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_18, 4, 18, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_19, 4, 19, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_20, 4, 20, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_21, 4, 21, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_22, 4, 22, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+
+  {
+    CTX_FORMAT_CBRLE_23, 4, 23, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+
+
+  {
+    CTX_FORMAT_CBRLE_24, 4, 24, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE_32, 4, 32, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+  {
+    CTX_FORMAT_CBRLE, 4, 32, 4, 12, 12, CTX_FORMAT_RGBA8,
+    ctx_CBRLE_to_RGBA8,  ctx_RGBA8_to_CBRLE,
+    ctx_composite_CBRLE, ctx_setup_CBRLE,
+  },
+#endif
 #if CTX_ENABLE_RGB565
   {
     CTX_FORMAT_RGB565, 3, 16, 4, 16, 32, CTX_FORMAT_RGBA8,
-    ctx_RGB565_to_RGBA8, ctx_RGBA8_to_RGB565,
+    ctx_RGB565_to_RGBA8,  ctx_RGBA8_to_RGB565,
     ctx_composite_RGB565, ctx_setup_RGB565,
   },
 #endif
@@ -15651,6 +17152,24 @@ ctx_rasterizer_generate_coverage_apply (CtxRasterizer *rasterizer,
                 ctx_span_set_colorb (dst_pix, src_pix, last - first - 1);
               }
               break;
+#if CTX_ENABLE_CBRLE
+              case CTX_COV_PATH_CBRLE_COPY:
+              {
+              uint8_t* dsts = (uint8_t*)(&dst[(first *bpp)/8]);
+              uint8_t  startcov = graystart;
+              rasterizer->apply_coverage (rasterizer, (uint8_t*)dsts, rasterizer->color, first, &startcov, 
1);
+
+              if (last-(first+1) > 0)
+              ctx_CBRLE_compress (rasterizer->color,
+                                   dst,
+                                   rasterizer->blit_width,
+                                   rasterizer->blit_stride,
+                                   first+1, last-(first+1), 
+                                   CBRLE_MODE_SET_COLOR, NULL, 1);
+
+              }
+              break;
+#endif
             case CTX_COV_PATH_RGB8_COPY:
             case CTX_COV_PATH_RGBAF_COPY:
             case CTX_COV_PATH_RGB565_COPY:
@@ -15735,6 +17254,85 @@ ctx_rasterizer_generate_coverage_apply (CtxRasterizer *rasterizer,
             }
               break;
 
+#if CTX_ENABLE_GRAY4
+              case CTX_COV_PATH_GRAY4_COPY:
+              {
+                uint8_t* dstp = (uint8_t*)(&dst[(first *bpp)/8]);
+                uint8_t *srcp = (uint8_t*)src_pixp;
+                uint8_t  startcov = graystart;
+                rasterizer->apply_coverage (rasterizer, (uint8_t*)dstp, rasterizer->color, first, &startcov, 
1);
+                dstp = (uint8_t*)(&dst[((first+1)*bpp)/8]);
+                unsigned int count = last - first - 1;
+                int val = srcp[0]/17;
+
+                uint8_t val_x2 = val + (val << 4);
+                {
+                  int x = first + 1;
+                  for (unsigned int i = 0; i < count && x & 1; count--)
+                  {
+                     int bitno = x & 1;
+                     *dstp &= ~(15<<(bitno*4));
+                     *dstp |= (val<<(bitno*4));
+                     dstp += (bitno == 1);
+                     x++;
+                  }
+
+                  for (unsigned int i = 0; i < count && count>2; count-=2, x+=2, dstp++)
+                     *dstp = val_x2;
+
+                  for (unsigned int i = 0; i < count; count--)
+                  {
+                     int bitno = x & 1;
+                     *dstp &= ~(15<<(bitno*4));
+                     *dstp |= (val<<(bitno*4));
+                     dstp += (bitno == 1);
+                     x++;
+                  }
+                }
+              }
+              break;
+#endif
+
+#if CTX_ENABLE_GRAY2
+              case CTX_COV_PATH_GRAY2_COPY:
+              {
+                uint8_t* dstp = (uint8_t*)(&dst[(first *bpp)/8]);
+                uint8_t *srcp = (uint8_t*)src_pixp;
+                uint8_t  startcov = graystart;
+                rasterizer->apply_coverage (rasterizer, (uint8_t*)dstp, rasterizer->color, first, &startcov, 
1);
+                dstp = (uint8_t*)(&dst[((first+1)*bpp)/8]);
+                unsigned int count = last - first - 1;
+                int val = srcp[0]/85; 
+
+                uint8_t val_x4 = val + (val << 2) + (val << 4) + (val << 6);
+                {
+                  int x = first + 1;
+                  for (unsigned int i = 0; i < count && x & 3; count--)
+                  {
+                     int bitno = x & 3;
+                     *dstp &= ~(3<<(bitno*2));
+                     *dstp |= (val<<(bitno*2));
+                     dstp += (bitno == 3);
+                     x++;
+                  }
+
+                  for (unsigned int i = 0; i < count && count>4; count-=4, x+=4, dstp++)
+                     *dstp = val_x4;
+
+                  for (unsigned int i = 0; i < count; count--)
+                  {
+                     int bitno = x & 3;
+                     *dstp &= ~(3<<(bitno*2));
+                     *dstp |= (val<<(bitno*2));
+                     dstp += (bitno == 3);
+                     x++;
+                  }
+                }
+              }
+              break;
+#endif
+
+#if CTX_ENABLE_GRAY1
               case CTX_COV_PATH_GRAY1_COPY:
               {
                 uint8_t* dstp = (uint8_t*)(&dst[(first *bpp)/8]);
@@ -15798,6 +17396,7 @@ ctx_rasterizer_generate_coverage_apply (CtxRasterizer *rasterizer,
                 }
               }
               break;
+#endif
 
             case CTX_COV_PATH_RGBA8_OVER:
             {
@@ -16007,7 +17606,7 @@ ctx_rasterizer_generate_coverage_set2 (CtxRasterizer *rasterizer,
               int count = 0;
               int mod = ((((u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256) % 256)^255)+64) *
                     (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/255));
-              int sum = ((u1-u0+CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV * 1.25)/255);
+              int sum = ((u1-u0+CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV * 5/4)/255);
               int recip = 65536 / sum;
               for (unsigned int u = u0; u < u1; u+= CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV)
               {
@@ -16219,7 +17818,7 @@ ctx_rasterizer_generate_coverage_apply2 (CtxRasterizer *rasterizer,
 
             int mod = ((((u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256) % 256)^255) +64) *
                     (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/255));
-            int sum = ((u1-u0+CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV * 1.25)/255);
+            int sum = ((u1-u0+CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV * 5/4)/255);
 
             int recip = 65536/ sum;
             for (unsigned int u = u0; u < u1; u+= CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV)
@@ -16321,6 +17920,21 @@ ctx_rasterizer_generate_coverage_apply2 (CtxRasterizer *rasterizer,
                }
              }
              break;
+#if CTX_ENABLE_CBRLE
+            case CTX_COV_PATH_CBRLE_COPY:
+              {
+              int count = (last - post) - (first+pre) + 1;
+              if (count>0)
+              ctx_CBRLE_compress (rasterizer->color,
+                                   dst,
+                                   rasterizer->blit_width,
+                                   rasterizer->blit_stride,
+                                   pre, count,
+                                   CBRLE_MODE_SET_COLOR, NULL, 1);
+
+              }
+              break;
+#endif
 
             case CTX_COV_PATH_RGBA8_COPY:
             {
@@ -16456,9 +18070,9 @@ ctx_rasterizer_reset (CtxRasterizer *rasterizer)
   if (CTX_LIKELY(!rasterizer->preserve))
   {
     rasterizer->scan_min      =
-    rasterizer->col_min       = 5000;
+    rasterizer->col_min       = 50000000;
     rasterizer->scan_max      =
-    rasterizer->col_max       = -5000;
+    rasterizer->col_max       = -50000000;
   }
   //rasterizer->comp_op       = NULL; // keep comp_op cached 
   //     between rasterizations where rendering attributes are
@@ -16873,7 +18487,7 @@ ctx_rasterizer_gradient_add_stop (CtxRasterizer *rasterizer, float pos, float *r
   CtxGradientStop *stop = &gradient->stops[gradient->n_stops];
   stop->pos = pos;
   ctx_color_set_rgba (rasterizer->state, & (stop->color), rgba[0], rgba[1], rgba[2], rgba[3]);
-  if (gradient->n_stops < 15) //we'll keep overwriting the last when out of stops
+  if (gradient->n_stops < CTX_MAX_GRADIENT_STOPS-1) //we'll keep overwriting the last when out of stops
     { gradient->n_stops++; }
 }
 
@@ -16889,7 +18503,7 @@ static inline void ctx_rasterizer_update_inner_point (CtxRasterizer *rasterizer,
 
 static inline int ctx_rasterizer_add_point (CtxRasterizer *rasterizer, int x1, int y1)
 {
-  CtxSegment entry = {CTX_EDGE, {{0},}};
+  CtxSegment entry = {CTX_EDGE, {{0,}},0,0};
 
   entry.data.s16[0]=rasterizer->inner_x;
   entry.data.s16[1]=rasterizer->inner_y;
@@ -16915,8 +18529,8 @@ static inline int ctx_rasterizer_add_point (CtxRasterizer *rasterizer, int x1, i
 #endif
 
 
-float ctx_shape_cache_rate = 0.0;
 #if CTX_SHAPE_CACHE
+float ctx_shape_cache_rate = 0.0;
 int   _ctx_shape_cache_enabled = CTX_SHAPE_CACHE_DEFAULT;
 
 //static CtxShapeCache ctx_cache = {{NULL,}, 0};
@@ -16940,8 +18554,8 @@ static inline CtxShapeEntry *ctx_shape_entry_find (CtxRasterizer *rasterizer, ui
         if (ctx_shape_cache_hits+ctx_shape_cache_misses)
         {
           ctx_shape_cache_rate = 
-                0.5 * ctx_shape_cache_rate +
-                0.5 * (ctx_shape_cache_hits * 100.0  / (ctx_shape_cache_hits+ctx_shape_cache_misses));
+                0.5f * ctx_shape_cache_rate +
+                0.5f * (ctx_shape_cache_hits * 100.0f  / (ctx_shape_cache_hits+ctx_shape_cache_misses));
         }
         i = 0;
         ctx_shape_cache_hits = 0;
@@ -16979,13 +18593,13 @@ static inline CtxShapeEntry *ctx_shape_entry_find (CtxRasterizer *rasterizer, ui
         rasterizer->shape_cache.entries[entry_no] = NULL;
         rasterizer->shape_cache.size -= entry->width * entry->height;
         rasterizer->shape_cache.size -= sizeof (CtxShapeEntry);
-        free (entry);
+        ctx_free (entry);
         entry = NULL;
       }
     }
 
   if (!entry)
-    entry = rasterizer->shape_cache.entries[entry_no] = (CtxShapeEntry *) calloc (size, 1);
+    entry = rasterizer->shape_cache.entries[entry_no] = (CtxShapeEntry *) ctx_calloc (size, 1);
 
   rasterizer->shape_cache.size += size;
 
@@ -16999,36 +18613,6 @@ static inline CtxShapeEntry *ctx_shape_entry_find (CtxRasterizer *rasterizer, ui
 
 #endif
 
-static uint32_t ctx_rasterizer_poly_to_hash (CtxRasterizer *rasterizer)
-{
-  int x = 0;
-  int y = 0;
-
-  CtxSegment *entry = (CtxSegment*)&rasterizer->edge_list.entries[0];
-
-  int ox = entry->data.s16[2];
-  int oy = entry->data.s16[3];
-  uint32_t hash = rasterizer->edge_list.count;
-  hash = ox;//(ox % CTX_SUBDIV);
-  hash *= CTX_SHAPE_CACHE_PRIME1;
-  hash += oy; //(oy % CTX_RASTERIZER_AA);
-  for (unsigned int i = 0; i < rasterizer->edge_list.count; i++)
-    {
-      CtxSegment *entry = &(((CtxSegment*)(rasterizer->edge_list.entries)))[i];
-      x = entry->data.s16[2];
-      y = entry->data.s16[3];
-      int dx = x-ox;
-      int dy = y-oy;
-      ox = x;
-      oy = y;
-      hash *= CTX_SHAPE_CACHE_PRIME3;
-      hash += dx;
-      hash *= CTX_SHAPE_CACHE_PRIME4;
-      hash += dy;
-    }
-  return hash;
-}
-
 static uint32_t ctx_rasterizer_poly_to_edges (CtxRasterizer *rasterizer)
 {
 #if CTX_SHAPE_CACHE
@@ -17097,50 +18681,56 @@ static inline void ctx_rasterizer_finish_shape (CtxRasterizer *rasterizer)
 
 static inline void ctx_rasterizer_move_to (CtxRasterizer *rasterizer, float x, float y)
 {
-  float tx = x; float ty = y;
+  int tx = 0, ty = 0;
+
   rasterizer->x        = x;
   rasterizer->y        = y;
   rasterizer->first_x  = x;
   rasterizer->first_y  = y;
   rasterizer->has_prev = -1;
-  if (rasterizer->uses_transforms)
-    {
-      _ctx_user_to_device (rasterizer->state, &tx, &ty);
-    }
+  _ctx_user_to_device_prepped (rasterizer->state, x,y, &tx, &ty);
 
-  tx = (tx - rasterizer->blit_x) * CTX_SUBDIV;
-  ty = ty * CTX_FULL_AA;
-
-  //ty = ctx_maxf (MIN_Y, ty);
-  //ty = ctx_minf (MAX_Y, ty);
-  //tx = ctx_maxf (MIN_X, tx);
-  //tx = ctx_minf (MAX_X, tx);
+  tx -= rasterizer->blit_x * CTX_SUBDIV;
   ctx_rasterizer_update_inner_point (rasterizer, tx, ty);
 }
 
+static inline void
+ctx_rasterizer_line_to_fixed (CtxRasterizer *rasterizer, int x, int y)
+{
+  rasterizer->has_shape = 1;
+  //  XXX we avoid doing this for the cases where we initially have fixed point
+  //  need a separate call for doing this at end of beziers and arcs
+  //if (done)
+  //{
+  //     rasterizer->y         = y*1.0/CTX_FULL_AA;
+  //     rasterizer->x         = x*1.0/CTX_SUBDIV;
+  //}
+  int tx = 0, ty = 0;
+  _ctx_user_to_device_prepped_fixed (rasterizer->state, x, y, &tx, &ty);
+  tx -= rasterizer->blit_x * CTX_SUBDIV;
+
+  ctx_rasterizer_add_point (rasterizer, tx, ty);
+
+  if (CTX_UNLIKELY(rasterizer->has_prev<=0))
+    {
+      CtxSegment *entry = & ((CtxSegment*)rasterizer->edge_list.entries)[rasterizer->edge_list.count-1];
+      entry->code = CTX_NEW_EDGE;
+      rasterizer->has_prev = 1;
+    }
+}
+
 static inline void
 ctx_rasterizer_line_to (CtxRasterizer *rasterizer, float x, float y)
 {
+  int tx = 0, ty = 0;
   rasterizer->has_shape = 1;
   rasterizer->y         = y;
   rasterizer->x         = x;
 
-  float tx = x;
-  float ty = y;
-  //float ox = rasterizer->x;
-  //float oy = rasterizer->y;
-  if (rasterizer->uses_transforms)
-    {
-      _ctx_user_to_device (rasterizer->state, &tx, &ty);
-    }
-  tx -= rasterizer->blit_x;
+  _ctx_user_to_device_prepped (rasterizer->state, x, y, &tx, &ty);
+  tx -= rasterizer->blit_x * CTX_SUBDIV;
 
-  //ty = ctx_maxf (MIN_Y, ty);
-  //ty = ctx_minf (MAX_Y, ty);
-  //tx = ctx_maxf (MIN_X, tx);
-  //tx = ctx_minf (MAX_X, tx);
-  
-  ctx_rasterizer_add_point (rasterizer, tx * CTX_SUBDIV, ty * CTX_FULL_AA);//rasterizer->aa);
+  ctx_rasterizer_add_point (rasterizer, tx, ty);
 
   if (CTX_UNLIKELY(rasterizer->has_prev<=0))
     {
@@ -17150,7 +18740,6 @@ ctx_rasterizer_line_to (CtxRasterizer *rasterizer, float x, float y)
     }
 }
 
-
 CTX_INLINE static float
 ctx_bezier_sample_1d (float x0, float x1, float x2, float x3, float dt)
 {
@@ -17193,7 +18782,7 @@ ctx_rasterizer_bezier_divide (CtxRasterizer *rasterizer,
   ly = ctx_lerpf (sy, ey, t);
   dx = lx - x;
   dy = ly - y;
-  if (iteration < 5 && (dx*dx+dy*dy) > tolerance)
+  if (iteration < 6 && (dx*dx+dy*dy) > tolerance)
   {
     ctx_rasterizer_bezier_divide (rasterizer, ox, oy, x0, y0, x1, y1, x2, y2,
                                   sx, sy, x, y, s, t, iteration + 1,
@@ -17205,21 +18794,92 @@ ctx_rasterizer_bezier_divide (CtxRasterizer *rasterizer,
   }
 }
 
+#define CTX_FIX_SCALE 1024
+#define CTX_FIX_SHIFT 10
+                      
+
+CTX_INLINE static int
+ctx_lerp_fixed (int v0, int v1, int dx)
+{
+  return v0 + (((v1-v0) * dx) >> CTX_FIX_SHIFT);
+}
+
+
+
+CTX_INLINE static int
+ctx_bezier_sample_1d_fixed (int x0, int x1, int x2, int x3, int dt)
+{
+  return ctx_lerp_fixed (
+      ctx_lerp_fixed (ctx_lerp_fixed (x0, x1, dt),
+                 ctx_lerp_fixed (x1, x2, dt), dt),
+      ctx_lerp_fixed (ctx_lerp_fixed (x1, x2, dt),
+                 ctx_lerp_fixed (x2, x3, dt), dt), dt);
+}
+
+CTX_INLINE static void
+ctx_bezier_sample_fixed (int x0, int y0,
+                         int x1, int y1,
+                         int x2, int y2,
+                         int x3, int y3,
+                         int dt, int *x, int *y)
+{
+  *x = ctx_bezier_sample_1d_fixed (x0, x1, x2, x3, dt);
+  *y = ctx_bezier_sample_1d_fixed (y0, y1, y2, y3, dt);
+}
+
+static inline void
+ctx_rasterizer_bezier_divide_fixed (CtxRasterizer *rasterizer,
+                              int ox, int oy,
+                              int x0, int y0,
+                              int x1, int y1,
+                              int x2, int y2,
+                              int sx, int sy,
+                              int ex, int ey,
+                              int s,
+                              int e,
+                              int iteration,
+                              int tolerance)
+{
+  int t = (s + e) / 2;
+  int x, y;
+  int lx, ly, dx, dy;
+  ctx_bezier_sample_fixed (ox, oy, x0, y0, x1, y1, x2, y2, t, &x, &y);
+  lx = ctx_lerp_fixed (sx, ex, t);
+  ly = ctx_lerp_fixed (sy, ey, t);
+  dx = lx - x;
+  dy = ly - y;
+  if (iteration < 6 && ((dx*dx+dy*dy))  > tolerance)
+  {
+    ctx_rasterizer_bezier_divide_fixed (rasterizer, ox, oy, x0, y0, x1, y1, x2, y2,
+                                  sx, sy, x, y, s, t, iteration + 1,
+                                  tolerance);
+    ctx_rasterizer_line_to_fixed (rasterizer, x, y);
+    ctx_rasterizer_bezier_divide_fixed (rasterizer, ox, oy, x0, y0, x1, y1, x2, y2,
+                                  x, y, ex, ey, t, e, iteration + 1,
+                                  tolerance);
+  }
+}
+
 static void
 ctx_rasterizer_curve_to (CtxRasterizer *rasterizer,
                          float x0, float y0,
                          float x1, float y1,
                          float x2, float y2)
 {
+#if CTX_32BIT_SEGMENTS
   float tolerance = 0.125f/ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
+#else
+  float tolerance = 0.5f/ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
+#endif
   float ox = rasterizer->state->x;
   float oy = rasterizer->state->y;
 
   tolerance = tolerance * tolerance;
 
-  {
-#define CTX_AVOID_CLIPPED_SUBDIVISION 0
+  if(1){
+
 #if CTX_AVOID_CLIPPED_SUBDIVISION
+          // XXX need sporting to fixed point
   float maxx = ctx_maxf (x1,x2);
   maxx = ctx_maxf (maxx, ox);
   maxx = ctx_maxf (maxx, x0);
@@ -17260,11 +18920,21 @@ ctx_rasterizer_curve_to (CtxRasterizer *rasterizer,
     }
     else
 #endif
-  ctx_rasterizer_bezier_divide (rasterizer,
-                                ox, oy, x0, y0,
-                                x1, y1, x2, y2,
-                                ox, oy, x2, y2,
-                                0.0f, 1.0f, 0, tolerance);
+    {
+#if 1
+        ctx_rasterizer_bezier_divide_fixed (rasterizer,
+            (int)(ox * CTX_FIX_SCALE), (int)(oy * CTX_FIX_SCALE), (int)(x0 * CTX_FIX_SCALE), (int)(y0 * 
CTX_FIX_SCALE),
+            (int)(x1 * CTX_FIX_SCALE), (int)(y1 * CTX_FIX_SCALE), (int)(x2 * CTX_FIX_SCALE), (int)(y2 * 
CTX_FIX_SCALE),
+            (int)(ox * CTX_FIX_SCALE), (int)(oy * CTX_FIX_SCALE), (int)(x2 * CTX_FIX_SCALE), (int)(y2 * 
CTX_FIX_SCALE),
+            0, CTX_FIX_SCALE, 0, (int)(tolerance * CTX_FIX_SCALE * CTX_FIX_SCALE));
+#else
+        ctx_rasterizer_bezier_divide (rasterizer,
+                                      ox, oy, x0, y0,
+                                      x1, y1, x2, y2,
+                                      ox, oy, x2, y2,
+                                      0.0f, 1.0f, 0, tolerance);
+#endif
+    }
   }
   ctx_rasterizer_line_to (rasterizer, x2, y2);
 }
@@ -17334,7 +19004,11 @@ ctx_rasterizer_set_texture (CtxRasterizer *rasterizer,
   if (no < 0 || no >= CTX_MAX_TEXTURES) { no = 0; }
   if (rasterizer->texture_source->texture[no].data == NULL)
     {
-      fprintf (stderr, "ctx tex fail %p %s %i\n", rasterizer->texture_source, eid, no);
+#if CTX_32BIT_SEGMENTS
+      // not really, but we want to avoid building/linking fprintf
+      // for firmwares which are likely to not have this set
+      //fprintf (stderr, "ctx tex fail %p %s %i\n", rasterizer->texture_source, eid, no);
+#endif
       return;
     }
   else
@@ -17375,7 +19049,7 @@ ctx_rasterizer_define_texture (CtxRasterizer *rasterizer,
                      *  use
                      */
 
-  ctx_rasterizer_set_texture (rasterizer, eid, 0.0, 0.0);
+  ctx_rasterizer_set_texture (rasterizer, eid, 0.0f, 0.0f);
   if (!rasterizer->state->gstate.source_fill.texture.buffer->color_managed)
   {
     _ctx_texture_prepare_color_management (rasterizer->state,
@@ -17690,19 +19364,19 @@ ctx_rasterizer_glyph (CtxRasterizer *rasterizer, uint32_t unichar, int stroke)
     float tx = 0;
     font_size = rasterizer->state->gstate.font_size;
 
-    ch = ctx_term_get_cell_height (rasterizer->backend.ctx);
-    cw = ctx_term_get_cell_width (rasterizer->backend.ctx);
+    ch = (int)ctx_term_get_cell_height (rasterizer->backend.ctx);
+    cw = (int)ctx_term_get_cell_width (rasterizer->backend.ctx);
 
     _ctx_user_to_device_distance (rasterizer->state, &tx, &font_size);
   }
   if (rasterizer->term_glyphs && !stroke &&
-      fabs (font_size - ch) < 0.5)
+      fabsf (font_size - ch) < 0.5f)
   {
     float tx = rasterizer->x;
     float ty = rasterizer->y;
     _ctx_user_to_device (rasterizer->state, &tx, &ty);
-    int col = tx / cw + 1;
-    int row = ty / ch + 1;
+    int col = (int)(tx / cw + 1);
+    int row = (int)(ty / ch + 1);
     CtxTermGlyph *glyph = ctx_calloc (sizeof (CtxTermGlyph), 1);
     ctx_list_append (&rasterizer->glyphs, glyph);
     glyph->unichar = unichar;
@@ -17732,17 +19406,18 @@ ctx_rasterizer_text (CtxRasterizer *rasterizer, const char *string, int stroke)
     font_size = rasterizer->state->gstate.font_size;
     _ctx_user_to_device_distance (rasterizer->state, &tx, &font_size);
   }
-  int   ch = ctx_term_get_cell_height (rasterizer->backend.ctx);
-  int   cw = ctx_term_get_cell_width (rasterizer->backend.ctx);
+  int   ch = (int)ctx_term_get_cell_height (rasterizer->backend.ctx);
+  int   cw = (int)ctx_term_get_cell_width (rasterizer->backend.ctx);
 
   if (rasterizer->term_glyphs && !stroke &&
-      fabs (font_size - ch) < 0.5)
+      fabsf (font_size - ch) < 0.5f)
   {
     float tx = rasterizer->x;
     float ty = rasterizer->y;
     _ctx_user_to_device (rasterizer->state, &tx, &ty);
-    int col = tx / cw + 1;
-    int row = ty / ch + 1;
+    int col = (int)(tx / cw + 1);
+    int row = (int)(ty / ch + 1);
+
     for (int i = 0; string[i]; i++, col++)
     {
       CtxTermGlyph *glyph = ctx_calloc (sizeof (CtxTermGlyph), 1);
@@ -17766,7 +19441,7 @@ _ctx_font (Ctx *ctx, const char *name);
 static void
 ctx_rasterizer_set_font (CtxRasterizer *rasterizer, const char *font_name)
 {
-  _ctx_font (rasterizer->backend.ctx, font_name);
+  //_ctx_font (rasterizer->backend.ctx, font_name);
 }
 
 static void
@@ -17780,23 +19455,23 @@ ctx_rasterizer_arc (CtxRasterizer *rasterizer,
 {
   float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
   int full_segments = CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS;
-  full_segments = factor * radius * CTX_PI * 2 / 4.0;
+  full_segments = (int)(factor * radius * CTX_PI * 2 / 4.0f);
   if (full_segments > CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS)
     { full_segments = CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS; }
-  if (full_segments < 24) full_segments = 24;
-  float step = CTX_PI*2.0/full_segments;
+  if (full_segments < 42) full_segments = 42;
+  float step = CTX_PI*2.0f/full_segments;
   int steps;
 
-  if (end_angle < -30.0)
-    end_angle = -30.0;
-  if (start_angle < -30.0)
-    start_angle = -30.0;
-  if (end_angle > 30.0)
-    end_angle = 30.0;
-  if (start_angle > 30.0)
-    start_angle = 30.0;
+  if (end_angle < -30.0f)
+    end_angle = -30.0f;
+  if (start_angle < -30.0f)
+    start_angle = -30.0f;
+  if (end_angle > 30.0f)
+    end_angle = 30.0f;
+  if (start_angle > 30.0f)
+    start_angle = 30.0f;
 
-  if (radius <= 0.0001)
+  if (radius <= 0.0001f)
           return;
 
   if (end_angle == start_angle)
@@ -17821,9 +19496,9 @@ ctx_rasterizer_arc (CtxRasterizer *rasterizer,
 #endif
     {
       if (anticlockwise)
-      steps = (start_angle - end_angle) / (CTX_PI*2) * full_segments;
+      steps = (int)((start_angle - end_angle) / (CTX_PI*2) * full_segments);
       else
-      steps = (end_angle - start_angle) / (CTX_PI*2) * full_segments;
+      steps = (int)((end_angle - start_angle) / (CTX_PI*2) * full_segments);
    // if (steps > full_segments)
    //   steps = full_segments;
     }
@@ -17944,7 +19619,7 @@ ctx_rasterizer_stroke (CtxRasterizer *rasterizer)
     {
       if (line_width < 5.0f)
       {
-      factor *= 0.89; /* this hack adjustment makes sharp 1px and 2px strokewidths
+      factor *= 0.89f; /* this hack adjustment makes sharp 1px and 2px strokewidths
       //                 end up sharp without erronious AA; we seem to be off by
       //                 one somewhere else, causing the need for this
       //                 */
@@ -17953,6 +19628,8 @@ ctx_rasterizer_stroke (CtxRasterizer *rasterizer)
       ctx_rasterizer_reset (rasterizer); /* then start afresh with our stroked shape  */
       CtxMatrix transform_backup = gstate->transform;
       _ctx_matrix_identity (&gstate->transform);
+      //gstate->transform_type = 0;
+      _ctx_transform_prime (rasterizer->state);
       float prev_x = 0.0f;
       float prev_y = 0.0f;
       float half_width_x = line_width/2;
@@ -17980,19 +19657,19 @@ ctx_rasterizer_stroke (CtxRasterizer *rasterizer)
                       end = i - 1;
                       goto foo;
                     }
-                  prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
-                  prev_y = entry->data.s16[1] * 1.0f / CTX_FULL_AA;
+                  prev_x = entry->data.s16[0] / CTX_SUBDIV;
+                  prev_y = entry->data.s16[1] / CTX_FULL_AA;
                   started = 1;
                   start = i;
                 }
-              x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
-              y = entry->data.s16[3] * 1.0f / CTX_FULL_AA;
+              x = entry->data.s16[2] / CTX_SUBDIV;
+              y = entry->data.s16[3] / CTX_FULL_AA;
               float dx = x - prev_x;
               float dy = y - prev_y;
               float length = ctx_fast_hypotf (dx, dy);
               if (length>0.001f)
                 {
-                  float recip_length = 1.0/length;
+                  float recip_length = 1.0f/length;
                   dx = dx * recip_length * half_width_x;
                   dy = dy * recip_length * half_width_y;
                   if (CTX_UNLIKELY(entry->code == CTX_NEW_EDGE))
@@ -18151,6 +19828,8 @@ foo:
       ctx_rasterizer_fill (rasterizer);
       gstate->fill_rule = rule_backup;
       gstate->transform = transform_backup;
+      //gstate->transform_type = 0;
+      _ctx_transform_prime (rasterizer->state);
     }
   }
 #if CTX_FAST_FILL_RECT
@@ -18178,7 +19857,7 @@ ctx_rasterizer_clip_reset (CtxRasterizer *rasterizer)
 {
 #if CTX_ENABLE_CLIP
   if (rasterizer->clip_buffer)
-   ctx_buffer_free (rasterizer->clip_buffer);
+   ctx_buffer_destroy (rasterizer->clip_buffer);
   rasterizer->clip_buffer = NULL;
 #endif
   rasterizer->state->gstate.clip_min_x = rasterizer->blit_x;
@@ -18211,8 +19890,8 @@ ctx_rasterizer_clip_apply (CtxRasterizer *rasterizer,
       float x, y;
       if (entry->code == CTX_NEW_EDGE)
         {
-          prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
-          prev_y = entry->data.s16[1] * 1.0f / CTX_FULL_AA;
+          prev_x = entry->data.s16[0] / CTX_SUBDIV;
+          prev_y = entry->data.s16[1] / CTX_FULL_AA;
           if (prev_x < minx) { minx = prev_x; }
           if (prev_y < miny) { miny = prev_y; }
           if (prev_x > maxx) { maxx = prev_x; }
@@ -18220,10 +19899,10 @@ ctx_rasterizer_clip_apply (CtxRasterizer *rasterizer,
         }
       x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
       y = entry->data.s16[3] * 1.0f / CTX_FULL_AA;
-      if (x < minx) { minx = x; }
-      if (y < miny) { miny = y; }
-      if (x > maxx) { maxx = x; }
-      if (y > maxy) { maxy = y; }
+      if (x < minx) { minx = (int)x; }
+      if (y < miny) { miny = (int)y; }
+      if (x > maxx) { maxx = (int)x; }
+      if (y > maxy) { maxy = (int)y; }
 
       if (i < 6)
       {
@@ -18331,8 +20010,8 @@ ctx_rasterizer_clip_apply (CtxRasterizer *rasterizer,
 
   {
 
-  int prev_x = 0;
-  int prev_y = 0;
+  float prev_x = 0;
+  float prev_y = 0;
 
     Ctx *ctx = ctx_new_for_framebuffer (clip_buffer->data, blit_width, blit_height,
        blit_width,
@@ -18354,7 +20033,7 @@ ctx_rasterizer_clip_apply (CtxRasterizer *rasterizer,
     }
     ctx_gray (ctx, 1.0f);
     ctx_fill (ctx);
-    ctx_free (ctx);
+    ctx_destroy (ctx);
   }
 
   int maybe_rect = 1;
@@ -18471,7 +20150,7 @@ ctx_rasterizer_clip_apply (CtxRasterizer *rasterizer,
        rasterizer->clip_rectangle = 1;
   }
   if (!we_made_it)
-   ctx_buffer_free (clip_buffer);
+   ctx_buffer_destroy (clip_buffer);
 #else
   if (coords[0][0]){};
 #endif
@@ -18584,7 +20263,7 @@ static inline float
 ctx_gaussian (float x, float mu, float sigma)
 {
   float a = ( x- mu) / sigma;
-  return ctx_expf (-0.5 * a * a);
+  return ctx_expf (-0.5f * a * a);
 }
 
 static inline void
@@ -18704,7 +20383,7 @@ ctx_rasterizer_end_group (CtxRasterizer *rasterizer)
                   NULL, NULL);
   {
      const char *eid = ".ctx-group";
-     int   eid_len = strlen (eid);
+     int   eid_len = ctx_strlen (eid);
 
      CtxEntry commands[4] =
       {
@@ -18731,7 +20410,7 @@ ctx_rasterizer_end_group (CtxRasterizer *rasterizer)
     ctx_rasterizer_process (ctx, (CtxCommand*)commands);
   }
   //ctx_texture_release (rasterizer->backend.ctx, ".ctx-group");
-  ctx_buffer_free (rasterizer->group[no]);
+  ctx_buffer_destroy (rasterizer->group[no]);
   rasterizer->group[no] = 0;
   ctx_rasterizer_process (ctx, (CtxCommand*)&restore_command);
 }
@@ -18781,7 +20460,7 @@ ctx_rasterizer_shadow_stroke (CtxRasterizer *rasterizer)
 #endif
       }
   }
-  //free (kernel);
+  //ctx_free (kernel);
   ctx_rasterizer_process (ctx, (CtxCommand*)&restore_command);
 }
 
@@ -18886,7 +20565,7 @@ ctx_rasterizer_line_dash (CtxRasterizer *rasterizer, unsigned int count, float *
     rasterizer->state->gstate.n_dashes = 0;
     return;
   }
-  count = CTX_MIN(count, CTX_PARSER_MAX_ARGS-1);
+  count = CTX_MIN(count, CTX_MAX_DASHES);
   rasterizer->state->gstate.n_dashes = count;
   memcpy(&rasterizer->state->gstate.dashes[0], dashes, count * sizeof(float));
   for (unsigned int i = 0; i < count; i ++)
@@ -19000,7 +20679,7 @@ ctx_rasterizer_process (Ctx *ctx, CtxCommand *command)
         break;
       case CTX_ARC:
         if (ctx->bail) break;
-        ctx_rasterizer_arc (rasterizer, c->arc.x, c->arc.y, c->arc.radius, c->arc.angle1, c->arc.angle2, 
c->arc.direction);
+        ctx_rasterizer_arc (rasterizer, c->arc.x, c->arc.y, c->arc.radius, c->arc.angle1, c->arc.angle2, 
(int)c->arc.direction);
         break;
       case CTX_RECTANGLE:
         if (ctx->bail) break;
@@ -19095,7 +20774,7 @@ ctx_rasterizer_process (Ctx *ctx, CtxCommand *command)
 #endif
 
       case CTX_RESTORE:
-        for (int i = state->gstate_no?state->gstate_stack[state->gstate_no-1].keydb_pos:0;
+        for (unsigned int i = state->gstate_no?state->gstate_stack[state->gstate_no-1].keydb_pos:0;
              i < state->gstate.keydb_pos; i++)
         {
           if (state->keydb[i].key == CTX_clip)
@@ -19109,7 +20788,6 @@ ctx_rasterizer_process (Ctx *ctx, CtxCommand *command)
       case CTX_APPLY_TRANSFORM:
       case CTX_TRANSLATE:
       case CTX_IDENTITY:
-        rasterizer->uses_transforms = 1;
         /* FALLTHROUGH */
       case CTX_SAVE:
         rasterizer->comp_op = NULL;
@@ -19117,7 +20795,7 @@ ctx_rasterizer_process (Ctx *ctx, CtxCommand *command)
         if (clear_clip)
         {
           ctx_rasterizer_clip_reset (rasterizer);
-        for (int i = state->gstate_no?state->gstate_stack[state->gstate_no-1].keydb_pos:0;
+          for (unsigned int i = state->gstate_no?state->gstate_stack[state->gstate_no-1].keydb_pos:0;
              i < state->gstate.keydb_pos; i++)
         {
           if (state->keydb[i].key == CTX_clip)
@@ -19135,7 +20813,7 @@ ctx_rasterizer_process (Ctx *ctx, CtxCommand *command)
       case CTX_STROKE:
           if (rasterizer->edge_list.count == 0)break;
 #if CTX_ENABLE_SHADOW_BLUR
-        if (state->gstate.shadow_blur > 0.0 &&
+        if (state->gstate.shadow_blur > 0.0f &&
             !rasterizer->in_text)
           ctx_rasterizer_shadow_stroke (rasterizer);
 #endif
@@ -19153,11 +20831,13 @@ ctx_rasterizer_process (Ctx *ctx, CtxCommand *command)
           int end   = 0;
       CtxMatrix transform_backup = state->gstate.transform;
       _ctx_matrix_identity (&state->gstate.transform);
+      //state->gstate.transform_type = 0;
+      _ctx_transform_prime (state);
       ctx_rasterizer_reset (rasterizer); /* for dashing we create
                                             a dashed path to stroke */
       float prev_x = 0.0f;
       float prev_y = 0.0f;
-      float pos = 0.0;
+      //float pos = 0.0;
 
       int   dash_no  = 0.0;
       float dash_lpos = state->gstate.line_dash_offset * factor;
@@ -19231,7 +20911,7 @@ again:
               }
               else
               {
-                pos += length;
+                //pos += length;
                 dash_lpos += length;
                 {
                   if (is_down)
@@ -19246,6 +20926,8 @@ foo:
           start = end+1;
         }
         state->gstate.transform = transform_backup;
+        //state->gstate.transform_type = 0;
+        _ctx_transform_prime (state);
         }
         ctx_rasterizer_stroke (rasterizer);
         }
@@ -19256,6 +20938,12 @@ foo:
         ctx_rasterizer_set_font (rasterizer, ctx_arg_string() );
         break;
       case CTX_TEXT:
+        if (ctx->bail)
+        {
+          _ctx_text (rasterizer->backend.ctx, ctx_arg_string(), 0, 0);
+          break;
+        }
+
         rasterizer->in_text++;
 #if CTX_ENABLE_SHADOW_BLUR
         if (state->gstate.shadow_blur > 0.0)
@@ -19270,25 +20958,34 @@ foo:
         ctx_rasterizer_reset (rasterizer);
         break;
       case CTX_GLYPH:
-        ctx_rasterizer_glyph (rasterizer, entry[0].data.u32[0], entry[0].data.u8[4]);
+        if (ctx->bail) break;
+        {
+        uint32_t unichar = entry[0].data.u32[0];
+        uint32_t stroke = unichar &  ((uint32_t)1<<31);
+        if (stroke) unichar -= stroke;
+        ctx_rasterizer_glyph (rasterizer, entry[0].data.u32[0], stroke);
+        }
         break;
       case CTX_PAINT:
         // XXX simplify this with a special case
-        ctx_rasterizer_rectangle (rasterizer, -1000.0, -1000.0, 10000, 10000);
+        ctx_rasterizer_rectangle (rasterizer, -1000.0, -1000.0, 11000, 11000);
         ctx_rasterizer_fill (rasterizer);
         ctx_rasterizer_reset (rasterizer);
         break;
       case CTX_FILL:
+        if (!ctx->bail)
+        {
           if (rasterizer->edge_list.count == 0)break;
 #if CTX_ENABLE_SHADOW_BLUR
-        if (state->gstate.shadow_blur > 0.0 &&
+        if (state->gstate.shadow_blur > 0.0f &&
             !rasterizer->in_text)
           ctx_rasterizer_shadow_fill (rasterizer);
 #endif
         ctx_rasterizer_fill (rasterizer);
+        }
         ctx_rasterizer_reset (rasterizer);
         break;
-      case CTX_RESET:
+      case CTX_START_FRAME:
       case CTX_BEGIN_PATH:
         ctx_rasterizer_reset (rasterizer);
         break;
@@ -19305,14 +21002,17 @@ foo:
   ctx_interpret_pos_bare (state, entry, NULL);
 }
 
+
+//static CtxFont *ctx_fonts;
 void
 ctx_rasterizer_deinit (CtxRasterizer *rasterizer)
 {
+  //rasterizer->fonts = ctx_fonts;
   ctx_drawlist_deinit (&rasterizer->edge_list);
 #if CTX_ENABLE_CLIP
   if (rasterizer->clip_buffer)
   {
-    ctx_buffer_free (rasterizer->clip_buffer);
+    ctx_buffer_destroy (rasterizer->clip_buffer);
     rasterizer->clip_buffer = NULL;
   }
 #endif
@@ -19320,16 +21020,18 @@ ctx_rasterizer_deinit (CtxRasterizer *rasterizer)
   for (int i = 0; i < CTX_SHAPE_CACHE_ENTRIES; i ++)
     if (rasterizer->shape_cache.entries[i])
     {
-      free (rasterizer->shape_cache.entries[i]);
+      ctx_free (rasterizer->shape_cache.entries[i]);
       rasterizer->shape_cache.entries[i] = NULL;
     }
-
 #endif
-
-
-  free (rasterizer);
 }
 
+void
+ctx_rasterizer_destroy (CtxRasterizer *rasterizer)
+{
+  ctx_rasterizer_deinit (rasterizer);
+  ctx_free (rasterizer);
+}
 
 CtxAntialias ctx_get_antialias (Ctx *ctx)
 {
@@ -19367,12 +21069,16 @@ static int _ctx_antialias_to_aa (CtxAntialias antialias)
 void
 ctx_set_antialias (Ctx *ctx, CtxAntialias antialias)
 {
-#if CTX_EVENTS
+#if CTX_TERMINAL_EVENTS
   if (ctx_backend_is_tiled (ctx))
   {
      CtxTiled *fb = (CtxTiled*)(ctx->backend);
      fb->antialias = antialias;
+#if CTX_THREADS
      for (int i = 0; i < _ctx_max_threads; i++)
+#else
+     int i = 0;
+#endif
      {
        ctx_set_antialias (fb->host[i], antialias);
      }
@@ -19394,7 +21100,7 @@ ctx_rasterizer_init (CtxRasterizer *rasterizer, Ctx *ctx, Ctx *texture_source, C
 {
 #if CTX_ENABLE_CLIP
   if (rasterizer->clip_buffer)
-    ctx_buffer_free (rasterizer->clip_buffer);
+    ctx_buffer_destroy (rasterizer->clip_buffer);
 #endif
   if (rasterizer->edge_list.size)
     ctx_drawlist_deinit (&rasterizer->edge_list);
@@ -19405,7 +21111,7 @@ ctx_rasterizer_init (CtxRasterizer *rasterizer, Ctx *ctx, Ctx *texture_source, C
 #endif
   CtxBackend *backend = (CtxBackend*)rasterizer;
   backend->process = ctx_rasterizer_process;
-  backend->free    = (CtxDestroyNotify)ctx_rasterizer_deinit;
+  backend->destroy = (CtxDestroyNotify)ctx_rasterizer_destroy;
   backend->ctx     = ctx;
   rasterizer->edge_list.flags |= CTX_DRAWLIST_EDGE_LIST;
   rasterizer->state       = state;
@@ -19454,7 +21160,7 @@ ctx_new_for_buffer (CtxBuffer *buffer)
 {
   Ctx *ctx = _ctx_new_drawlist (buffer->width, buffer->height);
   ctx_set_backend (ctx,
-                    ctx_rasterizer_init ( (CtxRasterizer *) malloc (sizeof (CtxRasterizer) ),
+                    ctx_rasterizer_init ( (CtxRasterizer *) ctx_malloc (sizeof (CtxRasterizer) ),
                                           ctx, NULL, &ctx->state,
                                           buffer->data, 0, 0, buffer->width, buffer->height,
                                           buffer->stride, buffer->format->pixel_format,
@@ -19485,8 +21191,8 @@ ctx_new_for_framebuffer (void *data, int width, int height,
 CtxRasterizer *ctx_rasterizer_new (void *data, int x, int y, int width, int height,
                                    int stride, CtxPixelFormat pixel_format)
 {
-  CtxState    *state    = (CtxState *) malloc (sizeof (CtxState) );
-  CtxRasterizer *rasterizer = (CtxRasterizer *) malloc (sizeof (CtxBackend) );
+  CtxState    *state    = (CtxState *) ctx_malloc (sizeof (CtxState) );
+  CtxRasterizer *rasterizer = (CtxRasterizer *) ctx_malloc (sizeof (CtxBackend) );
   ctx_rasterizer_init (rasterizer, state, data, x, y, width, height,
                        stride, pixel_format, CTX_ANTIALIAS_DEFAULT);
 }
@@ -19541,22 +21247,23 @@ static void bin2base64_group (const unsigned char *in, int remaining, char *out)
 
 void
 ctx_bin2base64 (const void *bin,
-                int         bin_length,
+                size_t      bin_length,
                 char       *ascii)
 {
   /* this allocation is a hack to ensure we always produce the same result,
    * regardless of padding data accidentally taken into account.
    */
-  unsigned char *bin2 = (unsigned char*)calloc (bin_length + 4, 1);
+  unsigned char *bin2 = (unsigned char*)ctx_calloc (bin_length + 4, 1);
   unsigned const char *p = bin2;
-  int i;
-  memcpy (bin2, bin, bin_length);
+  unsigned int i;
+  if (bin_length > 128 * 1024 * 1024) return;
+  memcpy (bin2, bin, (size_t)bin_length);
   for (i=0; i*3 < bin_length; i++)
    {
      int remaining = bin_length - i*3;
      bin2base64_group (&p[i*3], remaining, &ascii[i*4]);
    }
-  free (bin2);
+  ctx_free (bin2);
   ascii[i*4]=0;
 }
 
@@ -20041,6 +21748,11 @@ static int squoze_interned_find (uint64_t hash)
 #endif
 }
 
+#ifdef __CTX_H__
+#define strdup ctx_strdup
+#define strstr ctx_strstr
+#endif
+
 static inline uint64_t squoze (int squoze_dim, const char *utf8)
 {
   uint64_t hash = _squoze (squoze_dim, utf8);
@@ -20296,13 +22008,18 @@ static const char *squoze_decode_r (int squoze_dim, uint64_t hash, char *ret, in
  */
 static const char *squoze_decode (int squoze_dim, uint64_t hash)
 {
+#if CTX_THREADS
 #define THREAD __thread  // use thread local storage
   static THREAD int no = 0;
-  static THREAD char ret[8][256];
+  static THREAD char ret[3][256];
   no ++;
   if (no > 7) no = 0;
   return squoze_decode_r (squoze_dim, hash, ret[no], 256);
 #undef THREAD
+#else
+  static char ret[64];
+  return squoze_decode_r (squoze_dim, hash, ret, 256);
+#endif
 }
 
 const char *squoze6_decode (uint32_t hash)
@@ -20672,7 +22389,7 @@ again:
         case CTX_HOR_LINE_TO:
         case CTX_REL_HOR_LINE_TO:
         case CTX_ROTATE:
-        case CTX_FLUSH:
+        case CTX_END_FRAME:
         case CTX_TEXT_ALIGN:
         case CTX_TEXT_BASELINE:
         case CTX_TEXT_DIRECTION:
@@ -20683,13 +22400,14 @@ again:
         case CTX_SHADOW_BLUR:
         case CTX_SHADOW_OFFSET_X:
         case CTX_SHADOW_OFFSET_Y:
-        case CTX_RESET:
+        case CTX_START_FRAME:
         case CTX_EXIT:
         case CTX_BEGIN_PATH:
         case CTX_CLOSE_PATH:
         case CTX_SAVE:
         case CTX_CLIP:
         case CTX_PRESERVE:
+        case CTX_DEFINE_FONT:
         case CTX_DEFINE_GLYPH:
         case CTX_IDENTITY:
         case CTX_FONT_SIZE:
@@ -20698,6 +22416,9 @@ again:
         case CTX_RESTORE:
         case CTX_LINE_WIDTH:
         case CTX_LINE_DASH_OFFSET:
+        case CTX_LINE_HEIGHT:
+        case CTX_WRAP_LEFT:
+        case CTX_WRAP_RIGHT:
         case CTX_STROKE:
         case CTX_KERNING_PAIR:
         case CTX_SCALE:
@@ -20793,16 +22514,16 @@ ctx_drawlist_resize (CtxDrawlist *drawlist, int desired_size)
   if (drawlist->entries)
     {
       //printf ("grow %p to %d from %d\n", drawlist, new_size, drawlist->size);
-      CtxEntry *ne =  (CtxEntry *) malloc (item_size * new_size);
+      CtxEntry *ne =  (CtxEntry *) ctx_malloc (item_size * new_size);
       memcpy (ne, drawlist->entries, drawlist->size * item_size );
-      free (drawlist->entries);
+      ctx_free (drawlist->entries);
       drawlist->entries = ne;
-      //drawlist->entries = (CtxEntry*)malloc (drawlist->entries, item_size * new_size);
+      //drawlist->entries = (CtxEntry*)ctx_malloc (drawlist->entries, item_size * new_size);
     }
   else
     {
       //fprintf (stderr, "allocating for %p %d\n", drawlist, new_size);
-      drawlist->entries = (CtxEntry *) malloc (item_size * new_size);
+      drawlist->entries = (CtxEntry *) ctx_malloc (item_size * new_size);
     }
   drawlist->size = new_size;
     }
@@ -20904,10 +22625,28 @@ int ctx_append_drawlist (Ctx *ctx, void *data, int length)
       ctx_log("drawlist not multiple of 9\n");
       return -1;
     }
+#if 0
   for (unsigned int i = 0; i < length / sizeof (CtxEntry); i++)
     {
       ctx_drawlist_add_single (&ctx->drawlist, &entries[i]);
     }
+#else
+  CtxDrawlist dl;
+  dl.entries = entries;
+  dl.count = length/9;
+  dl.size = length;
+  dl.flags = CTX_DRAWLIST_DOESNT_OWN_ENTRIES;
+  dl.bitpack_pos = 0;
+
+  CtxIterator it;
+  ctx_iterator_init (&it, &dl, 0, 0);
+  CtxCommand *command;
+ 
+  while ((command = ctx_iterator_next (&it)))
+  {
+     ctx_process (ctx, (CtxEntry*)command);
+  }
+#endif
   return 0;
 }
 
@@ -20953,7 +22692,7 @@ ctx_add_data (Ctx *ctx, void *data, int length)
 
 int ctx_drawlist_add_u32 (CtxDrawlist *drawlist, CtxCode code, uint32_t u32[2])
 {
-  CtxEntry entry[3];
+  CtxEntry entry[4];
   entry[0].code = code;
   entry[0].data.u32[0] = u32[0];
   entry[0].data.u32[1] = u32[1];
@@ -20962,17 +22701,17 @@ int ctx_drawlist_add_u32 (CtxDrawlist *drawlist, CtxCode code, uint32_t u32[2])
 
 int ctx_drawlist_add_data (CtxDrawlist *drawlist, const void *data, int length)
 {
-  CtxEntry entry[3] = {{CTX_DATA, {{0},}}};
+  CtxEntry entry[4] = {{CTX_DATA, {{0},}}};
   entry[0].data.u32[0] = 0;
   entry[0].data.u32[1] = 0;
   int ret = ctx_drawlist_add_single (drawlist, &entry[0]);
   if (CTX_UNLIKELY(!data)) { return -1; }
   int length_in_blocks;
-  if (length <= 0) { length = strlen ( (char *) data) + 1; }
+  if (length <= 0) { length = ctx_strlen ( (char *) data) + 1; }
   length_in_blocks = length / sizeof (CtxEntry);
   length_in_blocks += (length % sizeof (CtxEntry) ) ?1:0;
   if ((signed)drawlist->count + length_in_blocks + 4 > drawlist->size)
-    { ctx_drawlist_resize (drawlist, drawlist->count * 1.2 + length_in_blocks + 32); }
+    { ctx_drawlist_resize (drawlist, (int)(drawlist->count * 1.2 + length_in_blocks + 32)); }
   if (CTX_UNLIKELY((signed)drawlist->count >= drawlist->size))
     { return -1; }
   drawlist->count += length_in_blocks;
@@ -20981,7 +22720,7 @@ int ctx_drawlist_add_data (CtxDrawlist *drawlist, const void *data, int length)
   memcpy (&drawlist->entries[ret+1], data, length);
   {
     //int reverse = ctx_drawlist_add (drawlist, CTX_DATA_REV);
-    CtxEntry entry[3] = {{CTX_DATA_REV, {{0},}}};
+    CtxEntry entry[4] = {{CTX_DATA_REV, {{0},}}};
     entry[0].data.u32[0] = length;
     entry[0].data.u32[1] = length_in_blocks;
     ctx_drawlist_add_single (drawlist, &entry[0]);
@@ -21080,7 +22819,7 @@ ctx_process_cmd_str_with_len (Ctx *ctx, CtxCode code, const char *string, uint32
 static void
 ctx_process_cmd_str (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1)
 {
-  ctx_process_cmd_str_with_len (ctx, code, string, arg0, arg1, strlen (string));
+  ctx_process_cmd_str_with_len (ctx, code, string, arg0, arg1, ctx_strlen (string));
 }
 
 static void
@@ -21090,7 +22829,7 @@ ctx_process_cmd_str_float (Ctx *ctx, CtxCode code, const char *string, float arg
   uint32_t iarg1;
   memcpy (&iarg0, &arg0, sizeof (iarg0));
   memcpy (&iarg1, &arg1, sizeof (iarg1));
-  ctx_process_cmd_str_with_len (ctx, code, string, iarg0, iarg1, strlen (string));
+  ctx_process_cmd_str_with_len (ctx, code, string, iarg0, iarg1, ctx_strlen (string));
 }
 
 #if CTX_BITPACK_PACKER
@@ -21446,6 +23185,117 @@ ctx_matrix_apply_transform (const CtxMatrix *m, float *x, float *y)
   _ctx_matrix_apply_transform (m, x, y);
 }
 
+static inline int
+determine_transform_type (const CtxMatrix *m)
+{
+  if (m->m[2][0] != 0.0f ||
+      m->m[2][1] != 0.0f ||
+      m->m[2][2] != 1.0f)
+    return 3;
+  if (m->m[0][1] != 0.0f ||
+      m->m[1][0] != 0.0f)
+    return 3;
+  if (m->m[0][2] != 0.0f ||
+      m->m[1][2] != 0.0f ||
+      m->m[0][0] != 1.0f ||
+      m->m[1][1] != 1.0f)
+    return 2;
+  return 1;
+}
+
+#define TRANSFORM_SHIFT (10)
+#define TRANSFORM_SCALE (1<<TRANSFORM_SHIFT)
+
+static inline void
+_ctx_transform_prime (CtxState *state)
+{
+   state->gstate.transform_type = 
+     determine_transform_type (&state->gstate.transform);
+
+   for (int c = 0; c < 3; c++)
+   {
+     state->gstate.prepped_transform.m[0][c] =
+             (int)(state->gstate.transform.m[0][c] * TRANSFORM_SCALE);
+     state->gstate.prepped_transform.m[1][c] =
+             (int)(state->gstate.transform.m[1][c] * TRANSFORM_SCALE);
+     state->gstate.prepped_transform.m[2][c] =
+             (int)(state->gstate.transform.m[2][c] * TRANSFORM_SCALE);
+   }
+}
+
+static inline void
+_ctx_matrix_apply_transform_perspective_fixed (const Ctx16f16Matrix *m, int x_in, int y_in,
+                int *x_out, int *y_out)
+{
+  int w  = (((x_in * m->m[2][0] +
+               y_in * m->m[2][1])>>TRANSFORM_SHIFT) +
+                     (m->m[2][2]));
+  int w_recip = w?TRANSFORM_SCALE / w:0;
+
+
+  *x_out = ((((((x_in * m->m[0][0] +
+               y_in * m->m[0][1])>>TRANSFORM_SHIFT) +
+                     (m->m[0][2])) * w_recip)>>TRANSFORM_SHIFT) * CTX_SUBDIV) >> TRANSFORM_SHIFT;
+  *y_out = ((((((x_in * m->m[1][0] +
+               y_in * m->m[1][1])>>TRANSFORM_SHIFT) +
+                     (m->m[1][2])) * w_recip)>>TRANSFORM_SHIFT) * CTX_FULL_AA) >> TRANSFORM_SHIFT;
+
+}
+
+static inline void
+_ctx_matrix_apply_transform_affine_fixed (const Ctx16f16Matrix *m, int x_in, int y_in,
+                int *x_out, int *y_out)
+{
+  *x_out = ((((x_in * m->m[0][0] +
+               y_in * m->m[0][1])>>TRANSFORM_SHIFT) +
+                     (m->m[0][2])) * CTX_SUBDIV) >>TRANSFORM_SHIFT;
+  *y_out = ((((x_in * m->m[1][0] +
+               y_in * m->m[1][1])>>TRANSFORM_SHIFT) +
+                     (m->m[1][2])) * CTX_FULL_AA) >>TRANSFORM_SHIFT;
+}
+
+static inline void
+_ctx_matrix_apply_transform_scale_translate_fixed (const Ctx16f16Matrix *m, int x_in, int y_in, int *x_out, 
int *y_out)
+{
+  *x_out = ((((x_in * m->m[0][0])>>TRANSFORM_SHIFT) +
+                     (m->m[0][2])) * CTX_SUBDIV) >>TRANSFORM_SHIFT;
+  *y_out = ((((y_in * m->m[1][1])>>TRANSFORM_SHIFT) +
+                     (m->m[1][2])) * CTX_FULL_AA) >>TRANSFORM_SHIFT;
+}
+
+static inline void
+_ctx_user_to_device_prepped_fixed (CtxState *state, int x, int y, int *x_out, int *y_out)
+{
+  switch (state->gstate.transform_type)
+  {
+    case 0:
+      _ctx_transform_prime (state);
+      _ctx_user_to_device_prepped_fixed (state, x, y, x_out, y_out);
+      break;
+    case 1:  // identity
+      *x_out = (x * CTX_SUBDIV) / TRANSFORM_SCALE;
+      *y_out = (y * CTX_FULL_AA) / TRANSFORM_SCALE;
+      break;
+    case 2:  // scale/translate
+      _ctx_matrix_apply_transform_scale_translate_fixed (&state->gstate.prepped_transform, x, y, x_out, 
y_out);
+      break;
+    case 3:  // affine
+      _ctx_matrix_apply_transform_affine_fixed (&state->gstate.prepped_transform, x, y, x_out, y_out);
+      break;
+    case 4:  // perspective
+      _ctx_matrix_apply_transform_perspective_fixed (&state->gstate.prepped_transform, x, y, x_out, y_out);
+      break;
+  }
+}
+
+static inline void
+_ctx_user_to_device_prepped (CtxState *state, float x, float y, int *x_out, int *y_out)
+{
+  int x_in = (int)(x * TRANSFORM_SCALE);
+  int y_in = (int)(y * TRANSFORM_SCALE);
+  _ctx_user_to_device_prepped_fixed (state, x_in, y_in, x_out, y_out);
+}
+
 static inline void
 _ctx_user_to_device (CtxState *state, float *x, float *y)
 {
@@ -21456,9 +23306,18 @@ static void
 _ctx_user_to_device_distance (CtxState *state, float *x, float *y)
 {
   const CtxMatrix *m = &state->gstate.transform;
-  _ctx_matrix_apply_transform (m, x, y);
-  *x -= m->m[2][0];
-  *y -= m->m[2][1];
+
+  float x0 = 0.0f;
+  float y0 = 0.0f;
+  float x1 = *x;
+  float y1 = *y;
+
+  _ctx_matrix_apply_transform (m, &x0, &y0);
+  _ctx_matrix_apply_transform (m, &x1, &y1);
+  *x = (x1-x0);
+  *y = (y1-y0);
+  //*x -= m->m[2][0];
+  //*y -= m->m[2][1];
 }
 
 void ctx_user_to_device          (Ctx *ctx, float *x, float *y)
@@ -21470,8 +23329,6 @@ void ctx_user_to_device_distance (Ctx *ctx, float *x, float *y)
   _ctx_user_to_device_distance (&ctx->state, x, y);
 }
 
-
-
 static inline void
 _ctx_device_to_user (CtxState *state, float *x, float *y)
 {
@@ -21494,16 +23351,13 @@ void ctx_device_to_user          (Ctx *ctx, float *x, float *y)
 {
   _ctx_device_to_user (&ctx->state, x, y);
 }
+
 void ctx_device_to_user_distance (Ctx *ctx, float *x, float *y)
 {
   _ctx_device_to_user_distance (&ctx->state, x, y);
 }
 
 
-
-
-
-
 static void
 ctx_matrix_set (CtxMatrix *matrix, float a, float b, float c, float d, float e, float f, float g, float h, 
float i)
 {
@@ -21772,8 +23626,6 @@ ctx_matrix_invert (CtxMatrix *m)
                    t.m [0][1] * t.m [1][0]) * c;
 }
 
-
-
 #endif
 #if CTX_AUDIO
 
@@ -21800,18 +23652,18 @@ int ctx_pcm_bytes_per_frame (CtxPCM format)
 {
   switch (format)
   {
-    case CTX_f32:  return 4;
-    case CTX_f32S: return 8;
-    case CTX_s16:  return 2;
-    case CTX_s16S: return 4;
+    case CTX_F32:  return 4;
+    case CTX_F32S: return 8;
+    case CTX_S16:  return 2;
+    case CTX_S16S: return 4;
     default: return 1;
   }
 }
 
 static float    ctx_host_freq     = 48000;
-static CtxPCM   ctx_host_format   = CTX_s16S;
+static CtxPCM   ctx_host_format   = CTX_S16S;
 static float    client_freq   = 48000;
-static CtxPCM   ctx_client_format = CTX_s16S;
+static CtxPCM   ctx_client_format = CTX_S16S;
 static int      ctx_pcm_queued    = 0;
 static int      ctx_pcm_cur_left  = 0;
 static CtxList *ctx_pcm_list;                 /* data is a blob a 32bit uint first, followed by pcm-data */
@@ -21827,11 +23679,11 @@ ctx_pcm_channels (CtxPCM format)
 {
   switch (format)
   {
-    case CTX_s16:
-    case CTX_f32:
+    case CTX_S16:
+    case CTX_F32:
       return 1;
-    case CTX_s16S:
-    case CTX_f32S:
+    case CTX_S16S:
+    case CTX_F32S:
       return 2;
   }
   return 0;
@@ -21906,8 +23758,8 @@ static void *ctx_alsa_audio_start(Ctx *ctx)
     int is_float = 0;
     int16_t data[81920*8]={0,};
 
-    if (ctx_client_format == CTX_f32 ||
-        ctx_client_format == CTX_f32S)
+    if (ctx_client_format == CTX_F32 ||
+        ctx_client_format == CTX_F32S)
       is_float = 1;
 
     c = snd_pcm_wait(h, 1000);
@@ -21940,7 +23792,7 @@ static void *ctx_alsa_audio_start(Ctx *ctx)
             if (client_channels > 1)
               right = packet[0] * (1<<15);
           }
-          else // s16
+          else // S16
           {
             uint16_t *packet = (ctx_pcm_list->data);
             packet += 8;
@@ -21959,7 +23811,7 @@ static void *ctx_alsa_audio_start(Ctx *ctx)
           {
             void *old = ctx_pcm_list->data;
             ctx_list_remove (&ctx_pcm_list, old);
-            free (old);
+            ctx_free (old);
             ctx_pcm_cur_left = 0;
             if (ctx_pcm_list)
             {
@@ -22037,8 +23889,8 @@ void ctx_ctx_pcm (Ctx *ctx)
     uint8_t data[81920*8]={0,};
     int c;
 
-    if (ctx_client_format == CTX_f32 ||
-        ctx_client_format == CTX_f32S)
+    if (ctx_client_format == CTX_F32 ||
+        ctx_client_format == CTX_F32S)
       is_float = 1;
 
     c = 2000;
@@ -22063,7 +23915,7 @@ void ctx_ctx_pcm (Ctx *ctx)
             if (client_channels > 1)
               right = packet[1] * (1<<15);
           }
-          else // s16
+          else // S16
           {
             uint16_t *packet = (ctx_pcm_list->data);
             packet += 8;
@@ -22081,7 +23933,7 @@ void ctx_ctx_pcm (Ctx *ctx)
           {
             void *old = ctx_pcm_list->data;
             ctx_list_remove (&ctx_pcm_list, old);
-            free (old);
+            ctx_free (old);
             ctx_pcm_cur_left = 0;
             if (ctx_pcm_list)
             {
@@ -22116,7 +23968,7 @@ int ctx_pcm_init (Ctx *ctx)
   if (ctx_backend_type (ctx) == CTX_BACKEND_CTX)
   {
      ctx_host_freq = 8000;
-     ctx_host_format = CTX_s16;
+     ctx_host_format = CTX_S16;
 #if 0
      pthread_t tid;
      pthread_create(&tid, NULL, (void*)ctx_audio_start, ctx);
@@ -22159,7 +24011,7 @@ int ctx_pcm_queue (Ctx *ctx, const int8_t *data, int frames)
     int   scaled_frames = frames / factor;
     int   bpf = ctx_pcm_bytes_per_frame (ctx_client_format);
 
-    uint8_t *packet = malloc (scaled_frames * ctx_pcm_bytes_per_frame (ctx_client_format) + 16);
+    uint8_t *packet = ctx_malloc (scaled_frames * ctx_pcm_bytes_per_frame (ctx_client_format) + 16);
     *((uint32_t *)packet) = scaled_frames;
 
     if (factor > 0.999 && factor < 1.0001)
@@ -22297,7 +24149,7 @@ int ctx_pcm_get_sample_rate (Ctx *ctx)
 void ctx_pcm_set_format (Ctx *ctx, CtxPCM format) { }
 void ctx_pcm_set_sample_rate (Ctx *ctx, int sample_rate) { }
 int ctx_pcm_get_sample_rate (Ctx *ctx) { return 48000; }
-CtxPCM ctx_pcm_get_format (Ctx *ctx) { return CTX_s16S; }
+CtxPCM ctx_pcm_get_format (Ctx *ctx) { return CTX_S16S; }
 int ctx_pcm_queue (Ctx *ctx, const int8_t *data, int frames) { return frames; }
 float ctx_pcm_get_queued_length (Ctx *ctx) { return 0.0; }
 
@@ -22486,13 +24338,13 @@ int ctx_a85len (const char *src, int count)
 int ctx_sha1_init(CtxSHA1 * sha1);
 CtxSHA1 *ctx_sha1_new (void)
 {
-  CtxSHA1 *state = (CtxSHA1*)calloc (sizeof (CtxSHA1), 1);
+  CtxSHA1 *state = (CtxSHA1*)ctx_calloc (sizeof (CtxSHA1), 1);
   ctx_sha1_init (state);
   return state;
 }
 void ctx_sha1_free (CtxSHA1 *sha1)
 {
-  free (sha1);
+  ctx_free (sha1);
 }
 
 #if 0
@@ -22913,7 +24765,7 @@ static int ctx_ydec (const char *tmp_src, char *dst, int count)
 #if 0
   if (tmp_src == dst)
   {
-    src = malloc (count);
+    src = ctx_malloc (count);
     memcpy (src, tmp_src, count);
   }
 #endif
@@ -22930,7 +24782,7 @@ static int ctx_ydec (const char *tmp_src, char *dst, int count)
         {
           dst[out_len]=0;
 #if 0
-          if (tmp_src == dst) free (src);
+          if (tmp_src == dst) ctx_free (src);
 #endif
           return out_len;
         }
@@ -22950,7 +24802,7 @@ static int ctx_ydec (const char *tmp_src, char *dst, int count)
   }
   dst[out_len]=0;
 #if 0
-  if (tmp_src == dst) free (src);
+  if (tmp_src == dst) ctx_free (src);
 #endif
   return out_len;
 }
@@ -22961,7 +24813,7 @@ int main (){
   char *input="this is a testæøåÅØ'''\"!:_asdac\n\r";
   char  encoded[256]="";
   char  decoded[256]="";
-  int   in_len = strlen (input);
+  int   in_len = ctx_strlen (input);
   int   out_len;
   int   dec_len;
 
@@ -23025,11 +24877,11 @@ ctx_register_contents (const char *path,
   for (CtxList *l = registered_contents; l; l = l->next)
   {
     CtxFileContent *c = (CtxFileContent*)l->data;
-    if (!strcmp (c->path, path))
+    if (!ctx_strcmp (c->path, path))
     {
        if (c->free_data)
        {
-         free (c->contents);
+         ctx_free (c->contents);
        }
        c->free_data = free_data;
        c->contents = (unsigned char*)contents;
@@ -23037,7 +24889,7 @@ ctx_register_contents (const char *path,
        return;
     }
   }
-  CtxFileContent *c = (CtxFileContent*)calloc (sizeof (CtxFileContent), 1);
+  CtxFileContent *c = (CtxFileContent*)ctx_calloc (sizeof (CtxFileContent), 1);
   c->free_data = free_data;
   c->contents = (unsigned char*)contents;
   c->length    = length;
@@ -23053,7 +24905,7 @@ _ctx_file_set_contents (const char     *path,
   file = fopen (path, "wb");
   if (!file)
     { return; }
-  if (length < 0) length = strlen ((const char*)contents);
+  if (length < 0) length = ctx_strlen ((const char*)contents);
   fwrite (contents, 1, length, file);
   fclose (file);
 }
@@ -23082,7 +24934,7 @@ ___ctx_file_get_contents (const char     *path,
   if (length)
     { *length =size; }
   rewind (file);
-  buffer = (char*)malloc (size + 8);
+  buffer = (char*)ctx_malloc (size + 8);
   if (!buffer)
     {
       fclose (file);
@@ -23092,7 +24944,7 @@ ___ctx_file_get_contents (const char     *path,
   if (remaining)
     {
       fclose (file);
-      free (buffer);
+      ctx_free (buffer);
       return -1;
     }
   fclose (file);
@@ -23134,12 +24986,12 @@ static float ctx_state_get (CtxState *state, uint32_t hash)
 
 static void ctx_state_set (CtxState *state, uint32_t key, float value)
 {
-  if (key != CTX_new_state)
+  if (key != CTX_newState)
     {
       if (ctx_state_get (state, key) == value)
         { return; }
       for (int i = state->gstate.keydb_pos-1;
-           i >= 0 && state->keydb[i].key != CTX_new_state;
+           i >= 0 && state->keydb[i].key != CTX_newState;
            i--)
         {
           if (state->keydb[i].key == key)
@@ -23157,12 +25009,12 @@ static void ctx_state_set (CtxState *state, uint32_t key, float value)
 }
 
 
-#define CTX_KEYDB_STRING_START (-90000.0)
+#define CTX_KEYDB_STRING_START (-90000.0f)
 #define CTX_KEYDB_STRING_END   (CTX_KEYDB_STRING_START + CTX_STRINGPOOL_SIZE)
 
 static int ctx_float_is_string (float val)
 {
-  return val >= CTX_KEYDB_STRING_START && val <= CTX_KEYDB_STRING_END;
+  return (int)(val) >= CTX_KEYDB_STRING_START && ((int)val) <= CTX_KEYDB_STRING_END;
 }
 
 static int ctx_float_to_string_index (float val)
@@ -23170,7 +25022,7 @@ static int ctx_float_to_string_index (float val)
   int idx = -1;
   if (ctx_float_is_string (val))
   {
-    idx = val - CTX_KEYDB_STRING_START;
+    idx = (int)(val - CTX_KEYDB_STRING_START);
   }
   return idx;
 }
@@ -23235,13 +25087,13 @@ static void ctx_state_set_string (CtxState *state, uint32_t key, const char *str
   if (old_idx >= 0)
   {
     const char *old_string = ctx_state_get_string (state, key);
-    if (old_string && !strcmp (old_string, string))
+    if (old_string && !ctx_strcmp (old_string, string))
       return;
   }
 
   if (ctx_str_is_number (string))
   {
-    ctx_state_set (state, key, strtod (string, NULL));
+    ctx_state_set (state, key, _ctx_parse_float (string, NULL));
     return;
   }
   // should do same with color
@@ -23251,7 +25103,7 @@ static void ctx_state_set_string (CtxState *state, uint32_t key, const char *str
   //
   //     for clips the behavior is howevre ideal, since
   //     we can have more than one clip per save/restore level
-  ctx_state_set_blob (state, key, (uint8_t*)string, strlen(string));
+  ctx_state_set_blob (state, key, (uint8_t*)string, ctx_strlen(string));
 }
 
 static int ctx_state_get_color (CtxState *state, uint32_t key, CtxColor *color)
@@ -23292,7 +25144,7 @@ float ctx_get_float (Ctx *ctx, uint32_t hash)
 }
 int ctx_get_int (Ctx *ctx, uint32_t hash)
 {
-  return ctx_state_get (&ctx->state, hash);
+  return (int)ctx_state_get (&ctx->state, hash);
 }
 void ctx_set_float (Ctx *ctx, uint32_t hash, float value)
 {
@@ -23329,7 +25181,7 @@ int ctx_color_model_get_components (CtxColorModel model)
         return 1;
       case CTX_GRAYA:
       case CTX_GRAYA_A:
-        return 1;
+        return 2;
       case CTX_RGB:
       case CTX_LAB:
       case CTX_LCH:
@@ -23371,7 +25223,7 @@ int ctx_color_is_transparent (CtxColor *color)
 
 void ctx_color_free (CtxColor *color)
 {
-  free (color);
+  ctx_free (color);
 }
 
 static void ctx_color_set_RGBA8 (CtxState *state, CtxColor *color, uint8_t r, uint8_t g, uint8_t b, uint8_t 
a)
@@ -23652,7 +25504,7 @@ float ctx_float_color_rgb_to_gray (CtxState *state, const float *rgb)
 uint8_t ctx_u8_color_rgb_to_gray (CtxState *state, const uint8_t *rgb)
 {
         // XXX todo replace with correct according to primaries
-  return CTX_CSS_RGB_TO_LUMINANCE(rgb);
+  return (uint8_t)(CTX_CSS_RGB_TO_LUMINANCE(rgb));
 }
 
 void ctx_color_get_graya (CtxState *state, CtxColor *color, float *out)
@@ -23765,40 +25617,6 @@ ctx_get_drgba (Ctx *ctx, float *rgba)
 }
 #endif
 
-int ctx_in_fill (Ctx *ctx, float x, float y)
-{
-  float x1, y1, x2, y2;
-  ctx_path_extents (ctx, &x1, &y1, &x2, &y2);
-
-  if (x1 <= x && x <= x2 &&
-      y1 <= y && y <= y2)
-  {
-#if CTX_CURRENT_PATH
-     uint32_t pixel = 0;
-     CtxMatrix transform;
-     ctx_get_matrix (ctx, &transform);
-     Ctx *tester = ctx_new_for_framebuffer (&pixel, 1, 1, 4, CTX_FORMAT_RGBA8);
-     CtxIterator *iterator = ctx_current_path (ctx);
-     CtxCommand *command;
-     ctx_set_matrix (tester, &transform);
-     ctx_rgb (tester, 1,1,1);
-     ctx_translate (tester, x, y);
-     while ((command = ctx_iterator_next (iterator)))
-     {
-       fprintf (stderr, "%c", command->code);
-       ctx_process (tester, (CtxEntry*)command);
-     }
-     fprintf (stderr, "foo\n");
-     ctx_fill (ctx);
-     ctx_free (tester);
-     if (pixel == 0xffffff) return 1;
-#else
-     return 1;
-#endif
-  }
-  return 0;
-}
-
 
 #if CTX_ENABLE_CMYK
 #if 0
@@ -23896,8 +25714,32 @@ static void ctx_color_raw (Ctx *ctx, CtxColorModel model, float *components, int
 
 void ctx_rgba (Ctx *ctx, float r, float g, float b, float a)
 {
+#if CTX_PROTOCOL_U8_COLOR
+  uint8_t ru, gu, bu, au;
+  if (r < 0) ru = 0;
+  else if ( r > 1.0f) ru = 255;
+  else ru = (uint8_t)(r * 255);
+  if (g < 0) gu = 0;
+  else if ( g > 1.0f) gu = 255;
+  else gu = (uint8_t)(g * 255);
+  if (b < 0) bu = 0;
+  else if ( b > 1.0f) bu = 255;
+  else bu = (uint8_t)(b * 255);
+  if (a < 0) au = 0;
+  else if ( a > 1.0f) au = 255;
+  else au = (uint8_t)(a * 255);
+
+  CtxEntry command = ctx_u8 (CTX_SET_RGBA_U8, ru,gu,bu,au, 0, 0, 0, 0);
+
+  uint8_t rgba[4];
+  ctx_color_get_rgba8 (&ctx->state, &ctx->state.gstate.source_fill.color, rgba);
+  if (rgba[0] == ru && rgba[1] == gu && rgba[2] == bu && rgba[3] == au)
+     return;
+  ctx_process (ctx, &command);
+#else
   float components[4]={r,g,b,a};
   ctx_color_raw (ctx, CTX_RGBA, components, 0);
+#endif
 }
 
 void ctx_rgba_stroke (Ctx *ctx, float r, float g, float b, float a)
@@ -24052,16 +25894,16 @@ static ColorDef _ctx_colors[]={
   {CTX_fuchsia,  1, 0, 1, 1},
   {CTX_cyan,     0, 1, 1, 1},
   {CTX_white,    1, 1, 1, 1},
-  {CTX_silver,   0.75294, 0.75294, 0.75294, 1},
-  {CTX_gray,     0.50196, 0.50196, 0.50196, 1},
-  {CTX_magenta,  0.50196, 0, 0.50196, 1},
-  {CTX_maroon,   0.50196, 0, 0, 1},
-  {CTX_purple,   0.50196, 0, 0.50196, 1},
-  {CTX_green,    0, 0.50196, 0, 1},
+  {CTX_silver,   0.75294f, 0.75294f, 0.75294f, 1},
+  {CTX_gray,     0.50196f, 0.50196f, 0.50196f, 1},
+  {CTX_magenta,  0.50196f, 0, 0.50196f, 1},
+  {CTX_maroon,   0.50196f, 0, 0, 1},
+  {CTX_purple,   0.50196f, 0, 0.50196f, 1},
+  {CTX_green,    0, 0.50196f, 0, 1},
   {CTX_lime,     0, 1, 0, 1},
-  {CTX_olive,    0.50196, 0.50196, 0, 1},
-  {CTX_navy,     0, 0,      0.50196, 1},
-  {CTX_teal,     0, 0.50196, 0.50196, 1},
+  {CTX_olive,    0.50196f, 0.50196f, 0, 1},
+  {CTX_navy,     0, 0,      0.50196f, 1},
+  {CTX_teal,     0, 0.50196f, 0.50196f, 1},
   {CTX_aqua,     0, 1, 1, 1},
   {CTX_transparent, 0, 0, 0, 0},
   {CTX_none,     0, 0, 0, 0},
@@ -24103,7 +25945,7 @@ ctx_color_parse_rgb (CtxState *ctxstate, CtxColor *color, const char *color_stri
       if (p != prev)
       {
         if (n_floats < 3)
-          dcolor[n_floats++] = val/255.0;
+          dcolor[n_floats++] = val/255.0f;
         else
           dcolor[n_floats++] = val;
 
@@ -24131,7 +25973,7 @@ static int
 mrg_color_parse_hex (CtxState *ctxstate, CtxColor *color, const char *color_string)
 {
   float dcolor[4]={0,0,0,1};
-  int string_length = strlen (color_string);
+  int string_length = ctx_strlen (color_string);
   int i;
   dcolor[3] = 1.0;
 
@@ -24322,13 +26164,13 @@ void ctx_rasterizer_colorspace_icc (CtxState      *state,
         for (i = 0; i < icc_length; i++)
           tmp[i]= (icc_data[i]>='A' && icc_data[i]<='Z')?icc_data[i]+('a'-'A'):icc_data[i];
         tmp[icc_length]=0;
-        if (!strcmp (tmp, "srgb"))            space = babl_space ("sRGB");
-        else if (!strcmp (tmp, "scrgb"))      space = babl_space ("scRGB");
-        else if (!strcmp (tmp, "acescg"))     space = babl_space ("ACEScg");
-        else if (!strcmp (tmp, "adobe"))      space = babl_space ("Adobe");
-        else if (!strcmp (tmp, "apple"))      space = babl_space ("Apple");
-        else if (!strcmp (tmp, "rec2020"))    space = babl_space ("Rec2020");
-        else if (!strcmp (tmp, "aces2065-1")) space = babl_space ("ACES2065-1");
+        if (!ctx_strcmp (tmp, "srgb"))            space = babl_space ("sRGB");
+        else if (!ctx_strcmp (tmp, "scrgb"))      space = babl_space ("scRGB");
+        else if (!ctx_strcmp (tmp, "acescg"))     space = babl_space ("ACEScg");
+        else if (!ctx_strcmp (tmp, "adobe"))      space = babl_space ("Adobe");
+        else if (!ctx_strcmp (tmp, "apple"))      space = babl_space ("Apple");
+        else if (!ctx_strcmp (tmp, "rec2020"))    space = babl_space ("Rec2020");
+        else if (!ctx_strcmp (tmp, "aces2065-1")) space = babl_space ("ACES2065-1");
       }
    }
 
@@ -24350,7 +26192,7 @@ void ctx_colorspace (Ctx           *ctx,
 {
   if (data)
   {
-    if (data_length <= 0) data_length = (int)strlen ((char*)data);
+    if (data_length <= 0) data_length = (int)ctx_strlen ((char*)data);
     ctx_process_cmd_str_with_len (ctx, CTX_COLOR_SPACE, (char*)data, space_slot, 0, data_length);
   }
   else
@@ -24373,10 +26215,10 @@ void ctx_gradient_add_stop_u8
 void ctx_gradient_add_stop
 (Ctx *ctx, float pos, float r, float g, float b, float a)
 {
-  int ir = r * 255;
-  int ig = g * 255;
-  int ib = b * 255;
-  int ia = a * 255;
+  int ir =(int)(r * 255);
+  int ig =(int)(g * 255);
+  int ib =(int)(b * 255);
+  int ia =(int)(a * 255);
   ir = CTX_CLAMP (ir, 0,255);
   ig = CTX_CLAMP (ig, 0,255);
   ib = CTX_CLAMP (ib, 0,255);
@@ -24441,7 +26283,7 @@ CtxBuffer *ctx_buffer_new_for_data (void *data, int width, int height,
 
 void ctx_buffer_pixels_free (void *pixels, void *userdata)
 {
-  free (pixels);
+  ctx_free (pixels);
 }
 
 CtxBuffer *ctx_buffer_new (int width, int height,
@@ -24467,7 +26309,7 @@ static void ctx_buffer_deinit (CtxBuffer *buffer)
     buffer->free_func (buffer->data, buffer->user_data);
   if (buffer->eid)
   {
-    free (buffer->eid);
+    ctx_free (buffer->eid);
   }
   buffer->eid = NULL;
   buffer->data = NULL;
@@ -24477,16 +26319,16 @@ static void ctx_buffer_deinit (CtxBuffer *buffer)
   {
     if (buffer->color_managed != buffer)
     {
-      ctx_buffer_free (buffer->color_managed);
+      ctx_buffer_destroy (buffer->color_managed);
     }
     buffer->color_managed = NULL;
   }
 }
 
-void ctx_buffer_free (CtxBuffer *buffer)
+void ctx_buffer_destroy (CtxBuffer *buffer)
 {
   ctx_buffer_deinit (buffer);
-  free (buffer);
+  ctx_free (buffer);
 }
 
 #if 0
@@ -24497,7 +26339,7 @@ ctx_texture_check_eid (Ctx *ctx, const char *eid, int *tw, int *th)
   {
     if (ctx->texture[i].data &&
         ctx->texture[i].eid  &&
-        !strcmp (ctx->texture[i].eid, eid))
+        !ctx_strcmp (ctx->texture[i].eid, eid))
     {
       if (tw) *tw = ctx->texture[i].width;
       if (th) *th = ctx->texture[i].height;
@@ -24527,7 +26369,7 @@ const char* ctx_texture_init (Ctx           *ctx,
     {
       if (ctx->texture[i].data &&
           ctx->texture[i].eid &&
-          !strcmp (ctx->texture[i].eid, eid))
+          !ctx_strcmp (ctx->texture[i].eid, eid))
       {
         ctx->texture[i].frame = ctx->texture_cache->frame;
         if (freefunc && user_data != (void*)23)
@@ -24562,7 +26404,7 @@ const char* ctx_texture_init (Ctx           *ctx,
 
   if (freefunc == ctx_buffer_pixels_free && user_data == (void*)23)
   {
-     uint8_t *tmp = (uint8_t*)malloc (data_len);
+     uint8_t *tmp = (uint8_t*)ctx_malloc (data_len);
      memcpy (tmp, pixels, data_len);
      pixels = tmp;
   }
@@ -24578,7 +26420,7 @@ const char* ctx_texture_init (Ctx           *ctx,
   if (eid)
   {
     /* we got an eid, this is the fast path */
-    ctx->texture[id].eid = strdup (eid);
+    ctx->texture[id].eid = ctx_strdup (eid);
   }
   else
   {
@@ -24596,7 +26438,7 @@ const char* ctx_texture_init (Ctx           *ctx,
        ascii[i*2+1]=hex[hash[i]%16];
     }
     ascii[40]=0;
-    ctx->texture[id].eid = strdup (ascii);
+    ctx->texture[id].eid = ctx_strdup (ascii);
   }
   return ctx->texture[id].eid;
 }
@@ -24766,7 +26608,7 @@ ctx_utf8_to_unichar (const char *input)
            (utf8[5] & 0x3F);
   return 0;
 }
-#if CTX_EVENTS
+#if CTX_TERMINAL_EVENTS
 
 #if !__COSMOPOLITAN__
 #include <termios.h>
@@ -25155,8 +26997,8 @@ static const char *mouse_get_event_int (Ctx *n, int *x, int *y)
   relx = buf[1];
   rely = -buf[2];
 
-  n->mouse_x += relx * 0.1;
-  n->mouse_y += rely * 0.1;
+  n->mouse_x += (int)(relx * 0.1f);
+  n->mouse_y += (int)(rely * 0.1f);
 
   if (n->mouse_x < 1) n->mouse_x = 1;
   if (n->mouse_y < 1) n->mouse_y = 1;
@@ -25414,8 +27256,8 @@ const char *ctx_nct_get_event (Ctx *n, int timeoutms, int *x, int *y)
               return match->nick;
               break;
             case 9001: /* mouse event */
-              if (x) *x = ((unsigned char)buf[4]-32)*1.0;
-              if (y) *y = ((unsigned char)buf[5]-32)*1.0;
+              if (x) *x = ((unsigned char)buf[4]-32);
+              if (y) *y = ((unsigned char)buf[5]-32);
               switch (buf[3])
                 {
                         /* XXX : todo reduce this to less string constants */
@@ -25517,8 +27359,8 @@ void ctx_nct_consume_events (Ctx *ctx)
     float x, y;
     event = ctx_nct_get_event (ctx, 50, &ix, &iy);
 
-    x = (ix - 1.0 + 0.5) / ctxctx->cols * ctx->width;
-    y = (iy - 1.0)       / ctxctx->rows * ctx->height;
+    x = (ix - 1.0f + 0.5f) / ctxctx->cols * ctx->width;
+    y = (iy - 1.0f)        / ctxctx->rows * ctx->height;
 
     if (!strcmp (event, "pp"))
     {
@@ -25549,12 +27391,12 @@ void ctx_nct_consume_events (Ctx *ctx)
       nct_set_size (backend->term, width, height);
       width *= CPX;
       height *= CPX;
-      free (mrg->glyphs);
-      free (mrg->styles);
-      free (backend->nct_pixels);
-      backend->nct_pixels = calloc (width * height * 4, 1);
-      mrg->glyphs = calloc ((width/CPX) * (height/CPX) * 4, 1);
-      mrg->styles = calloc ((width/CPX) * (height/CPX) * 1, 1);
+      ctx_free (mrg->glyphs);
+      ctx_free (mrg->styles);
+      ctx_free (backend->nct_pixels);
+      backend->nct_pixels = ctx_calloc (width * height * 4, 1);
+      mrg->glyphs = ctx_calloc ((width/CPX) * (height/CPX) * 4, 1);
+      mrg->styles = ctx_calloc ((width/CPX) * (height/CPX) * 1, 1);
       mrg_set_size (mrg, width, height);
       mrg_queue_draw (mrg, NULL);
 #endif
@@ -25715,13 +27557,6 @@ ctx_ticks (void)
 
 
 
-enum _CtxFlags {
-   CTX_FLAG_DIRECT = (1<<0),
-};
-typedef enum _CtxFlags CtxFlags;
-
-
-int _ctx_max_threads = 1;
 int _ctx_enable_hash_cache = 1;
 #if CTX_SHAPE_CACHE
 extern int _ctx_shape_cache_enabled;
@@ -25729,6 +27564,7 @@ extern int _ctx_shape_cache_enabled;
 
 #if CTX_THREADS
 static mtx_t _ctx_texture_mtx;
+int _ctx_max_threads = 1;
 #endif
 
 void _ctx_texture_lock (void)
@@ -25750,7 +27586,7 @@ ctx_init (int *argc, char ***argv)
 {
 #if 0
   const char *backend = getenv ("CTX_BACKEND");
-  if (!backend || strcmp (backend, "ctx"))
+  if (!backend || ctx_strcmp (backend, "ctx"))
   {
     int i;
     char *new_argv[*argc+5];
@@ -25792,8 +27628,10 @@ void ctx_list_backends(void)
 #if CTX_FB
     fprintf (stderr, " fb");
 #endif
+#if CTX_TERMINAL_EVENTS
     fprintf (stderr, " term");
     fprintf (stderr, " termimg");
+#endif
     fprintf (stderr, "\n");
 }
 
@@ -25802,16 +27640,64 @@ static uint32_t ctx_ms (Ctx *ctx)
   return _ctx_ticks () / 1000;
 }
 
-static int is_in_ctx (void);
+#if CTX_TERMINAL_EVENTS
+
+static int is_in_ctx (void)
+{
+  char buf[1024];
+  struct termios orig_attr;
+  struct termios raw;
+  tcgetattr (STDIN_FILENO, &orig_attr);
+  raw = orig_attr;
+  raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+  raw.c_oflag &= ~(OPOST);
+  raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+  raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+  if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
+    return 0;
+  fprintf (stderr, "\e[?200$p");
+  //tcflush(STDIN_FILENO, 1);
+#if !__COSMOPOLITAN__
+  tcdrain(STDIN_FILENO);
+#endif
+  int length = 0;
+  usleep (1000 * 60); // to account for possibly lowish latency ssh,
+                      // should be made configurable ; perhaps in
+                      // an env var
+  struct timeval tv = {0,0};
+  fd_set rfds;
+  
+  FD_ZERO(&rfds);
+  FD_SET(0, &rfds);
+  tv.tv_usec = 1000 * 5;
+
+  for (int n = 0; select(1, &rfds, NULL, NULL, &tv) && n < 20; n++)
+  {
+    length += read (STDIN_FILENO, &buf[length], 1);
+  }
+  tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
+  if (length == -1)
+  {
+    return 0;
+  }
+  char *semi = strchr (buf, ';');
+  buf[length]=0;
+  if (semi &&  semi[1] == '2')
+  {
+    return 1;
+  }
+  return 0;
+}
+#endif
 
 #if EMSCRIPTEN
 
 CTX_EXPORT Ctx *
-get_context (void);
+ctx_wasm_get_context (int flags);
 
 static Ctx *ctx_new_ui (int width, int height, const char *backend)
 {
-   return get_context ();
+   return ctx_wasm_get_context (CTX_FLAG_HASH_CACHE);
 }
 #else
 
@@ -25821,8 +27707,8 @@ static Ctx *ctx_new_ui (int width, int height, const char *backend)
   if (getenv ("CTX_DAMAGE_CONTROL"))
   {
     const char * val = getenv ("CTX_DAMAGE_CONTROL");
-    if (!strcmp (val, "0") ||
-        !strcmp (val, "off"))
+    if (!ctx_strcmp (val, "0") ||
+        !ctx_strcmp (val, "off"))
       _ctx_damage_control = 0;
     else
       _ctx_damage_control = 1;
@@ -25832,12 +27718,13 @@ static Ctx *ctx_new_ui (int width, int height, const char *backend)
   if (getenv ("CTX_HASH_CACHE"))
   {
     const char * val = getenv ("CTX_HASH_CACHE");
-    if (!strcmp (val, "0"))
+    if (!ctx_strcmp (val, "0"))
       _ctx_enable_hash_cache = 0;
-    if (!strcmp (val, "off"))
+    if (!ctx_strcmp (val, "off"))
       _ctx_enable_hash_cache = 0;
   }
 
+#if CTX_THREADS
   if (getenv ("CTX_THREADS"))
   {
     int val = atoi (getenv ("CTX_THREADS"));
@@ -25851,54 +27738,56 @@ static Ctx *ctx_new_ui (int width, int height, const char *backend)
 #endif
   }
   
-#if CTX_THREADS
   mtx_init (&_ctx_texture_mtx, mtx_plain);
-#endif
 
   if (_ctx_max_threads < 1) _ctx_max_threads = 1;
   if (_ctx_max_threads > CTX_MAX_THREADS) _ctx_max_threads = CTX_MAX_THREADS;
+#endif
 
   //fprintf (stderr, "ctx using %i threads\n", _ctx_max_threads);
   if (!backend)
     backend = getenv ("CTX_BACKEND");
 
-  if (backend && !strcmp (backend, ""))
+  if (backend && !ctx_strcmp (backend, ""))
     backend = NULL;
-  if (backend && !strcmp (backend, "auto"))
+  if (backend && !ctx_strcmp (backend, "auto"))
     backend = NULL;
-  if (backend && !strcmp (backend, "list"))
+  if (backend && !ctx_strcmp (backend, "list"))
   {
     ctx_list_backends ();
     exit (-1);
   }
 
   Ctx *ret = NULL;
-
+#if CTX_TERMINAL_EVENTS
   /* we do the query on auto but not on directly set ctx
    *
    */
-  if ((backend && !strcmp(backend, "ctx")) ||
+  if ((backend && !ctx_strcmp(backend, "ctx")) ||
       (backend == NULL && is_in_ctx ()))
   {
-    if (!backend || !strcmp (backend, "ctx"))
+    if (!backend || !ctx_strcmp (backend, "ctx"))
     {
       // full blown ctx protocol - in terminal or standalone
       ret = ctx_new_ctx (width, height);
     }
   }
+#endif
 
+#if CTX_TERMINAL_EVENTS
 #if CTX_HEADLESS
   if (!ret)
     {
-      if (backend && !strcmp (backend, "headless"))
+      if (backend && !ctx_strcmp (backend, "headless"))
         ret = ctx_new_headless (width, height);
     }
 #endif
+#endif
 
 #if CTX_SDL
   if (!ret && getenv ("DISPLAY"))
   {
-    if ((backend==NULL) || (!strcmp (backend, "SDL")))
+    if ((backend==NULL) || (!ctx_strcmp (backend, "SDL")))
       ret = ctx_new_sdl (width, height);
   }
 #endif
@@ -25906,7 +27795,7 @@ static Ctx *ctx_new_ui (int width, int height, const char *backend)
 #if CTX_KMS
   if (!ret && !getenv ("DISPLAY"))
   {
-    if ((backend==NULL) || (!strcmp (backend, "kms")))
+    if ((backend==NULL) || (!ctx_strcmp (backend, "kms")))
       ret = ctx_new_kms (width, height);
   }
 #endif
@@ -25915,23 +27804,25 @@ static Ctx *ctx_new_ui (int width, int height, const char *backend)
 #if CTX_FB
   if (!ret && !getenv ("DISPLAY"))
     {
-      if ((backend==NULL) || (!strcmp (backend, "fb")))
+      if ((backend==NULL) || (!ctx_strcmp (backend, "fb")))
         ret = ctx_new_fb (width, height);
     }
 #endif
 
+#if CTX_TERMINAL_EVENTS
 #if CTX_RASTERIZER
   // braille in terminal
   if (!ret)
   {
-    if ((backend==NULL) || (!strcmp (backend, "term")))
+    if ((backend==NULL) || (!ctx_strcmp (backend, "term")))
     ret = ctx_new_term (width, height);
   }
   if (!ret)
   {
-    if ((backend==NULL) || (!strcmp (backend, "termimg")))
+    if ((backend==NULL) || (!ctx_strcmp (backend, "termimg")))
     ret = ctx_new_termimg (width, height);
   }
+#endif
 #endif
   if (!ret)
   {
@@ -25961,6 +27852,18 @@ void ctx_set_size (Ctx *ctx, int width, int height)
   {
     ctx->width = width;
     ctx->height = height;
+    switch (ctx_backend_type (ctx))
+    {
+      case CTX_BACKEND_CTX:
+      case CTX_BACKEND_TERM:
+      case CTX_BACKEND_TERMIMG:
+        {CtxCtx *ctxctx = (CtxCtx*)ctx->backend;
+         ctxctx->width = width;
+         ctxctx->height = height;
+        }
+        break;
+      default: break;
+    }
 #if CTX_EVENTS
     _ctx_resized (ctx, width, height, 0);
 #endif
@@ -25969,54 +27872,6 @@ void ctx_set_size (Ctx *ctx, int width, int height)
 
 #if CTX_EVENTS
 
-
-static int is_in_ctx (void)
-{
-  char buf[1024];
-  struct termios orig_attr;
-  struct termios raw;
-  tcgetattr (STDIN_FILENO, &orig_attr);
-  raw = orig_attr;
-  raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
-  raw.c_oflag &= ~(OPOST);
-  raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
-  raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
-  if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
-    return 0;
-  fprintf (stderr, "\e[?200$p");
-  //tcflush(STDIN_FILENO, 1);
-#if !__COSMOPOLITAN__
-  tcdrain(STDIN_FILENO);
-#endif
-  int length = 0;
-  usleep (1000 * 60); // to account for possibly lowish latency ssh,
-                      // should be made configurable ; perhaps in
-                      // an env var
-  struct timeval tv = {0,0};
-  fd_set rfds;
-  
-  FD_ZERO(&rfds);
-  FD_SET(0, &rfds);
-  tv.tv_usec = 1000 * 5;
-
-  for (int n = 0; select(1, &rfds, NULL, NULL, &tv) && n < 20; n++)
-  {
-    length += read (STDIN_FILENO, &buf[length], 1);
-  }
-  tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
-  if (length == -1)
-  {
-    return 0;
-  }
-  char *semi = strchr (buf, ';');
-  buf[length]=0;
-  if (semi &&  semi[1] == '2')
-  {
-    return 1;
-  }
-  return 0;
-}
-
 typedef struct CtxIdleCb {
   int (*cb) (Ctx *ctx, void *idle_data);
   void *idle_data;
@@ -26157,13 +28012,13 @@ void ctx_add_key_binding_full (Ctx *ctx,
     fprintf (stderr, "warning: binding overflow\n");
     return;
   }
-  events->bindings[events->n_bindings].nick = strdup (key);
+  events->bindings[events->n_bindings].nick = ctx_strdup (key);
   strcpy (events->bindings[events->n_bindings].nick, key);
 
   if (action)
-    events->bindings[events->n_bindings].command = action ? strdup (action) : NULL;
+    events->bindings[events->n_bindings].command = action ? ctx_strdup (action) : NULL;
   if (label)
-    events->bindings[events->n_bindings].label = label ? strdup (label) : NULL;
+    events->bindings[events->n_bindings].label = label ? ctx_strdup (label) : NULL;
   events->bindings[events->n_bindings].cb = cb;
   events->bindings[events->n_bindings].cb_data = cb_data;
   events->bindings[events->n_bindings].destroy_notify = destroy_notify;
@@ -26189,11 +28044,11 @@ void ctx_clear_bindings (Ctx *ctx)
   {
     if (events->bindings[i].destroy_notify)
       events->bindings[i].destroy_notify (events->bindings[i].destroy_data);
-    free (events->bindings[i].nick);
+    ctx_free (events->bindings[i].nick);
     if (events->bindings[i].command)
-      free (events->bindings[i].command);
+      ctx_free (events->bindings[i].command);
     if (events->bindings[i].label)
-      free (events->bindings[i].label);
+      ctx_free (events->bindings[i].label);
   }
   memset (&events->bindings, 0, sizeof (events->bindings));
   events->n_bindings = 0;
@@ -26209,7 +28064,7 @@ static void _ctx_bindings_key_press (CtxEvent *event, void *data1, void *data2)
   int handled = 0;
 
   for (i = events->n_bindings-1; i>=0; i--)
-    if (!strcmp (events->bindings[i].nick, event->string))
+    if (!ctx_strcmp (events->bindings[i].nick, event->string))
     {
       if (events->bindings[i].cb)
       {
@@ -26221,7 +28076,7 @@ static void _ctx_bindings_key_press (CtxEvent *event, void *data1, void *data2)
     }
   if (!handled)
   for (i = events->n_bindings-1; i>=0; i--)
-    if (!strcmp (events->bindings[i].nick, "any"))
+    if (!ctx_strcmp (events->bindings[i].nick, "any"))
     {
       if (events->bindings[i].cb)
       {
@@ -26273,7 +28128,7 @@ void ctx_remove_idle (Ctx *ctx, int handle)
 int ctx_add_timeout_full (Ctx *ctx, int ms, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data,
                           void (*destroy_notify)(void *destroy_data), void *destroy_data)
 {
-  CtxIdleCb *item = calloc (sizeof (CtxIdleCb), 1);
+  CtxIdleCb *item = ctx_calloc (sizeof (CtxIdleCb), 1);
   item->cb              = idle_cb;
   item->idle_data       = idle_data;
   item->id              = ++ctx->events.idle_id;
@@ -26296,7 +28151,7 @@ int ctx_add_timeout (Ctx *ctx, int ms, int (*idle_cb)(Ctx *ctx, void *idle_data)
 int ctx_add_idle_full (Ctx *ctx, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data,
                                  void (*destroy_notify)(void *destroy_data), void *destroy_data)
 {
-  CtxIdleCb *item = calloc (sizeof (CtxIdleCb), 1);
+  CtxIdleCb *item = ctx_calloc (sizeof (CtxIdleCb), 1);
   item->cb = idle_cb;
   item->idle_data = idle_data;
   item->id = ++ctx->events.idle_id;
@@ -26397,9 +28252,10 @@ void _ctx_item_unref (CtxItem *item)
     }
     if (item->path)
     {
-      //cairo_path_destroy (item->path);
+      ctx_free (item->path);
+      item->path = NULL;
     }
-    free (item);
+    ctx_free (item);
   }
 }
 
@@ -26415,8 +28271,15 @@ static int
 path_equal (void *path,
             void *path2)
 {
-  //  XXX
-  return 0;
+        return 0;
+  CtxDrawlist *a = (CtxDrawlist*)path;
+  CtxDrawlist *b = (CtxDrawlist*)path2;
+  if (!a && !b) return 1;
+  if (!a && b) return 0;
+  if (!b && a) return 0;
+  if (a->count != b->count)
+    return 0;
+  return memcmp (a->entries, b->entries, a->count * 9) == 0;
 }
 
 void ctx_listen_set_cursor (Ctx      *ctx,
@@ -26466,7 +28329,7 @@ void ctx_listen_full (Ctx     *ctx,
       }
     }
 
-    item = calloc (sizeof (CtxItem), 1);
+    item = ctx_calloc (sizeof (CtxItem), 1);
     item->x0 = x;
     item->y0 = y;
     item->x1 = x + width;
@@ -26479,11 +28342,12 @@ void ctx_listen_full (Ctx     *ctx,
     item->cb[0].finalize_data = finalize_data;
     item->cb_count = 1;
     item->types = types;
-    //item->path = cairo_copy_path (cr); // XXX
+    item->path = ctx_current_path (ctx);
     item->path_hash = ctx_path_hash (item->path);
     ctx_get_matrix (ctx, &item->inv_matrix);
     ctx_matrix_invert (&item->inv_matrix);
 
+#if 0
     if (ctx->events.items)
     {
       CtxList *l;
@@ -26502,13 +28366,14 @@ void ctx_listen_full (Ctx     *ctx,
         {
           /* found an item, copy over cb data  */
           item2->cb[item2->cb_count] = item->cb[0];
-          free (item);
+          ctx_free (item);
           item2->cb_count++;
           item2->types |= types;
           return;
         }
       }
     }
+#endif
     item->ref_count       = 1;
     ctx->events.last_item = item;
     ctx_list_prepend_full (&ctx->events.items, item, _ctx_item_unref2, NULL);
@@ -26598,7 +28463,7 @@ static void ctx_report_hit_region (CtxEvent *event,
 
 void ctx_add_hit_region (Ctx *ctx, const char *id)
 {
-  char *id_copy = strdup (id);
+  char *id_copy = ctx_strdup (id);
   float x, y, width, height;
   /* generate bounding box of what to listen for - from current cairo path */
   {
@@ -26612,7 +28477,7 @@ void ctx_add_hit_region (Ctx *ctx, const char *id)
   
   return ctx_listen_full (ctx, x, y, width, height,
                           CTX_POINTER, ctx_report_hit_region,
-                          id_copy, NULL, (void*)free, NULL);
+                          id_copy, NULL, (void*)ctx_free, NULL);
 }
 
 typedef struct _CtxGrab CtxGrab;
@@ -26636,7 +28501,7 @@ static void grab_free (Ctx *ctx, CtxGrab *grab)
     grab->timeout_id = 0;
   }
   _ctx_item_unref (grab->item);
-  free (grab);
+  ctx_free (grab);
 }
 
 static void device_remove_grab (Ctx *ctx, CtxGrab *grab)
@@ -26647,7 +28512,7 @@ static void device_remove_grab (Ctx *ctx, CtxGrab *grab)
 
 static CtxGrab *device_add_grab (Ctx *ctx, int device_no, CtxItem *item, CtxEventType type)
 {
-  CtxGrab *grab = calloc (1, sizeof (CtxGrab));
+  CtxGrab *grab = ctx_calloc (1, sizeof (CtxGrab));
   grab->item = item;
   grab->type = type;
   _ctx_item_ref (item);
@@ -26671,10 +28536,10 @@ static CtxList *_ctx_device_get_grabs (Ctx *ctx, int device_no)
 
 static void _mrg_restore_path (Ctx *ctx, void *path)  //XXX
 {
-  //int i;
-  //cairo_path_data_t *data;
-  //cairo_new_path (cr);
-  //cairo_append_path (cr, path);
+  CtxDrawlist *dl = (CtxDrawlist*)path;
+  if (!dl) return;
+
+  ctx_append_drawlist (ctx, dl->entries, dl->count*9);
 }
 
 CtxList *_ctx_detect_list (Ctx *ctx, float x, float y, CtxEventType type)
@@ -26719,9 +28584,9 @@ CtxList *_ctx_detect_list (Ctx *ctx, float x, float y, CtxEventType type)
       if (item->path)
       {
         _mrg_restore_path (ctx, item->path);
+        // XXX  - is this done on wrongly transformed coordinates?
         if (ctx_in_fill (ctx, u, v))
         {
-          ctx_begin_path (ctx);
           ctx_list_prepend (&ret, item);
         }
         ctx_begin_path (ctx);
@@ -27423,6 +29288,7 @@ ctx_scrolled (Ctx *ctx, float x, float y, CtxScrollDirection scroll_direction, u
   return 0;
 }
 
+#if 0
 static int ctx_str_has_prefix (const char *string, const char *prefix)
 {
   for (int i = 0; prefix[i]; i++)
@@ -27432,6 +29298,7 @@ static int ctx_str_has_prefix (const char *string, const char *prefix)
   }
   return 0;
 }
+#endif
 
 
 static const char *ctx_keycode_to_keyname (CtxModifierState modifier_state,
@@ -27548,9 +29415,9 @@ ctx_key_press (Ctx *ctx, unsigned int keyval,
   {
     string = ctx_keycode_to_keyname (ctx->events.modifier_state, keyval);
 
-    if (!strcmp (string, "shift") ||
-        !strcmp (string, "control") ||
-        !strcmp (string, "alt"))
+    if (!ctx_strcmp (string, "shift") ||
+        !ctx_strcmp (string, "control") ||
+        !ctx_strcmp (string, "alt"))
       return 0;
 
     if (ctx->events.modifier_state)
@@ -27560,33 +29427,46 @@ ctx_key_press (Ctx *ctx, unsigned int keyval,
             ctx->events.modifier_state & CTX_MODIFIER_STATE_CONTROL))
        {
          string = ctx_keycode_to_keyname (0, keyval);
-         sprintf (&temp_key[strlen(temp_key)], "shift-");
+         sprintf (&temp_key[ctx_strlen(temp_key)], "shift-");
        }
 
        if (ctx->events.modifier_state & CTX_MODIFIER_STATE_ALT)
        {
-         sprintf (&temp_key[strlen(temp_key)], "alt-");
+         sprintf (&temp_key[ctx_strlen(temp_key)], "alt-");
        }
        if (ctx->events.modifier_state & CTX_MODIFIER_STATE_CONTROL)
        {
-         sprintf (&temp_key[strlen(temp_key)], "control-");
+         sprintf (&temp_key[ctx_strlen(temp_key)], "control-");
        }
-       sprintf (&temp_key[strlen(temp_key)], "%s", string);
+       sprintf (&temp_key[ctx_strlen(temp_key)], "%s", string);
        string = temp_key;
     }
   }
 
-  sscanf (string, "%s %f %f %i", event_type, &x, &y, &b);
-  if (!strcmp (event_type, "pm") ||
-      !strcmp (event_type, "pd"))
+  int i = 0;
+  for (i = 0; string[i] && string[i] != ' '; i++)
+  {
+    event_type[i] = string[i];
+  }
+  event_type[i]=0;
+  char *pos = (char*)&string[i] + 1;
+  while (*pos==' ')pos++;
+  x = _ctx_parse_float (pos, &pos);
+  while (*pos==' ')pos++;
+  y = _ctx_parse_float (pos, &pos);
+  while (*pos==' ')pos++;
+  b = atoi(pos);
+
+  if (!ctx_strcmp (event_type, "pm") ||
+      !ctx_strcmp (event_type, "pd"))
     return ctx_pointer_motion (ctx, x, y, b, 0);
-  else if (!strcmp (event_type, "pp"))
+  else if (!ctx_strcmp (event_type, "pp"))
     return ctx_pointer_press (ctx, x, y, b, 0);
-  else if (!strcmp (event_type, "pr"))
+  else if (!ctx_strcmp (event_type, "pr"))
     return ctx_pointer_release (ctx, x, y, b, 0);
-  //else if (!strcmp (event_type, "keydown"))
+  //else if (!ctx_strcmp (event_type, "keydown"))
   //  return ctx_key_down (ctx, keyval, string + 8, time);
-  //else if (!strcmp (event_type, "keyup"))
+  //else if (!ctx_strcmp (event_type, "keyup"))
   //  return ctx_key_up (ctx, keyval, string + 6, time);
 
   CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_PRESS);
@@ -27600,10 +29480,17 @@ ctx_key_press (Ctx *ctx, unsigned int keyval,
     event.ctx = ctx;
     event.type = CTX_KEY_PRESS;
     event.unicode = keyval; 
+#ifdef EMSCRIPTEN
     if (string)
-    event.string = strdup(string);
+      event.string = strdup(string);
     else
-    event.string = "--";
+      event.string = strdup("--");
+#else
+    if (string)
+      event.string = ctx_strdup(string);
+    else
+      event.string = ctx_strdup("--");
+#endif
     event.stop_propagate = 0;
     event.time = time;
 
@@ -27615,12 +29502,20 @@ ctx_key_press (Ctx *ctx, unsigned int keyval,
         item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
         if (event.stop_propagate)
         {
+#ifdef EMSCRIPTEN
           free ((void*)event.string);
+#else
+          ctx_free ((void*)event.string);
+#endif
           return event.stop_propagate;
         }
       }
     }
+#ifdef EMSCRIPTEN
     free ((void*)event.string);
+#else
+    ctx_free ((void*)event.string);
+#endif
   }
   return 0;
 }
@@ -27634,15 +29529,15 @@ ctx_key_down (Ctx *ctx, unsigned int keyval,
   if (!string)
     string = ctx_keycode_to_keyname (0, keyval);
 
-  if (!strcmp (string, "shift"))
+  if (!ctx_strcmp (string, "shift"))
   {
     ctx->events.modifier_state |= CTX_MODIFIER_STATE_SHIFT;
   }
-  else if (!strcmp (string, "control"))
+  else if (!ctx_strcmp (string, "control"))
   {
     ctx->events.modifier_state |= CTX_MODIFIER_STATE_CONTROL;
   }
-  else if (!strcmp (string, "alt"))
+  else if (!ctx_strcmp (string, "alt"))
   {
     ctx->events.modifier_state |= CTX_MODIFIER_STATE_ALT;
   }
@@ -27655,7 +29550,7 @@ ctx_key_down (Ctx *ctx, unsigned int keyval,
     event.ctx     = ctx;
     event.type    = CTX_KEY_DOWN;
     event.unicode = keyval; 
-    event.string  = strdup(string);
+    event.string  = ctx_strdup(string);
     event.stop_propagate = 0;
     event.time    = time;
 
@@ -27667,12 +29562,12 @@ ctx_key_down (Ctx *ctx, unsigned int keyval,
         item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
         if (event.stop_propagate)
         {
-          free ((void*)event.string);
+          ctx_free ((void*)event.string);
           return event.stop_propagate;
         }
       }
     }
-    free ((void*)event.string);
+    ctx_free ((void*)event.string);
   }
   return 0;
 }
@@ -27686,15 +29581,15 @@ ctx_key_up (Ctx *ctx, unsigned int keyval,
   if (!string)
     string = ctx_keycode_to_keyname (0, keyval);
 
-  if (!strcmp (string, "shift"))
+  if (!ctx_strcmp (string, "shift"))
   {
     ctx->events.modifier_state &= ~(CTX_MODIFIER_STATE_SHIFT);
   }
-  else if (!strcmp (string, "control"))
+  else if (!ctx_strcmp (string, "control"))
   {
     ctx->events.modifier_state &= ~(CTX_MODIFIER_STATE_CONTROL);
   }
-  else if (!strcmp (string, "alt"))
+  else if (!ctx_strcmp (string, "alt"))
   {
     ctx->events.modifier_state &= ~(CTX_MODIFIER_STATE_ALT);
   }
@@ -27707,7 +29602,7 @@ ctx_key_up (Ctx *ctx, unsigned int keyval,
     event.ctx = ctx;
     event.type = CTX_KEY_UP;
     event.unicode = keyval; 
-    event.string = strdup(string);
+    event.string = ctx_strdup(string);
     event.stop_propagate = 0;
     event.time = time;
 
@@ -27719,12 +29614,12 @@ ctx_key_up (Ctx *ctx, unsigned int keyval,
         item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
         if (event.stop_propagate)
         {
-          free ((void*)event.string);
+          ctx_free ((void*)event.string);
           return event.stop_propagate;
         }
       }
     }
-    free ((void*)event.string);
+    ctx_free ((void*)event.string);
   }
   return 0;
 }
@@ -27769,7 +29664,7 @@ void _ctx_debug_overlays (Ctx *ctx)
   ctx_save (ctx);
 
   ctx_line_width (ctx, 2);
-  ctx_rgba (ctx, 0,0,0.8,0.5);
+  ctx_rgba (ctx, 0,0,0.8f,0.5f);
   for (a = ctx->events.items; a; a = a->next)
   {
     float current_x = ctx_pointer_x (ctx);
@@ -27791,6 +29686,7 @@ void _ctx_debug_overlays (Ctx *ctx)
   ctx_restore (ctx);
 }
 
+#if CTX_THREADS
 void ctx_set_render_threads   (Ctx *ctx, int n_threads)
 {
   // XXX
@@ -27799,6 +29695,7 @@ int ctx_get_render_threads   (Ctx *ctx)
 {
   return _ctx_max_threads;
 }
+#endif
 void ctx_set_hash_cache (Ctx *ctx, int enable_hash_cache)
 {
   _ctx_enable_hash_cache = enable_hash_cache;
@@ -27823,7 +29720,6 @@ int ctx_need_redraw (Ctx *ctx)
  * wake us up, this to remove sleeping and polling
  */
 
-#define CTX_MAX_LISTEN_FDS 128 // becomes max clients..
 
 static int _ctx_listen_fd[CTX_MAX_LISTEN_FDS];
 static int _ctx_listen_fds    = 0;
@@ -27907,13 +29803,15 @@ static void ctx_events_deinit (Ctx *ctx)
   }
 }
 
-
 #define evsource_has_event(es)   (es)->has_event((es))
 #define evsource_get_event(es)   (es)->get_event((es))
 #define evsource_destroy(es)     do{if((es)->destroy)(es)->destroy((es));}while(0)
 #define evsource_set_coord(es,x,y) do{if((es)->set_coord)(es)->set_coord((es),(x),(y));}while(0)
 #define evsource_get_fd(es)      ((es)->get_fd?(es)->get_fd((es)):0)
 
+#if CTX_TERMINAL_EVENTS
+
+
 static int mice_has_event ();
 static char *mice_get_event ();
 static void mice_destroy ();
@@ -27998,7 +29896,7 @@ static char *mice_get_event ()
   CtxTiled *tiled = (void*)ctx_ev_src_mice.priv;
   n_read = read (mrg_mice_this->fd, buf, 3);
   if (n_read == 0)
-     return strdup ("");
+     return ctx_strdup ("");
   relx = buf[1];
   rely = -buf[2];
 
@@ -28108,7 +30006,7 @@ static char *mice_get_event ()
   mrg_mice_this->prev_state = buf[0];
 
   {
-    char *r = malloc (64);
+    char *r = ctx_malloc (64);
     sprintf (r, "%s %.0f %.0f %i", ret, mrg_mice_this->x, mrg_mice_this->y, button);
     return r;
   }
@@ -28127,7 +30025,7 @@ static void mice_set_coord (EvSource *ev_source, double x, double y)
   mrg_mice_this->y = y;
 }
 
-static EvSource *evsource_mice_new (void)
+static inline EvSource *evsource_mice_new (void)
 {
   if (mmm_evsource_mice_init () == 0)
     {
@@ -28426,7 +30324,7 @@ static int fb_keyboard_match_keycode (const char *buf, int length, const MmmKeyC
     if (!strncmp (buf, ufb_keycodes[i].sequence, length))
       {
         matches ++;
-        if ((int)strlen (ufb_keycodes[i].sequence) == length && ret)
+        if ((int)ctx_strlen (ufb_keycodes[i].sequence) == length && ret)
           {
             *ret = &ufb_keycodes[i];
             return 1;
@@ -28466,7 +30364,7 @@ static char *evsource_kb_get_event (void)
             tv.tv_sec = 0;
             tv.tv_usec = 1000 * 120;
             if (select (STDIN_FILENO+1, &rfds, NULL, NULL, &tv) == 0)
-              return strdup ("escape");
+              return ctx_strdup ("escape");
           }
 
         switch (fb_keyboard_match_keycode ((void*)buf, length + 1, &match))
@@ -28474,11 +30372,11 @@ static char *evsource_kb_get_event (void)
             case 1: /* unique match */
               if (!match)
                 return NULL;
-              return strdup (match->nick);
+              return ctx_strdup (match->nick);
               break;
             case 0: /* no matches, bail*/
              {
-                static char ret[256]="";
+                char ret[256]="";
                 if (length == 0 && ctx_utf8_len (buf[0])>1) /* read a
                                                              * single unicode
                                                              * utf8 character
@@ -28490,13 +30388,13 @@ static char *evsource_kb_get_event (void)
                       buf[ctx_utf8_len(buf[0])]=0;
                       strcpy (ret, (void*)buf);
                     }
-                    return strdup(ret); //XXX: simplify
+                    return ctx_strdup(ret); //XXX: simplify
                   }
                 if (length == 0) /* ascii */
                   {
                     buf[1]=0;
                     strcpy (ret, (void*)buf);
-                    return strdup(ret);
+                    return ctx_strdup(ret);
                   }
                 sprintf (ret, "unhandled %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c'",
                     length >=0 ? buf[0] : 0,
@@ -28514,7 +30412,7 @@ static char *evsource_kb_get_event (void)
                     length >=6 ? buf[6] : 0,
                     length >=6 ? buf[6]>31?buf[6]:'?' : ' '
                     );
-                return strdup(ret);
+                return ctx_strdup(ret);
             }
               return NULL;
             default: /* continue */
@@ -28522,8 +30420,8 @@ static char *evsource_kb_get_event (void)
           }
       }
     else
-      return strdup("key read eek");
-  return strdup("fail");
+      return ctx_strdup("key read eek");
+  return ctx_strdup("fail");
 }
 
 static int evsource_kb_get_fd (void)
@@ -28532,7 +30430,7 @@ static int evsource_kb_get_fd (void)
 }
 
 
-static EvSource *evsource_kb_new (void)
+static inline EvSource *evsource_kb_new (void)
 {
   if (evsource_kb_init() == 0)
   {
@@ -28540,32 +30438,10 @@ static EvSource *evsource_kb_new (void)
   }
   return NULL;
 }
-
-#if CTX_BABL
-static int _ctx_babl_inits = 0;
-#endif
-static void ctx_babl_init (void)
-{
-#if CTX_BABL
-  _ctx_babl_inits ++;
-  if (_ctx_babl_inits == 1)
-  {
-    babl_init ();
-  }
-#endif
-}
-static void ctx_babl_exit (void)
-{
-#if CTX_BABL
-  _ctx_babl_inits --;
-  if (_ctx_babl_inits == 0)
-  {
-    babl_exit ();
-  }
 #endif
-}
 
-static int event_check_pending (CtxTiled *tiled)
+
+static inline int event_check_pending (CtxTiled *tiled)
 {
   int events = 0;
   for (int i = 0; i < tiled->evsource_count; i++)
@@ -28580,7 +30456,7 @@ static int event_check_pending (CtxTiled *tiled)
           ctx_key_press (tiled->backend.ctx, 0, event, 0); // we deliver all events as key-press, the 
key_press handler disambiguates
           events++;
         }
-        free (event);
+        ctx_free (event);
       }
     }
   }
@@ -28589,11 +30465,99 @@ static int event_check_pending (CtxTiled *tiled)
 
 #endif
 
-
 void ctx_queue_draw (Ctx *ctx)
 {
   ctx->dirty ++;
 }
+
+int ctx_in_fill (Ctx *ctx, float x, float y)
+{
+  float x1, y1, x2, y2;
+  float width, height;
+  float factor = 1.0f;
+  ctx_path_extents (ctx, &x1, &y1, &x2, &y2);
+  width = x2-x1;
+  height = y2-y1;
+  while ((width < 200 || height < 200) && factor < 16.0f)
+  {
+    width *=2;
+    height *=2;
+    factor *=2;
+  }
+  x1 *= factor;
+  y1 *= factor;
+  x2 *= factor;
+  y2 *= factor;
+  x *= factor;
+  y *= factor;
+
+  if (x1 <= x && x <= x2 && y1 <= y && y <= y2)
+  {
+#if CTX_CURRENT_PATH
+     uint32_t pixels[9] = {0,};
+     Ctx *tester = ctx_new_for_framebuffer (&pixels[0], 3, 3, 3*4, CTX_FORMAT_RGBA8);
+     ctx_translate (tester, -(x-1), -(y-1));
+     ctx_scale (tester, factor, factor);
+     ctx_gray (tester, 1.0f);
+     ctx_append_drawlist (tester, ctx->current_path.entries, ctx->current_path.count*9);
+     ctx_fill (tester);
+     ctx_destroy (tester);
+     if (pixels[1+3] != 0)
+       return 1;
+     return 0;
+#else
+     return 1
+#endif
+  }
+  return 0;
+}
+
+int ctx_in_stroke (Ctx *ctx, float x, float y)
+{
+  float x1, y1, x2, y2;
+  float width, height;
+  float factor = 1.0f;
+  ctx_path_extents (ctx, &x1, &y1, &x2, &y2);
+  width = x2-x1;
+  height = y2-y1;
+
+  while ((width < 200 || height < 200) && factor < 16.0f)
+  {
+    width *=2;
+    height *=2;
+    factor *=2;
+  }
+  x1 *= factor;
+  y1 *= factor;
+  x2 *= factor;
+  y2 *= factor;
+  x *= factor;
+  y *= factor;
+  if (x1 <= x && x <= x2 && y1 <= y && y <= y2)
+  {
+#if CTX_CURRENT_PATH
+     uint32_t pixels[9] = {0,};
+     Ctx *tester = ctx_new_for_framebuffer (&pixels[0], 3, 3, 3*4, CTX_FORMAT_RGBA8);
+     ctx_translate (tester, -(x-1), -(y-1));
+     ctx_scale (tester, factor, factor);
+     ctx_gray (tester, 1.0f);
+     ctx_append_drawlist (tester, ctx->current_path.entries, ctx->current_path.count*9);
+     ctx_line_width  (tester, ctx_get_line_width  (ctx) * factor);
+     ctx_line_cap    (tester, ctx_get_line_cap    (ctx));
+     ctx_line_join   (tester, ctx_get_line_join   (ctx));
+     ctx_miter_limit (tester, ctx_get_miter_limit (ctx) * factor);
+     ctx_stroke (tester);
+     ctx_destroy (tester);
+     if (pixels[1+3] != 0)
+       return 1;
+     return 0;
+#else
+     return 1
+#endif
+  }
+  return 0;
+}
+
 static void ctx_svg_arc_circle_to (Ctx *ctx,
                                    float radius,
                                    int large,
@@ -28626,9 +30590,9 @@ static void ctx_svg_arc_circle_to (Ctx *ctx,
   }
 
   float len_squared = ctx_pow2(radius_vec_x) + ctx_pow2(radius_vec_y);
-  if (len_squared - 0.03 > r * r || r < 0)
+  if (len_squared - 0.03f > r * r || r < 0)
   {
-    r = sqrtf (len_squared);
+    r = ctx_sqrtf (len_squared);
   }
 
   float center_x = midpoint_x +
@@ -28646,7 +30610,7 @@ static void ctx_svg_arc_circle_to (Ctx *ctx,
 }
 
 
-static void ctx_svg_arc_to (Ctx *ctx, float rx, float ry, 
+static inline void ctx_svg_arc_to (Ctx *ctx, float rx, float ry, 
                             float rotation,  int large, int sweep,
                             float x1, float y1)
 {
@@ -28658,9 +30622,9 @@ static void ctx_svg_arc_to (Ctx *ctx, float rx, float ry,
 
   float x0, y0;
   ctx_current_point (ctx, &x0, &y0);
-  float radius_min = ctx_hypotf (x1-x0,y1-y0)/2.0;
+  float radius_min = ctx_hypotf (x1-x0,y1-y0)/2.0f;
   float radius_lim = ctx_hypotf (rx, ry);
-  float up_scale = 1.0;
+  float up_scale = 1.0f;
   if (radius_lim < radius_min)
     up_scale = radius_min / radius_lim;
   float ratio = rx / ry;
@@ -28826,13 +30790,13 @@ CtxParser *ctx_parser_new (
                            exit, exit_data);
 }
 
-void ctx_parser_free (CtxParser *parser)
+void ctx_parser_destroy (CtxParser *parser)
 {
 #if !CTX_PARSER_FIXED_TEMP
   if (parser->holding)
-    free (parser->holding);
+    ctx_free (parser->holding);
 #endif
-  free (parser);
+  ctx_free (parser);
 }
 
 #define CTX_ARG_COLLECT_NUMBERS             50
@@ -28850,12 +30814,13 @@ static int ctx_arguments_for_code (CtxCode code)
       case CTX_IDENTITY:
       case CTX_CLOSE_PATH:
       case CTX_BEGIN_PATH:
-      case CTX_RESET:
-      case CTX_FLUSH:
+      case CTX_START_FRAME:
+      case CTX_END_FRAME:
       case CTX_RESTORE:
       case CTX_STROKE:
       case CTX_FILL:
       case CTX_PAINT:
+      case CTX_DEFINE_FONT:
       case CTX_NEW_PAGE:
       case CTX_CLIP:
       case CTX_EXIT:
@@ -28869,6 +30834,9 @@ static int ctx_arguments_for_code (CtxCode code)
       case CTX_LINE_CAP:
       case CTX_LINE_WIDTH:
       case CTX_LINE_DASH_OFFSET:
+      case CTX_LINE_HEIGHT:
+      case CTX_WRAP_LEFT:
+      case CTX_WRAP_RIGHT:
       case CTX_IMAGE_SMOOTHING:
       case CTX_SHADOW_BLUR:
       case CTX_SHADOW_OFFSET_X:
@@ -29001,6 +30969,9 @@ static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
       case 'c': return ctx_parser_set_command (parser, CTX_LINE_CAP);
       case 'w': return ctx_parser_set_command (parser, CTX_LINE_WIDTH);
       case 'D': return ctx_parser_set_command (parser, CTX_LINE_DASH_OFFSET);
+      case 'H': return ctx_parser_set_command (parser, CTX_LINE_HEIGHT);
+      case 'L': return ctx_parser_set_command (parser, CTX_WRAP_LEFT);
+      case 'R': return ctx_parser_set_command (parser, CTX_WRAP_RIGHT);
       case 'S': return ctx_parser_set_command (parser, CTX_IMAGE_SMOOTHING);
       case 'C': return ctx_parser_set_command (parser, CTX_SHADOW_COLOR);
       case 's': return ctx_parser_set_command (parser, CTX_SHADOW_BLUR);
@@ -29036,7 +31007,7 @@ static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
           case CTX_stroke:         ret = CTX_STROKE; break;
           case CTX_fill:           ret = CTX_FILL; break;
           case CTX_paint:          ret = CTX_PAINT; break;
-          case CTX_flush:          ret = CTX_FLUSH; break;
+          case CTX_endFrame:       ret = CTX_END_FRAME; break;
           case CTX_horLineTo:      ret = CTX_HOR_LINE_TO; break;
           case CTX_rotate:         ret = CTX_ROTATE; break;
           case CTX_color:          ret = CTX_COLOR; break;
@@ -29046,8 +31017,8 @@ static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
           case CTX_newPage:        ret = CTX_NEW_PAGE; break;
           case CTX_quadTo:         ret = CTX_QUAD_TO; break;
           case CTX_viewBox:        ret = CTX_VIEW_BOX; break;
-          case CTX_smooth_to:      ret = CTX_SMOOTH_TO; break;
-          case CTX_smooth_quad_to: ret = CTX_SMOOTHQ_TO; break;
+          case CTX_smoothTo:       ret = CTX_SMOOTH_TO; break;
+          case CTX_smoothQuadTo:   ret = CTX_SMOOTHQ_TO; break;
           case CTX_clear:          ret = CTX_COMPOSITE_CLEAR; break;
           case CTX_copy:           ret = CTX_COMPOSITE_COPY; break;
           case CTX_destinationOver:  ret = CTX_COMPOSITE_DESTINATION_OVER; break;
@@ -29072,7 +31043,7 @@ static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
           case CTX_normal:         ret = CTX_BLEND_NORMAL;break;
           case CTX_screen:         ret = CTX_BLEND_SCREEN;break;
           case CTX_difference:     ret = CTX_BLEND_DIFFERENCE; break;
-          case CTX_reset:          ret = CTX_RESET; break;
+          case CTX_startFrame:     ret = CTX_START_FRAME; break;
           case CTX_verLineTo:      ret = CTX_VER_LINE_TO; break;
           case CTX_exit:
           case CTX_done:           ret = CTX_EXIT; break;
@@ -29118,6 +31089,8 @@ static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
           case CTX_drgbSpace:
             return ctx_parser_set_command (parser, CTX_SET_DRGB_SPACE);
 #endif
+          case CTX_defineFont:
+            return ctx_parser_set_command (parser, CTX_DEFINE_FONT);
           case CTX_defineGlyph:
             return ctx_parser_set_command (parser, CTX_DEFINE_GLYPH);
           case CTX_kerningPair:
@@ -29166,6 +31139,12 @@ static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
             return ctx_parser_set_command (parser, CTX_LINE_WIDTH);
           case CTX_lineDashOffset:
             return ctx_parser_set_command (parser, CTX_LINE_DASH_OFFSET);
+          case CTX_lineHeight:
+            return ctx_parser_set_command (parser, CTX_LINE_HEIGHT);
+          case CTX_wrapLeft:
+            return ctx_parser_set_command (parser, CTX_WRAP_LEFT);
+          case CTX_wrapRight:
+            return ctx_parser_set_command (parser, CTX_WRAP_RIGHT);
           case CTX_imageSmoothing:
             return ctx_parser_set_command (parser, CTX_IMAGE_SMOOTHING);
           case CTX_shadowColor:
@@ -29263,10 +31242,8 @@ static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
           /* words that correspond to low integer constants
           */
           case CTX_nonzero:     return CTX_FILL_RULE_WINDING;
-          case CTX_non_zero:    return CTX_FILL_RULE_WINDING;
           case CTX_winding:     return CTX_FILL_RULE_WINDING;
-          case CTX_evenOdd:
-          case CTX_even_odd:    return CTX_FILL_RULE_EVEN_ODD;
+          case CTX_evenOdd:     return CTX_FILL_RULE_EVEN_ODD;
           case CTX_bevel:       return CTX_JOIN_BEVEL;
           case CTX_round:       return CTX_JOIN_ROUND;
           case CTX_miter:       return CTX_JOIN_MITER;
@@ -29327,7 +31304,7 @@ static void ctx_parser_set_color_model (CtxParser *parser, CtxColorModel color_m
 static void ctx_parser_get_color_rgba (CtxParser *parser, int offset, float *red, float *green, float *blue, 
float *alpha)
 {
   /* XXX - this function is to be deprecated */
-  *alpha = 1.0;
+  *alpha = 1.0f;
   switch (parser->color_model)
     {
       case CTX_GRAYA:
@@ -29354,12 +31331,12 @@ static void ctx_parser_get_color_rgba (CtxParser *parser, int offset, float *red
         /* FALLTHROUGH */
       case CTX_CMYK:
         /* should use profile instead  */
-        *red = (1.0-parser->numbers[offset + 0]) *
-               (1.0 - parser->numbers[offset + 3]);
-        *green = (1.0-parser->numbers[offset + 1]) *
-                 (1.0 - parser->numbers[offset + 3]);
-        *blue = (1.0-parser->numbers[offset + 2]) *
-                (1.0 - parser->numbers[offset + 3]);
+        *red = (1.0f-parser->numbers[offset + 0]) *
+               (1.0f - parser->numbers[offset + 3]);
+        *green = (1.0f-parser->numbers[offset + 1]) *
+                 (1.0f - parser->numbers[offset + 3]);
+        *blue = (1.0f-parser->numbers[offset + 2]) *
+                (1.0f - parser->numbers[offset + 3]);
         break;
     }
 }
@@ -29439,12 +31416,12 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
             parser->numbers[1] = ctx_utf8_to_unichar ((char*)parser->holding);
             break;
           case 2:
-            parser->numbers[2] = strtod ((char*)parser->holding, NULL);
+            parser->numbers[2] = _ctx_parse_float ((char*)parser->holding, NULL);
             {
-              CtxEntry e = {CTX_KERNING_PAIR, };
-              e.data.u16[0] = parser->numbers[0];
-              e.data.u16[1] = parser->numbers[1];
-              e.data.s32[1] = parser->numbers[2] * 256;
+              CtxEntry e = {CTX_KERNING_PAIR, {{0},}};
+              e.data.u16[0] = (uint16_t)parser->numbers[0];
+              e.data.u16[1] = (uint16_t)parser->numbers[1];
+              e.data.s32[1] = (int32_t)(parser->numbers[2] * 256);
               ctx_process (ctx, &e);
             }
             break;
@@ -29474,8 +31451,8 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
           if (parser->texture_done++ == 1)
           {
              const char *eid = (char*)parser->texture_id;
-             int width  = arg(0);
-             int height = arg(1);
+             int width  = (int)arg(0);
+             int height = (int)arg(1);
              CtxPixelFormat format = (CtxPixelFormat)arg(2);
              int stride = ctx_pixel_format_get_stride (format, width);
              int data_len = stride * height;
@@ -29520,14 +31497,17 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
         parser->command = CTX_DEFINE_TEXTURE;
         break;
 
+      case CTX_DEFINE_FONT:
+        // XXX: todo
+        break;
 
       case CTX_DEFINE_GLYPH:
         /* XXX : reuse n_args logic - to enforce order */
         if (parser->n_numbers == 1)
         {
-          CtxEntry e = {CTX_DEFINE_GLYPH, };
+          CtxEntry e = {CTX_DEFINE_GLYPH, {{0},}};
           e.data.u32[0] = parser->color_space_slot;
-          e.data.u32[1] = arg(0) * 256;
+          e.data.u32[1] = (int)arg(0) * 256;
           ctx_process (ctx, &e);
         }
         else
@@ -29591,7 +31571,7 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
         //append_dash_val (ctx, arg(0));
         break;
       case CTX_ARC_TO:
-        ctx_svg_arc_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5), arg(6));
+        ctx_svg_arc_to (ctx, arg(0), arg(1), arg(2), (int)arg(3), (int)arg(4), arg(5), arg(6));
         break;
       case CTX_REL_ARC_TO:
         //ctx_rel_arc_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4) );
@@ -29599,7 +31579,7 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
         {
           float x = ctx_x (ctx);
           float y = ctx_y (ctx);
-          ctx_svg_arc_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5)+x, arg(6)+y);
+          ctx_svg_arc_to (ctx, arg(0), arg(1), arg(2), (int)arg(3), (int)arg(4), arg(5)+x, arg(6)+y);
         }
         break;
       case CTX_REL_SMOOTH_TO:
@@ -29663,7 +31643,7 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
         parser->pcy = ctx_y (ctx);
         break;
       case CTX_ARC:
-        ctx_arc (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
+        ctx_arc (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), (int)arg(5));
         break;
       case CTX_APPLY_TRANSFORM:
         ctx_apply_transform (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) , arg(6), arg(7), arg(8));
@@ -29705,6 +31685,9 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
       case CTX_SCALE:
         ctx_scale (ctx, arg(0), arg(1) );
         break;
+      case CTX_NEW_PAGE:
+        ctx_new_page (ctx);
+        break;
       case CTX_QUAD_TO:
         parser->pcx = arg(0);
         parser->pcy = arg(1);
@@ -29787,8 +31770,17 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
       case CTX_LINE_DASH_OFFSET:
         ctx_line_dash_offset (ctx, arg(0));
         break;
+      case CTX_LINE_HEIGHT:
+        ctx_line_height (ctx, arg(0));
+        break;
+      case CTX_WRAP_LEFT:
+        ctx_wrap_left (ctx, arg(0));
+        break;
+      case CTX_WRAP_RIGHT:
+        ctx_wrap_right (ctx, arg(0));
+        break;
       case CTX_IMAGE_SMOOTHING:
-        ctx_image_smoothing (ctx, arg(0));
+        ctx_image_smoothing (ctx, (int)arg(0));
         break;
       case CTX_SHADOW_COLOR:
         ctx_shadow_rgba (ctx, arg(0), arg(1), arg(2), arg(3));
@@ -29813,7 +31805,7 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
         break;
       case CTX_BLEND_MODE:
         {
-          int blend_mode = arg(0);
+          int blend_mode = (int)arg(0);
           if (blend_mode == CTX_COLOR) blend_mode = CTX_BLEND_COLOR;
           ctx_blend_mode (ctx, (CtxBlend)blend_mode);
         }
@@ -29852,6 +31844,7 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
         break;
       case CTX_VIEW_BOX:
         ctx_view_box (ctx, arg(0), arg(1), arg(2), arg(3) );
+        ctx_parser_set_size (parser, (int)arg(2), (int)arg(3), 0, 0);
         break;
       case CTX_LINEAR_GRADIENT:
         ctx_linear_gradient (ctx, arg(0), arg(1), arg(2), arg(3) );
@@ -29873,7 +31866,7 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
         ctx_begin_path (ctx);
         break;
       case CTX_GLYPH:
-        ctx_glyph (ctx, arg(0), 0);
+        ctx_glyph (ctx, (uint32_t)arg(0), 0);
         break;
       case CTX_CLOSE_PATH:
         ctx_close_path (ctx);
@@ -29884,16 +31877,16 @@ static void ctx_parser_dispatch_command (CtxParser *parser)
             return;
           }
         break;
-      case CTX_FLUSH:
+      case CTX_END_FRAME:
         //ctx_flush (ctx); // XXX  XXX  flush only does things inside backends
         break;
-      case CTX_RESET:
-        ctx_reset (ctx);
+      case CTX_START_FRAME: // XXX is it right to do things here?
+        ctx_start_frame (ctx);
         if (parser->translate_origin)
         {
           ctx_translate (ctx,
-                         (parser->cursor_x-1) * parser->cell_width * 1.0,
-                         (parser->cursor_y-1) * parser->cell_height * 1.0);
+                         (parser->cursor_x-1) * parser->cell_width * 1.0f,
+                         (parser->cursor_y-1) * parser->cell_height * 1.0f);
         }
         break;
     }
@@ -29908,7 +31901,7 @@ static inline void ctx_parser_holding_append (CtxParser *parser, int byte)
   {
     int new_len = parser->hold_len * 2;
     if (new_len < 512) new_len = 512;
-    parser->holding = (uint8_t*)realloc (parser->holding, new_len);
+    parser->holding = (uint8_t*)ctx_realloc (parser->holding, parser->hold_len, new_len);
     parser->hold_len = new_len;
   }
 #endif
@@ -29938,15 +31931,15 @@ static void ctx_parser_transform_percent (CtxParser *parser, CtxCode code, int a
           {
             case 0:
             case 3:
-              *value *= (parser->width/100.0);
+              *value *= (parser->width/100.0f);
               break;
             case 1:
             case 4:
-              *value *= (parser->height/100.0);
+              *value *= (parser->height/100.0f);
               break;
             case 2:
             case 5:
-              *value *= small/100.0;
+              *value *= small/100.0f;
               break;
           }
         break;
@@ -29955,47 +31948,47 @@ static void ctx_parser_transform_percent (CtxParser *parser, CtxCode code, int a
       case CTX_LINE_WIDTH:
       case CTX_LINE_DASH_OFFSET:
         {
-          *value *= (small/100.0);
+          *value *= (small/100.0f);
         }
         break;
       case CTX_ARC_TO:
       case CTX_REL_ARC_TO:
         if (arg_no > 3)
           {
-            *value *= (small/100.0);
+            *value *= (small/100.0f);
           }
         else
           {
             if (arg_no % 2 == 0)
-              { *value  *= ( (parser->width) /100.0); }
+              { *value  *= ( (parser->width) /100.0f); }
             else
-              { *value *= ( (parser->height) /100.0); }
+              { *value *= ( (parser->height) /100.0f); }
           }
         break;
       case CTX_ROUND_RECTANGLE:
         if (arg_no == 4)
         {
-          { *value *= ((parser->height)/100.0); }
+          { *value *= ((parser->height)/100.0f); }
           return;
         }
         /* FALLTHROUGH */
       default: // even means x coord
         if (arg_no % 2 == 0)
-          { *value  *= ((parser->width)/100.0); }
+          { *value  *= ((parser->width)/100.0f); }
         else
-          { *value *= ((parser->height)/100.0); }
+          { *value *= ((parser->height)/100.0f); }
         break;
     }
 }
 
 static void ctx_parser_transform_percent_height (CtxParser *parser, CtxCode code, int arg_no, float *value)
 {
-  *value *= (parser->height/100.0);
+  *value *= (parser->height/100.0f);
 }
 
 static void ctx_parser_transform_percent_width (CtxParser *parser, CtxCode code, int arg_no, float *value)
 {
-  *value *= (parser->height/100.0);
+  *value *= (parser->height/100.0f);
 }
 
 static void ctx_parser_transform_cell (CtxParser *parser, CtxCode code, int arg_no, float *value)
@@ -30333,7 +32326,7 @@ static inline void ctx_parser_feed_byte (CtxParser *parser, char byte)
                 if (parser->decimal)
                   {
                     parser->decimal *= 10;
-                    parser->numbers[parser->n_numbers] += (byte - '0') / (1.0 * parser->decimal);
+                    parser->numbers[parser->n_numbers] += (byte - '0') / (1.0f * parser->decimal);
                   }
                 else
                   {
@@ -30565,9 +32558,9 @@ ctx_parse (Ctx *ctx, const char *string)
                                            ctx_get_font_size(ctx),
                                            ctx_get_font_size(ctx),
                                            0, 0, NULL, NULL, NULL, NULL, NULL);
-  ctx_parser_feed_bytes (parser, string, strlen (string));
+  ctx_parser_feed_bytes (parser, string, ctx_strlen (string));
   ctx_parser_feed_bytes (parser, " ", 1);
-  ctx_parser_free (parser);
+  ctx_parser_destroy (parser);
 }
 
 CTX_EXPORT void
@@ -30578,7 +32571,7 @@ ctx_parse2 (Ctx *ctx, const char *string, float *scene_elapsed_time,
   int scene_no = *scene_no_p;
   CtxString *str = ctx_string_new ("");
   int in_var = 0;
-  float scene_duration = 5.0;
+  float scene_duration = 5.0f;
 
   int i;
 
@@ -30620,7 +32613,7 @@ again:
        }
        else if (p>='0' && p<='9' && duration < 0)
        {
-          duration = atof (&string[i]);
+          duration = _ctx_parse_float (&string[i], NULL);
        }
     }
     else
@@ -30721,19 +32714,19 @@ again:
           prev_val = val;
         }
         if (resolved_val <= -100000.0f) resolved_val = prev_val;
-        ctx_string_append_printf (str, "%f", resolved_val);
+        ctx_string_append_printf (str, "%f", (double)resolved_val);
         in_var = 0;
       }
       else if (p>='0' && p<='9')
       {
-        const char *sp = &string[i];
-        char *ep = (char*)sp;
-        float key      = strtof (sp, &ep);
+        char *sp = (char*)&string[i];
+        char *ep = sp;
+        float key      = _ctx_parse_float (sp, &ep);
         char *eq       = strchr (sp, '=');
         float val      = 0.0;
 
         if (eq)
-           val = strtof (eq+1, &ep);
+           val = _ctx_parse_float (eq+1, &ep);
 
         keys[n_keys] = key;
         values[n_keys++] = val;
@@ -30784,7 +32777,7 @@ static void ctx_string_init (CtxString *string, int initial_size)
   string->allocated_length = initial_size;
   string->length = 0;
   string->utf8_length = 0;
-  string->str = (char*)malloc (string->allocated_length + 1);
+  string->str = (char*)ctx_malloc (string->allocated_length + 1);
   string->str[0]='\0';
 }
 
@@ -30792,7 +32785,7 @@ static void ctx_string_destroy (CtxString *string)
 {
   if (string->str)
     {
-      free (string->str);
+      ctx_free (string->str);
       string->str = NULL;
     }
 }
@@ -30808,8 +32801,9 @@ void ctx_string_clear (CtxString *string)
 void ctx_string_pre_alloc (CtxString *string, int size)
 {
   char *old = string->str;
+  int old_len = string->allocated_length;
   string->allocated_length = CTX_MAX (size + 2, string->length + 2);
-  string->str = (char*)realloc (old, string->allocated_length);
+  string->str = (char*)ctx_realloc (old, old_len, string->allocated_length);
 }
 
 
@@ -30820,8 +32814,9 @@ static inline void _ctx_string_append_byte (CtxString *string, char  val)
   if (CTX_UNLIKELY(string->length + 2 >= string->allocated_length))
     {
       char *old = string->str;
+      int old_len = string->allocated_length;
       string->allocated_length = CTX_MAX (string->allocated_length * 2, string->length + 2);
-      string->str = (char*)realloc (old, string->allocated_length);
+      string->str = (char*)ctx_realloc (old, old_len, string->allocated_length);
     }
   string->str[string->length++] = val;
   string->str[string->length] = '\0';
@@ -30929,14 +32924,14 @@ ctx_string_free (CtxString *string, int freealloc)
   {
     VtLine *line = (VtLine*)string;
     if (line->style)
-      { free (line->style); }
+      { ctx_free (line->style); }
     if (line->ctx)
-      { ctx_free (line->ctx); }
+      { ctx_destroy (line->ctx); }
     if (line->ctx_copy)
-      { ctx_free (line->ctx_copy); }
+      { ctx_destroy (line->ctx_copy); }
   }
 #endif
-  free (string);
+  ctx_free (string);
 }
 
 char       *ctx_string_dissolve       (CtxString *string)
@@ -30953,14 +32948,6 @@ ctx_string_set (CtxString *string, const char *new_string)
   _ctx_string_append_str (string, new_string);
 }
 
-static char *ctx_strdup (const char *str)
-{
-  int len = strlen (str);
-  char *ret = (char*)malloc (len + 1);
-  memcpy (ret, str, len);
-  ret[len]=0;
-  return ret;
-}
 
 void ctx_string_replace_utf8 (CtxString *string, int pos, const char *new_glyph)
 {
@@ -30999,7 +32986,7 @@ void ctx_string_replace_utf8 (CtxString *string, int pos, const char *new_glyph)
       strcpy (tmp, string->str);
       defer = string->str;
       string->str = tmp;
-      free (defer);
+      ctx_free (defer);
     }
   char *p = (char *) ctx_utf8_skip (string->str, pos);
   int prev_len = ctx_utf8_len (*p);
@@ -31016,11 +33003,11 @@ void ctx_string_replace_utf8 (CtxString *string, int pos, const char *new_glyph)
         { rest = ctx_strdup (p + prev_len); }
     }
   memcpy (p, new_glyph, new_len);
-  memcpy (p + new_len, rest, strlen (rest) + 1);
+  memcpy (p + new_len, rest, ctx_strlen (rest) + 1);
   string->length += new_len;
   string->length -= prev_len;
-  free (rest);
-  //string->length = strlen (string->str);
+  ctx_free (rest);
+  //string->length = ctx_strlen (string->str);
   //string->utf8_length = ctx_utf8_strlen (string->str);
 }
 
@@ -31070,7 +33057,7 @@ void ctx_string_insert_utf8 (CtxString *string, int pos, const char *new_glyph)
       strcpy (tmp, string->str);
       defer = string->str;
       string->str = tmp;
-      free (defer);
+      ctx_free (defer);
     }
   char *p = (char *) ctx_utf8_skip (string->str, pos);
   int prev_len = ctx_utf8_len (*p);
@@ -31084,9 +33071,9 @@ void ctx_string_insert_utf8 (CtxString *string, int pos, const char *new_glyph)
       rest = ctx_strdup (p);
     }
   memcpy (p, new_glyph, new_len);
-  memcpy (p + new_len, rest, strlen (rest) + 1);
-  free (rest);
-  string->length = strlen (string->str);
+  memcpy (p + new_len, rest, ctx_strlen (rest) + 1);
+  ctx_free (rest);
+  string->length = ctx_strlen (string->str);
   string->utf8_length = ctx_utf8_strlen (string->str);
 }
 
@@ -31126,8 +33113,8 @@ void ctx_string_remove (CtxString *string, int pos)
     }
   strcpy (p, rest);
   string->str[string->length - prev_len] = 0;
-  free (rest);
-  string->length = strlen (string->str);
+  ctx_free (rest);
+  string->length = ctx_strlen (string->str);
   string->utf8_length = ctx_utf8_strlen (string->str);
 }
 
@@ -31138,7 +33125,7 @@ char *ctx_strdup_printf (const char *format, ...)
   char *buffer;
   va_start (ap, format);
   needed = vsnprintf (NULL, 0, format, ap) + 1;
-  buffer = (char*)malloc (needed);
+  buffer = (char*)ctx_malloc (needed);
   va_end (ap);
   va_start (ap, format);
   vsnprintf (buffer, needed, format, ap);
@@ -31153,13 +33140,13 @@ void ctx_string_append_printf (CtxString *string, const char *format, ...)
   char *buffer;
   va_start (ap, format);
   needed = vsnprintf (NULL, 0, format, ap) + 1;
-  buffer = (char*)malloc (needed);
+  buffer = (char*)ctx_malloc (needed);
   va_end (ap);
   va_start (ap, format);
   vsnprintf (buffer, needed, format, ap);
   va_end (ap);
   ctx_string_append_str (string, buffer);
-  free (buffer);
+  ctx_free (buffer);
 }
 
 CtxString *ctx_string_new_printf (const char *format, ...)
@@ -31170,25 +33157,86 @@ CtxString *ctx_string_new_printf (const char *format, ...)
   char *buffer;
   va_start (ap, format);
   needed = vsnprintf (NULL, 0, format, ap) + 1;
-  buffer = (char*)malloc (needed);
+  buffer = (char*)ctx_malloc (needed);
   va_end (ap);
   va_start (ap, format);
   vsnprintf (buffer, needed, format, ap);
   va_end (ap);
   ctx_string_append_str (string, buffer);
-  free (buffer);
+  ctx_free (buffer);
   return string;
 }
 
+
+void
+ctx_string_append_int (CtxString *string, int val)
+{
+  char buf[64];
+  char *bp = &buf[0];
+  int remainder;
+  if (val < 0)
+  {
+    buf[0]='-';
+    bp++;
+    remainder = -val;
+  }
+  else
+  remainder = val;
+
+  int len = 0;
+  do {
+    int digit = remainder % 10;
+    bp[len++] = digit + '0';
+    remainder /= 10;
+  } while (remainder);
+
+  bp[len]=0;
+  for (int i = 0; i < len/2; i++)
+  {
+    int tmp = bp[i];
+    bp[i] = bp[len-1-i];
+    bp[len-1-i] = tmp;
+  }
+  len += (val < 0);
+  ctx_string_append_str (string, buf);
+}
+
+void
+ctx_string_append_float (CtxString *string, float val)
+{
+  if (val < 0.0f)
+  {
+    ctx_string_append_byte (string, '-');
+    val = -val;
+  }
+  int remainder = ((int)(val*10000))%10000;
+  if (remainder % 10 > 5)
+    remainder = remainder/10+1;
+  else
+    remainder /= 10;
+  ctx_string_append_int (string, (int)val);
+  if (remainder)
+  {
+    if (remainder<0)
+      remainder=-remainder;
+    ctx_string_append_byte (string, '.');
+    if (remainder < 10)
+      ctx_string_append_byte (string, '0');
+    if (remainder < 100)
+      ctx_string_append_byte (string, '0');
+    ctx_string_append_int (string, remainder);
+  }
+}
+
 void ctx_drawlist_clear (Ctx *ctx)
 {
   ctx->drawlist.count = 0;
   ctx->drawlist.bitpack_pos = 0;
 }
 
-static void ctx_drawlist_backend_free (CtxBackend *backend)
+static void ctx_drawlist_backend_destroy (CtxBackend *backend)
 {
-  free (backend);
+  ctx_free (backend);
 }
 
 static void ctx_update_current_path (Ctx *ctx, CtxEntry *entry)
@@ -31210,13 +33258,15 @@ static void ctx_update_current_path (Ctx *ctx, CtxEntry *entry)
       case CTX_CLOSE_PATH:
       case CTX_LINE_TO:
       case CTX_MOVE_TO:
+      case CTX_CURVE_TO:
       case CTX_QUAD_TO:
       case CTX_SMOOTH_TO:
       case CTX_SMOOTHQ_TO:
+      case CTX_REL_LINE_TO:
+      case CTX_REL_MOVE_TO:
       case CTX_REL_QUAD_TO:
       case CTX_REL_SMOOTH_TO:
       case CTX_REL_SMOOTHQ_TO:
-      case CTX_CURVE_TO:
       case CTX_REL_CURVE_TO:
       case CTX_ARC:
       case CTX_ARC_TO:
@@ -31248,9 +33298,9 @@ ctx_drawlist_process (Ctx *ctx, CtxEntry *entry)
 
 static CtxBackend *ctx_drawlist_backend_new (void)
 {
-  CtxBackend *backend = (CtxBackend*)calloc (sizeof (CtxBackend), 1);
+  CtxBackend *backend = (CtxBackend*)ctx_calloc (sizeof (CtxBackend), 1);
   backend->process = (void(*)(Ctx *a, CtxCommand *c))ctx_drawlist_process;
-  backend->free    = (void(*)(void *a))ctx_drawlist_backend_free;
+  backend->destroy = (void(*)(void *a))ctx_drawlist_backend_destroy;
   return backend;
 }
 
@@ -31284,18 +33334,17 @@ _ctx_add_hash (CtxHasher *hasher, CtxIntRectangle *shape_rect, uint32_t hash)
       if (ctx_rect_intersect (shape_rect, &rect))
       {
         hasher->hashes[(row * hasher->cols + col)] ^= hash;
+        hasher->hashes[(row * hasher->cols + col)] += 11;
         active |= (1<<hno);
       }
     }
 
-  if (hasher->active_info_count+1 >= hasher->active_info_size)
+  if (hasher->prev_command>=0)
   {
-    hasher->active_info_size = hasher->active_info_size * 2 + 1024;
-    hasher->active_info = realloc (hasher->active_info, hasher->active_info_size * sizeof (CtxCommandState));
+    hasher->drawlist->entries[hasher->prev_command].data.u32[1] = active;
   }
-  hasher->active_info[hasher->active_info_count].pos = hasher->pos;
-  hasher->active_info[hasher->active_info_count].active = active;
-  hasher->active_info_count++;
+
+  hasher->prev_command = hasher->pos;
 }
 
 static int
@@ -31351,7 +33400,7 @@ static inline void murmur3_32_init (CtxMurmur *murmur)
 }
 static inline void murmur3_32_free (CtxMurmur *murmur)
 {
-  free (murmur);
+  ctx_free (murmur);
 }
 static inline uint32_t murmur3_32_finalize (CtxMurmur *murmur)
 {
@@ -31383,6 +33432,28 @@ static inline int murmur3_32_done (CtxMurmur *murmur, unsigned char *out)
  * as stroke/fill can be ignored  clips outside
  * should mean no more drawing until restore
  */
+
+static inline void
+ctx_device_corners_to_user_rect (CtxState *state,
+                                 float x0, float y0, float x1, float y1,
+                                 CtxIntRectangle *shape_rect)
+{
+  int itw, ith;
+  int itx = 0, ity = 0, itx2 = 0, ity2 = 0;
+  _ctx_user_to_device_prepped (state, x0, y0, &itx, &ity);
+  _ctx_user_to_device_prepped (state, x1, y1, &itx2, &ity2);
+  itx /= CTX_SUBDIV;
+  itx2 /= CTX_SUBDIV;
+  ity /= CTX_FULL_AA;
+  ity2 /= CTX_FULL_AA;
+  itw = itx2-itx;
+  ith = ity2-ity;
+  shape_rect->x=itx;
+  shape_rect->y=ity;
+  shape_rect->width = itw;
+  shape_rect->height = ith;
+}
+
 static void
 ctx_hasher_process (Ctx *ctx, CtxCommand *command)
 {
@@ -31410,18 +33481,12 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
            CtxIntRectangle shape_rect;
 
            float tx = rasterizer->x;
-           float ty = rasterizer->y - height * 1.2;
-           float tw = width;
-           float th = height * (ctx_str_count_lines (str) + 1.5);
+           float ty = rasterizer->y - height * 1.2f;
+           float tx2 = tx+width;
+           float ty2 = ty+height * (ctx_str_count_lines (str) + 1.5f);
 
-           _ctx_user_to_device (rasterizer->state, &tx, &ty);
-           _ctx_user_to_device_distance (rasterizer->state, &tw, &th);
-          
-           shape_rect.x=tx;
-           shape_rect.y=ty;
-           shape_rect.width = tw;
-           shape_rect.height = th;
-          switch ((int)ctx_state_get (rasterizer->state, CTX_text_align))
+           ctx_device_corners_to_user_rect (rasterizer->state, tx,ty,tx2,ty2, &shape_rect);
+          switch ((int)ctx_state_get (rasterizer->state, CTX_textAlign))
           {
           case CTX_TEXT_ALIGN_LEFT:
           case CTX_TEXT_ALIGN_START:
@@ -31436,11 +33501,7 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
                    // XXX : doesn't take all text-alignments into account
           }
 
-#if 0
-          uint32_t color;
-          ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, 
(uint8_t*)(&color));
-#endif
-          murmur3_32_process(&murmur, (const unsigned char*)ctx_arg_string(), strlen  (ctx_arg_string()));
+          murmur3_32_process(&murmur, (const unsigned char*)ctx_arg_string(), ctx_strlen  
(ctx_arg_string()));
 #if 1
         murmur3_32_process(&murmur, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof 
(rasterizer->state->gstate.transform));
     //      murmur3_32_process(&murmur, (unsigned char*)&color, 4);
@@ -31463,23 +33524,17 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
            CtxIntRectangle shape_rect;
 
            float tx = rasterizer->x;
-           float ty = rasterizer->y;
-           float tw = width;
-           float th = height * (ctx_str_count_lines (str));
+           float ty = rasterizer->y - height * 1.2f;
+           float tx2 = tx+width;
+           float ty2 = ty+height * (ctx_str_count_lines (str) + 1.5f);
+           ctx_device_corners_to_user_rect (rasterizer->state, tx,ty,tx2,ty2, &shape_rect);
 
-           _ctx_user_to_device (rasterizer->state, &tx, &ty);
-           _ctx_user_to_device_distance (rasterizer->state, &tw, &th);
-          
-           shape_rect.x=tx;
-           shape_rect.y=ty;
-           shape_rect.width = tw;
-           shape_rect.height = th;
 
 #if 0
           uint32_t color;
           ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_stroke.color, 
(uint8_t*)(&color));
 #endif
-          murmur3_32_process(&murmur, (unsigned char*)ctx_arg_string(), strlen  (ctx_arg_string()));
+          murmur3_32_process(&murmur, (unsigned char*)ctx_arg_string(), ctx_strlen  (ctx_arg_string()));
 #if 1
           murmur3_32_process(&murmur, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof 
(rasterizer->state->gstate.transform));
     //    murmur3_32_process(&murmur, (unsigned char*)&color, 4);
@@ -31503,19 +33558,19 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
 
           float tx = rasterizer->x;
           float ty = rasterizer->y;
-          float tw = width;
-          float th = height * 2;
+          float tx2 = rasterizer->x + width;
+          float ty2 = rasterizer->y + height * 2;
+          CtxIntRectangle shape_rect;
+          ctx_device_corners_to_user_rect (rasterizer->state, tx,ty,tx2,ty2, &shape_rect);
 
-          _ctx_user_to_device (rasterizer->state, &tx, &ty);
-          _ctx_user_to_device_distance (rasterizer->state, &tw, &th);
-          CtxIntRectangle shape_rect = {(int)tx,(int)(ty-th/2),(int)tw,(int)th};
+          shape_rect.y-=shape_rect.height/2;
 
 
 #if 0
           uint32_t color;
           ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, 
(uint8_t*)(&color));
 #endif
-          murmur3_32_process(&murmur, string, strlen ((const char*)string));
+          murmur3_32_process(&murmur, string, ctx_strlen ((const char*)string));
           murmur3_32_process(&murmur, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof 
(rasterizer->state->gstate.transform));
 #if 0
           murmur3_32_process(&murmur, (unsigned char*)&color, 4);
@@ -31540,9 +33595,9 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
           int is = rasterizer->state->gstate.fill_rule;
           murmur3_32_process(&murmur, (uint8_t*)&is, sizeof(int));
         }
-        CtxIntRectangle shape_rect = {0,0,
-                rasterizer->blit_width,
-                rasterizer->blit_height};
+        CtxIntRectangle shape_rect = {-100,-100,
+                rasterizer->blit_width*10,
+                rasterizer->blit_height*10};
         _ctx_add_hash (hasher, &shape_rect, murmur3_32_finalize (&murmur));
         }
 
@@ -31558,10 +33613,10 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
            */
         //uint64_t hash = ctx_rasterizer_poly_to_hash2 (rasterizer); // + hasher->salt;
         CtxIntRectangle shape_rect = {
-          (int)(rasterizer->col_min / CTX_SUBDIV - 2),
-          (int)(rasterizer->scan_min / aa - 2),
-          (int)(3+(rasterizer->col_max - rasterizer->col_min + CTX_SUBDIV-1) / CTX_SUBDIV),
-          (int)(3+(rasterizer->scan_max - rasterizer->scan_min + aa-1) / aa)
+          (int)(rasterizer->col_min / CTX_SUBDIV - 3),
+          (int)(rasterizer->scan_min / aa - 3),
+          (int)(5+(rasterizer->col_max - rasterizer->col_min + CTX_SUBDIV-1) / CTX_SUBDIV),
+          (int)(5+(rasterizer->scan_max - rasterizer->scan_min + aa-1) / aa)
         };
 
         if (rasterizer->edge_list.count)
@@ -31604,10 +33659,10 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
           (int)((rasterizer->scan_max - rasterizer->scan_min + 1) / aa + 
rasterizer->state->gstate.line_width)
         };
 
-        shape_rect.width += rasterizer->state->gstate.line_width * 2;
-        shape_rect.height += rasterizer->state->gstate.line_width * 2;
-        shape_rect.x -= rasterizer->state->gstate.line_width;
-        shape_rect.y -= rasterizer->state->gstate.line_width;
+        shape_rect.width += (int)(rasterizer->state->gstate.line_width * 2);
+        shape_rect.height += (int)(rasterizer->state->gstate.line_width * 2);
+        shape_rect.x -= (int)(rasterizer->state->gstate.line_width);
+        shape_rect.y -= (int)(rasterizer->state->gstate.line_width);
 
         {
           float f;
@@ -31672,7 +33727,7 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
         //ctx_rasterizer_rel_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
         break;
       case CTX_ARC:
-        ctx_rasterizer_arc (rasterizer, c->arc.x, c->arc.y, c->arc.radius, c->arc.angle1, c->arc.angle2, 
c->arc.direction);
+        ctx_rasterizer_arc (rasterizer, c->arc.x, c->arc.y, c->arc.radius, c->arc.angle1, c->arc.angle2, 
(int)c->arc.direction);
         break;
       case CTX_RECTANGLE:
         ctx_rasterizer_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
@@ -31725,12 +33780,7 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
       case CTX_TRANSLATE:
       case CTX_APPLY_TRANSFORM:
 
-
-
-        rasterizer->uses_transforms = 1;
         ctx_interpret_transforms (rasterizer->state, entry, NULL);
-
-        
         break;
       case CTX_FONT:
         ctx_rasterizer_set_font (rasterizer, ctx_arg_string() );
@@ -31745,7 +33795,7 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
         {
         murmur3_32_init (&hasher->murmur_fill[hasher->source_level]);
         murmur3_32_process(&hasher->murmur_fill[hasher->source_level], 
&rasterizer->state->gstate.global_alpha_u8, 1);
-        murmur3_32_process (&hasher->murmur_fill[hasher->source_level], (uint8_t*)c->define_texture.eid, 
strlen (c->define_texture.eid));
+        murmur3_32_process (&hasher->murmur_fill[hasher->source_level], (uint8_t*)c->define_texture.eid, 
ctx_strlen (c->define_texture.eid));
         murmur3_32_process(&hasher->murmur_fill[hasher->source_level], (unsigned 
char*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
 
         rasterizer->comp_op = NULL; // why?
@@ -31754,7 +33804,7 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
       case CTX_TEXTURE:
         murmur3_32_init (&hasher->murmur_fill[hasher->source_level]);
         murmur3_32_process(&hasher->murmur_fill[hasher->source_level], 
&rasterizer->state->gstate.global_alpha_u8, 1);
-        murmur3_32_process (&hasher->murmur_fill[hasher->source_level], (uint8_t*)c->texture.eid, strlen 
(c->texture.eid));
+        murmur3_32_process (&hasher->murmur_fill[hasher->source_level], (uint8_t*)c->texture.eid, ctx_strlen 
(c->texture.eid));
         murmur3_32_process (&hasher->murmur_fill[hasher->source_level], 
(uint8_t*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
         rasterizer->comp_op = NULL; // why?
         break;
@@ -31808,13 +33858,8 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
     }
 
 #if 0
-  if (command->code == CTX_RESET)
+  if (command->code == CTX_START_FRAME)
   {
-    while (hasher->active_info)
-    {
-      free (hasher->active_info->data);
-      ctx_list_remove (&hasher->active_info, hasher->active_info->data);
-    }
   }
 #endif
 
@@ -31833,14 +33878,14 @@ ctx_hasher_process (Ctx *ctx, CtxCommand *command)
 }
 
 static CtxRasterizer *
-ctx_hasher_init (CtxRasterizer *rasterizer, Ctx *ctx, CtxState *state, int width, int height, int cols, int 
rows)
+ctx_hasher_init (CtxRasterizer *rasterizer, Ctx *ctx, CtxState *state, int width, int height, int cols, int 
rows, CtxDrawlist *drawlist)
 {
   CtxHasher *hasher = (CtxHasher*)rasterizer;
   ctx_memset (rasterizer, 0, sizeof (CtxHasher) );
   CtxBackend *backend = (CtxBackend*)hasher;
   backend->ctx         = ctx;
   backend->process = ctx_hasher_process;
-  backend->free    = (CtxDestroyNotify)ctx_rasterizer_deinit;
+  backend->destroy = (CtxDestroyNotify)ctx_rasterizer_destroy;
   // XXX need own destructor to not leak ->hashes
   rasterizer->edge_list.flags |= CTX_DRAWLIST_EDGE_LIST;
   rasterizer->state       = state;
@@ -31861,19 +33906,22 @@ ctx_hasher_init (CtxRasterizer *rasterizer, Ctx *ctx, CtxState *state, int width
   hasher->cols = cols;
   hasher->pos  = 0;
 
-  hasher->hashes = (uint32_t*)ctx_calloc (4, rows * cols);
+  hasher->drawlist = drawlist;
+  hasher->prev_command = -1;
+
+  memset(hasher->hashes,0, sizeof (hasher->hashes));
   murmur3_32_init (&hasher->murmur_fill[hasher->source_level]);
   murmur3_32_init (&hasher->murmur_stroke[hasher->source_level]);
 
   return rasterizer;
 }
 
-Ctx *ctx_hasher_new (int width, int height, int cols, int rows)
+Ctx *ctx_hasher_new (int width, int height, int cols, int rows, CtxDrawlist *drawlist)
 {
   Ctx *ctx           = _ctx_new_drawlist (width, height);
   CtxState    *state = &ctx->state;
   CtxRasterizer *rasterizer = (CtxRasterizer *) ctx_calloc (sizeof (CtxHasher), 1);
-  ctx_hasher_init (rasterizer, ctx, state, width, height, cols, rows);
+  ctx_hasher_init (rasterizer, ctx, state, width, height, cols, rows, drawlist);
   ctx_set_backend (ctx, (void*)rasterizer);
   return ctx;
 }
@@ -31886,18 +33934,933 @@ uint32_t ctx_hasher_get_hash (Ctx *ctx, int col, int row)
   if (row >= hasher->rows) row = hasher->rows-1;
   if (col >= hasher->cols) col = hasher->cols-1;
 
+  hasher->drawlist->entries[hasher->prev_command].data.u32[1] = 0xffffffff;
+
   return hasher->hashes[(row*hasher->cols+col)];
 }
 
-CtxCommandState *ctx_hasher_get_active_info (Ctx *ctx, int *count)
+#endif
+/*
+ * TODO:
+ *   gradients
+ *   text-layout
+ *   textures
+ *   links
+ *
+ */
+
+
+#if CTX_PDF
+
+#define CTX_PDF_MAX_OBJS 256
+#define CTX_PDF_MAX_RESOURCES 256 // in one page
+
+#define CTX_PDF_MAX_PAGES CTX_PDF_MAX_OBJS
+
+typedef struct _CtxPDF CtxPDF;
+enum { CTX_PDF_TIMES = 1,
+       CTX_PDF_HELVETICA, //2
+       CTX_PDF_COURIER, //3
+       CTX_PDF_SYMBOL, //4
+       CTX_PDF_TIMES_BOLD,
+       CTX_PDF_HELVETICA_BOLD,
+       CTX_PDF_COURIER_BOLD,
+       CTX_PDF_ZAPF_DING_BATS, // 8
+       CTX_PDF_TIMES_ITALIC, // 9
+       CTX_PDF_HELVETICA_ITALIC, // 10
+       CTX_PDF_COURIER_ITALIC, // 11
+       CTX_PDF_TIMES_BOLD_ITALIC, // 12
+       CTX_PDF_HELVETICA_BOLD_ITALIC, //13
+       CTX_PDF_COURIER_BOLD_ITALIC, //14
+       // courier and helvetica variants are called
+       // oblique not italic in the PDF spec
+
+};
+
+typedef struct
+_CtxPdfResource
 {
-  CtxHasher *hasher = (CtxHasher*)ctx->backend;
-  *count = hasher->active_info_count;
-  CtxCommandState *ret = hasher->active_info;
-  hasher->active_info = NULL;
-  return ret;
+  int id;
+  int type; // 0 opacity, 1 linear grad, 2 radial grad
+  union { 
+     struct { float value;}                   opacity;
+     struct { float x0, y0, x1, y1;}          linear_gradient;
+     struct { float x0, y0, r0, x1, y1, r1;}  radial_gradient;
+     struct { const char *eid;int width, height,stride,format;uint8_t *data;}  texture;
+     struct { int   no;}    font;
+     // texture
+     // linear-gradient
+     // radial-gradient
+  };
+} CtxPdfResource;
+
+
+struct
+  _CtxPDF
+{
+  CtxBackend     backend;
+  int            preserve;
+  const char    *path;
+  CtxString     *document;
+  CtxState       state;
+  int            pat;
+  int            xref[CTX_PDF_MAX_OBJS];
+  int            objs;
+  int            page_length_offset;
+  int            page_height_offset;
+  int            kids_offset;
+  int            page_count_offset;
+
+  int            width;
+  int            height;
+
+  char          *encoding;
+
+  CtxPdfResource resource[CTX_PDF_MAX_RESOURCES];
+  int            resource_count;
+
+  int            page_resource[CTX_PDF_MAX_RESOURCES];
+  int            page_resource_count;
+  int            new_resource[CTX_PDF_MAX_RESOURCES];
+  int            new_resource_count;
+
+  int            next_obj; // pre-emptive builds
+                           // during page build
+
+  float          page_size[4];
+
+  int            page_objs[CTX_PDF_MAX_PAGES];
+  int            content_objs[CTX_PDF_MAX_PAGES];
+  int            page_count;
+
+  int            pages; // known to be 1
+  int            font;
+  int            font_map;
+
+
+  int alphas[10];
+};
+
+
+#define ctx_pdf_print(str) \
+        do { ctx_string_append_str (pdf->document, str);\
+}while (0)
+#define ctx_pdf_printf(fmt, a...) \
+        do { ctx_string_append_printf (pdf->document, fmt, ##a);\
+}while (0)
+#define ctx_pdf_print1i(i0) \
+        do { ctx_string_append_int (pdf->document, i0);\
+        ctx_string_append_byte (pdf->document, ' ');\
+}while (0)
+#define ctx_pdf_print1f(f0) \
+        do { ctx_string_append_float (pdf->document, f0);\
+             ctx_string_append_byte (pdf->document, ' '); }while (0)
+#define ctx_pdf_print2f(f0,f1) \
+        do { ctx_pdf_print1f(f0);ctx_pdf_print1f(f1); }while (0)
+#define ctx_pdf_print3f(f0,f1,f2) \
+        do { ctx_pdf_print2f(f0,f1);ctx_pdf_print1f(f2); }while (0)
+#define ctx_pdf_print4f(f0,f1,f2,f3) \
+        do { ctx_pdf_print3f(f0,f1,f2);ctx_pdf_print1f(f3); }while (0)
+#define ctx_pdf_print5f(f0,f1,f2,f3,f4) \
+        do { ctx_pdf_print4f(f0,f1,f2,f3);ctx_pdf_print1f(f4); }while (0)
+#define ctx_pdf_print6f(f0,f1,f2,f3,f4,f5) \
+        do { ctx_pdf_print5f(f0,f1,f2,f3,f4);ctx_pdf_print1f(f5); }while (0)
+
+/**
+ * Generate a cubic Bezier representing an arc on the unit circle of total
+ * angle ‘size‘ radians, beginning ‘start‘ radians above the x-axis.
+ */
+static void acuteArcToBezier(float start, float size,
+                float *ax,
+                float *ay,
+                float *bx,
+                float *by,
+                float *cx,
+                float *cy,
+                float *dx,
+                float *dy
+                ) {
+  // Evaluate constants.
+  float alpha = size / 2.0,
+      cos_alpha = ctx_cosf(alpha),
+      sin_alpha = ctx_sinf(alpha),
+      cot_alpha = 1.0 / ctx_tanf(alpha),
+      phi = start + alpha, // This is how far the arc needs to be rotated.
+      cos_phi = ctx_cosf(phi),
+      sin_phi = ctx_sinf(phi),
+      lambda = (4.0 - cos_alpha) / 3.0,
+      mu = sin_alpha + (cos_alpha - lambda) * cot_alpha;
+ // Return rotated waypoints.
+ *ax = ctx_cosf(start),
+ *ay = ctx_sinf(start),
+ *bx = lambda * cos_phi + mu * sin_phi,
+ *by = lambda * sin_phi - mu * cos_phi,
+ *cx = lambda * cos_phi - mu * sin_phi,
+ *cy = lambda * sin_phi + mu * cos_phi,
+ *dx = ctx_cosf(start + size),
+ *dy = ctx_sinf(start + size);
+}
+
+
+static char *ctx_utf8_to_mac_roman (const uint8_t *string);
+static char *ctx_utf8_to_windows_1252 (const uint8_t *string);
+
+void pdf_end_object (CtxPDF *pdf)
+{
+  ctx_pdf_print("\nendobj\n");
+}
+
+int pdf_add_object (CtxPDF *pdf)
+{
+  if (pdf->objs) pdf_end_object (pdf);
+  // we use 1 indexing in this array
+  pdf->xref[++pdf->objs] = pdf->document->length;
+  ctx_pdf_printf("%i 0 obj\n", pdf->objs);
+  return pdf->objs;
 }
 
+static void
+pdf_start_page (CtxPDF *pdf)
+{
+  pdf->page_count++;
+  pdf->content_objs[pdf->page_count]=pdf_add_object (pdf); // 2 - our actual page contents
+  ctx_pdf_printf ("<</Length ");
+  pdf->page_length_offset = pdf->document->length;
+  ctx_pdf_printf ("XXXXXXXXXX>>\n");
+  ctx_pdf_printf ("stream\nBT\n1 0 0 -1 0 ");
+  pdf->page_height_offset = pdf->document->length;
+  ctx_pdf_printf ("XXXXXXXXXX cm\n/F1 24 Tf\n", pdf->height);
+
+  pdf->page_resource_count = 0;
+  pdf->new_resource_count = 0;
+  pdf->next_obj = pdf->content_objs[pdf->page_count]+1;
+}
+
+static void
+pdf_end_page (CtxPDF *pdf)
+{
+  int length = (pdf->document->length - pdf->page_length_offset) - 17;
+  char buf[11];
+  snprintf (buf, 11, "%10u", length);
+  memcpy   (&pdf->document->str[pdf->page_length_offset], buf, 10);
+  snprintf (buf, 11, "% 9f", pdf->page_size[3]);
+  memcpy   (&pdf->document->str[pdf->page_height_offset], buf, 10);
+  ctx_pdf_printf("\nET\nendstream\n");
+
+  for (int i = 0; i < pdf->new_resource_count; i ++)
+  {
+    float opacity = 1.0f;
+    for (int j = 0; j < pdf->resource_count; j ++)
+    {
+      if (pdf->resource[j].id == pdf->new_resource[i])
+        opacity = pdf->resource[j].opacity.value;
+    }
+    pdf->alphas[i]=pdf_add_object (pdf); // 4
+    ctx_pdf_printf ("<</Type/ExtGState/ca %.2f/CA %.2f>>", opacity, opacity);
+  }
+
+   pdf->page_objs[pdf->page_count]=pdf_add_object (pdf);
+   ctx_pdf_printf ("<<"
+"/Contents %i 0 R/Type/Page/Resources<</ProcSet[/PDF/Text]/Font %i 0 R", pdf->content_objs[pdf->page_count], 
pdf->font_map);
+   ctx_pdf_printf ("/ExtGState");
+
+   ctx_pdf_printf ("<<");
+   for (int i = 0; i < pdf->page_resource_count; i++)
+   {
+     ctx_pdf_printf ("/G%i %i 0 R", pdf->page_resource[i],
+                                    pdf->page_resource[i]);
+   }
+   ctx_pdf_print (">>");
+   ctx_pdf_print (">>/Parent ");
+   ctx_pdf_print1i (pdf->pages);ctx_pdf_print ("0 R");
+   ctx_pdf_print ("/MediaBox[");
+   ctx_pdf_print4f (pdf->page_size[0], pdf->page_size[1],
+                    pdf->page_size[2]+pdf->page_size[0], pdf->page_size[3]+pdf->page_size[1]);
+   ctx_pdf_print ("]>>");
+
+}
+
+
+void ctx_pdf_set_opacity (CtxPDF *pdf, float alpha)
+{
+  int obj_no = 0;
+
+  for (int i = 0; i < pdf->resource_count; i++)
+  {
+    if (pdf->resource[i].type == 0 &&
+        pdf->resource[i].opacity.value == alpha)
+    {
+      obj_no = pdf->resource[i].id;
+    }
+  }
+
+  if (obj_no == 0)
+  {
+     pdf->resource[pdf->resource_count].type = 0;
+     pdf->resource[pdf->resource_count].opacity.value = alpha;
+     obj_no = pdf->resource[pdf->resource_count].id = 
+             pdf->next_obj++;
+     pdf->resource_count++;
+
+     pdf->new_resource[pdf->new_resource_count++] =
+       obj_no;
+  }
+
+  ctx_pdf_printf("/G%i gs ", obj_no);
+
+  for (int i = 0; i < pdf->page_resource_count; i ++)
+  {
+    if (pdf->page_resource[i] == obj_no)
+      return;
+  }
+  pdf->page_resource[pdf->page_resource_count++] = obj_no;
+}
+
+static void
+ctx_pdf_line_to (Ctx *ctx, float x, float y)
+{
+  CtxPDF *pdf = (void*)ctx->backend;
+  ctx_pdf_print2f(x, y); ctx_pdf_print("l ");
+}
+static void
+ctx_pdf_move_to (Ctx *ctx, float x, float y)
+{
+  CtxPDF *pdf = (void*)ctx->backend;
+  ctx_pdf_print2f(x, y); ctx_pdf_print("m ");
+}
+static void
+ctx_pdf_curve_to (Ctx *ctx, float cx0, float cy0, float cx1, float cy1, float x, float y)
+{
+  CtxPDF *pdf = (void*)ctx->backend;
+  ctx_pdf_print6f(cx0,cy0,cx1,cy1,x,y); ctx_pdf_print("c ");
+}
+
+static void
+ctx_pdf_apply_transform (Ctx *ctx, float a, float b, float c, float d, float e, float f)
+{
+  CtxPDF *pdf = (void*)ctx->backend;
+  ctx_pdf_print6f(a,b,c,d,e,f);
+  ctx_pdf_print("cm\n");
+}
+
+static void
+ctx_pdf_process (Ctx *ctx, CtxCommand *c)
+{
+  CtxPDF *pdf = (void*)ctx->backend;
+  CtxEntry *entry = (CtxEntry *) &c->entry;
+  CtxState *state = &pdf->state;
+
+  CtxDrawlist *preserved = NULL;
+
+  ctx_interpret_style (&pdf->state, entry, NULL);
+
+  switch (entry->code)
+    {
+      case CTX_NEW_PAGE:
+        pdf_end_page (pdf);
+        pdf_start_page (pdf);
+        break;
+
+      case CTX_LINE_TO:         ctx_pdf_line_to (ctx, c->line_to.x, c->line_to.y); break;
+      case CTX_HOR_LINE_TO:     ctx_pdf_line_to (ctx, ctx_arg_float(0), state->y); break;
+      case CTX_VER_LINE_TO:     ctx_pdf_line_to (ctx, state->x, ctx_arg_float(0)); break;
+      case CTX_REL_LINE_TO:     ctx_pdf_line_to (ctx, c->line_to.x + state->x, c->line_to.y + state->y); 
break;
+      case CTX_REL_HOR_LINE_TO: ctx_pdf_line_to (ctx, ctx_arg_float(0) + state->x, state->y); break;
+      case CTX_REL_VER_LINE_TO: ctx_pdf_line_to (ctx, state->x, ctx_arg_float(0) + state->y); break;
+
+      case CTX_MOVE_TO:         ctx_pdf_move_to (ctx, c->move_to.x, c->move_to.y); break;
+      case CTX_REL_MOVE_TO:     ctx_pdf_move_to (ctx, c->move_to.x + state->x, c->move_to.y + state->y); 
break;
+
+      case CTX_CURVE_TO:
+        ctx_pdf_curve_to (ctx, c->curve_to.cx1, c->curve_to.cy1,
+                               c->curve_to.cx2, c->curve_to.cy2,
+                               c->curve_to.x, c->curve_to.y);
+        break;
+
+
+      case CTX_REL_CURVE_TO:
+        ctx_pdf_curve_to (ctx, c->curve_to.cx1 + state->x, c->curve_to.cy1 + state->y,
+                               c->curve_to.cx2 + state->x, c->curve_to.cy2 + state->y,
+                               c->curve_to.x   + state->x, c->curve_to.y   + state->y);
+        break;
+
+
+      case CTX_PRESERVE:
+        pdf->preserve = 1;
+        break;
+
+      case CTX_QUAD_TO:
+        {
+          float cx = ctx_arg_float (0);
+          float cy = ctx_arg_float (1);
+          float  x = ctx_arg_float (2);
+          float  y = ctx_arg_float (3);
+          float cx1 = (cx * 2 + state->x) / 3.0f;
+          float cy1 = (cy * 2 + state->y) / 3.0f;
+          float cx2 = (cx * 2 + x) / 3.0f;
+          float cy2 = (cy * 2 + y) / 3.0f;
+          ctx_pdf_curve_to (ctx, cx1, cy1, cx2, cy2, x, y);
+        }
+        break;
+
+      case CTX_REL_QUAD_TO:
+        {
+          float cx = ctx_arg_float (0);
+          float cy = ctx_arg_float (1);
+          float  x = ctx_arg_float (2);
+          float  y = ctx_arg_float (3);
+          float cx1 = (cx * 2 ) / 3.0f;
+          float cy1 = (cy * 2 ) / 3.0f;
+          float cx2 = (cx * 2 + x) / 3.0f;
+          float cy2 = (cy * 2 + y) / 3.0f;
+          ctx_pdf_curve_to (ctx, cx1 + state->x, cy1 + state->y,
+                                 cx2 + state->x, cy2 + state->y,
+                                 x   + state->x, y   + state->y);
+        }
+        break;
+
+      case CTX_LINE_WIDTH:
+        ctx_pdf_printf("%f w\n", ctx_arg_float (0));
+        break;
+
+      case CTX_ARC:
+        {
+           float x = c->arc.x,
+                 y = c->arc.y,
+                 w = c->arc.radius,
+                 h = c->arc.radius,
+                 stop  = c->arc.angle1,
+                 start = c->arc.angle2;
+                 //direction = c->arc.direction;
+
+           start = start * 0.99;
+
+           while (start < 0) start += CTX_PI * 2;
+           while (stop < 0) stop += CTX_PI * 2;
+
+           start = ctx_fmodf (start, CTX_PI * 2);
+           stop  = ctx_fmodf (stop, CTX_PI * 2);
+           // Adjust angles to counter linear scaling.
+           if (start <= CTX_PI/2) {
+             start = ctx_atanf(w / h * ctx_tanf(start));
+           } else if (start > CTX_PI/2 && start <= 3 * CTX_PI/2) {
+             start = ctx_atanf(w / h * ctx_tanf(start)) + CTX_PI;
+           } else {
+             start = ctx_atanf(w / h * ctx_tanf(start)) + CTX_PI*2;
+           }
+           if (stop <= CTX_PI/2) {
+             stop = ctx_atanf(w / h * ctx_tanf(stop));
+           } else if (stop > CTX_PI/2 && stop <= 3 * CTX_PI/2) {
+             stop = ctx_atanf (w / h * ctx_tanf(stop)) + CTX_PI;
+           } else {
+             stop = ctx_atanf (w / h * ctx_tanf(stop)) + CTX_PI*2;
+           }
+           // Exceed the interval if necessary in order to preserve the size and
+           // orientation of the arc.
+           if (start > stop) {
+             stop += CTX_PI * 2;
+           }
+             // Create curves
+             float epsilon = 0.00001f; // Smallest visible angle on displays up to 4K.
+             float arcToDraw = 0;
+             float curves[4][8]={{0.0f,}};
+             int n_curves = 0;
+             while(stop - start > epsilon) {
+               arcToDraw = ctx_minf(stop - start, CTX_PI/2);
+               {
+                 //float cx0, cy0, cx1, cy1, cx2, cy2, x, y;
+                 acuteArcToBezier(start, arcToDraw, 
+                                 &curves[n_curves][0], &curves[n_curves][1],
+                                 &curves[n_curves][2], &curves[n_curves][3],
+                                 &curves[n_curves][4], &curves[n_curves][5],
+                                 &curves[n_curves][6], &curves[n_curves][7]);
+                 n_curves++;
+               }
+             start += arcToDraw;
+           }
+
+             float rx = w / 2.0f;
+             float ry = h / 2.0f;
+             ctx_pdf_print2f(x + rx * curves[0][0], y + ry * curves[0][1]);
+             ctx_pdf_print("m\n");
+             for (int i = 0; i < n_curves; i++)
+             {
+               ctx_pdf_curve_to (ctx, x + rx * curves[i][2], y + ry * curves[i][3],
+                                  x + rx * curves[i][4], y + ry * curves[i][5],
+                                  x + rx * curves[i][6], y + ry * curves[i][7]);
+             }
+        }
+#if 0
+        fprintf (stderr, "F %2.1f %2.1f %2.1f %2.1f %2.1f %2.1f\n",
+                        ctx_arg_float(0),
+                        ctx_arg_float(1),
+                        ctx_arg_float(2),
+                        ctx_arg_float(3),
+                        ctx_arg_float(4),
+                        ctx_arg_float(5),
+                        ctx_arg_float(6));
+        if (ctx_arg_float (5) == 1)
+          pdf_arc (cr, ctx_arg_float (0), ctx_arg_float (1),
+                     ctx_arg_float (2), ctx_arg_float (3),
+                     ctx_arg_float (4) );
+        else
+          pdf_arc_negative (cr, ctx_arg_float (0), ctx_arg_float (1),
+                              ctx_arg_float (2), ctx_arg_float (3),
+                              ctx_arg_float (4) );
+#endif
+        break;
+
+      case CTX_COLOR:
+        int space =  ((int) ctx_arg_float (0)) & 511;
+        switch (space) // XXX remove 511 after stroke source is complete
+        {
+           case CTX_RGBA:
+           case CTX_DRGBA:
+             ctx_pdf_set_opacity (pdf, c->rgba.a);
+             /*FALLTHROUGH*/
+           case CTX_RGB:
+              if (space == CTX_RGB || space == CTX_DRGB)
+                ctx_pdf_set_opacity (pdf, 1.0);
+             ctx_pdf_print3f(c->rgba.r, c->rgba.g, c->rgba.b);
+             ctx_pdf_print("rg ");
+             ctx_pdf_print3f(c->rgba.r, c->rgba.g, c->rgba.b);
+             ctx_pdf_print("RG\n");
+             break;
+           case CTX_CMYKA:
+           case CTX_DCMYKA:
+             ctx_pdf_set_opacity (pdf, c->cmyka.a);
+               /*FALLTHROUGH*/
+           case CTX_CMYK:
+           case CTX_DCMYK:
+              if (space == CTX_CMYK || space == CTX_DCMYK)
+                ctx_pdf_set_opacity (pdf, 1.0);
+              ctx_pdf_print4f(c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k);
+              ctx_pdf_print("k ");
+              ctx_pdf_print4f(c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k);
+              ctx_pdf_print("K ");
+              break;
+           case CTX_GRAYA:
+             ctx_pdf_set_opacity (pdf, c->graya.a);
+               /*FALLTHROUGH*/
+           case CTX_GRAY:
+              if (space == CTX_GRAY)
+                ctx_pdf_set_opacity (pdf, 1.0);
+              ctx_pdf_print1f(c->graya.g);
+              ctx_pdf_print("g ");
+              ctx_pdf_print1f(c->graya.g);
+              ctx_pdf_print("G\n");
+              break;
+            }
+        break;
+
+      case CTX_SET_RGBA_U8:
+        ctx_pdf_printf("/G%i gs\n", ctx_arg_u8(3)*10/255);
+        ctx_pdf_printf("%f %f %f RG\n",
+                               ctx_u8_to_float (ctx_arg_u8 (0) ),
+                               ctx_u8_to_float (ctx_arg_u8 (1) ),
+                               ctx_u8_to_float (ctx_arg_u8 (2) ));
+        ctx_pdf_printf("%f %f %f rg\n",
+                               ctx_u8_to_float (ctx_arg_u8 (0) ),
+                               ctx_u8_to_float (ctx_arg_u8 (1) ),
+                               ctx_u8_to_float (ctx_arg_u8 (2) ));
+        break;
+
+      case CTX_RECTANGLE:
+      case CTX_ROUND_RECTANGLE:
+        ctx_pdf_print4f(c->rectangle.x, c->rectangle.y,
+                        c->rectangle.width, c->rectangle.height);
+        ctx_pdf_print("re\n");
+        break;
+
+      case CTX_SET_PIXEL:
+#if 0
+        pdf_set_source_rgba (cr, ctx_u8_to_float (ctx_arg_u8 (0) ),
+                               ctx_u8_to_float (ctx_arg_u8 (1) ),
+                               ctx_u8_to_float (ctx_arg_u8 (2) ),
+                               ctx_u8_to_float (ctx_arg_u8 (3) ) );
+        pdf_rectangle (cr, ctx_arg_u16 (2), ctx_arg_u16 (3), 1, 1);
+        pdf_fill (cr);
+#endif
+        break;
+
+      case CTX_FILL:
+        if (pdf->preserve)
+        {
+          preserved = ctx_current_path (ctx);
+          pdf->preserve = 0;
+        }
+        ctx_pdf_print ("f\n");
+        break;
+
+      case CTX_TRANSLATE:
+         ctx_pdf_apply_transform (ctx, 1.f, 0.f, 0.f, 1.f, c->f.a0, c->f.a1); 
+         break;
+      case CTX_SCALE:     
+         ctx_pdf_apply_transform (ctx, c->f.a0, 0.f, 0.f, c->f.a1, 0.f, 0.f); 
+         break;
+      case CTX_ROTATE:
+         ctx_pdf_apply_transform (ctx,
+             ctx_cosf (-c->f.a0), ctx_sinf (-c->f.a0),
+             -ctx_sinf (-c->f.a0), ctx_cosf (-c->f.a0),
+             0.f, 0.f);
+         break;
+
+      case CTX_APPLY_TRANSFORM:
+        ctx_pdf_apply_transform (ctx, c->f.a0, c->f.a1,
+                                      c->f.a3, c->f.a4,
+                                      c->f.a4, c->f.a7);
+        break;
+
+      case CTX_STROKE:
+        if (pdf->preserve)
+        {
+          preserved = ctx_current_path (ctx);
+          ctx_pdf_print("S\n");
+          pdf->preserve = 0;
+        }
+        else
+        {
+          ctx_pdf_print("S\n");
+        }
+        break;
+
+      case CTX_CLIP:
+        if (pdf->preserve)
+        {
+          preserved = ctx_current_path (ctx);
+          ctx_pdf_print("W\n");
+          pdf->preserve = 0;
+        }
+        else
+        {
+          ctx_pdf_print("W\n");
+        }
+        break;
+      case CTX_BEGIN_PATH:  ctx_pdf_print("n\n"); break;
+      case CTX_CLOSE_PATH:  ctx_pdf_print("h\n"); break;
+      case CTX_SAVE:        ctx_pdf_print("q\n"); break;
+      case CTX_RESTORE:     ctx_pdf_print("Q\n"); break;
+      case CTX_FONT_SIZE:   ctx_pdf_printf("/F%i %f Tf\n", pdf->font, state->gstate.font_size); break;
+      case CTX_MITER_LIMIT: ctx_pdf_printf("%f M\n", ctx_arg_float (0)); break;
+      case CTX_LINE_CAP:    ctx_pdf_printf("%i J\n", ctx_arg_u8 (0)); break;
+      case CTX_LINE_JOIN:   ctx_pdf_printf("%i j\n", ctx_arg_u8 (0)); break;
+
+      case CTX_FONT:
+        {
+          const char *str = ctx_arg_string ();
+          if (!strcmp (str, "Helvetica"))             pdf->font = CTX_PDF_HELVETICA;
+          if (!strcmp (str, "Helvetica Bold"))        pdf->font = CTX_PDF_HELVETICA_BOLD;
+          if (!strcmp (str, "Helvetica Italic"))      pdf->font = CTX_PDF_HELVETICA_ITALIC;
+          if (!strcmp (str, "Helvetica BoldItalic"))  pdf->font = CTX_PDF_HELVETICA_BOLD_ITALIC;
+          if (!strcmp (str, "Helvetica Bold Italic")) pdf->font = CTX_PDF_HELVETICA_BOLD_ITALIC;
+          if (!strcmp (str, "Symbol"))                pdf->font = CTX_PDF_SYMBOL;
+          if (!strcmp (str, "Zapf Dingbats"))         pdf->font = CTX_PDF_ZAPF_DING_BATS;
+          if (!strcmp (str, "ZapfDingbats"))          pdf->font = CTX_PDF_ZAPF_DING_BATS;
+          if (!strcmp (str, "Times"))                 pdf->font = CTX_PDF_TIMES;
+          if (!strcmp (str, "Times Italic"))          pdf->font = CTX_PDF_TIMES_ITALIC;
+          if (!strcmp (str, "Times Bold"))            pdf->font = CTX_PDF_TIMES_BOLD;
+          if (!strcmp (str, "Times Bold Italic"))     pdf->font = CTX_PDF_TIMES_BOLD_ITALIC;
+          if (!strcmp (str, "Times BoldItalic"))      pdf->font = CTX_PDF_TIMES_BOLD_ITALIC;
+          if (!strcmp (str, "Courier"))               pdf->font = CTX_PDF_COURIER;
+          if (!strcmp (str, "Courier Bold"))          pdf->font = CTX_PDF_COURIER_BOLD;
+          if (!strcmp (str, "Courier Italic"))        pdf->font = CTX_PDF_COURIER_ITALIC;
+          if (!strcmp (str, "Courier Bold Italic"))   pdf->font = CTX_PDF_COURIER_BOLD_ITALIC;
+          if (!strcmp (str, "Courier BoldItalic"))    pdf->font = CTX_PDF_COURIER_BOLD_ITALIC;
+        }
+        ctx_pdf_printf("/F%i %f Tf\n", pdf->font, state->gstate.font_size);
+        break;
+
+
+#if 0
+      case CTX_BLEND_MODE:
+        {
+        }
+        break;
+      case CTX_COMPOSITING_MODE:
+        {
+          int pdf_val = CAIRO_OPERATOR_OVER;
+          switch (ctx_arg_u8 (0) )
+            {
+              case CTX_COMPOSITE_SOURCE_OVER:
+                pdf_val = CAIRO_OPERATOR_OVER;
+                break;
+              case CTX_COMPOSITE_COPY:
+                pdf_val = CAIRO_OPERATOR_SOURCE;
+                break;
+            }
+          pdf_set_operator (cr, pdf_val);
+        }
+        break;
+#endif
+      case CTX_LINEAR_GRADIENT: { ctx_pdf_print("1 0 0 rg\n"); } break;
+      case CTX_RADIAL_GRADIENT: { ctx_pdf_print("0 2 0 rg\n"); } break;
+      case CTX_TEXTURE:
+      case CTX_DEFINE_TEXTURE: { ctx_pdf_print("0 0 1 rg\n"); } break;
+      case CTX_GRADIENT_STOP:
+        // we set the color so we might get a flavour of the gradient
+         ctx_pdf_printf("%f %f %f rg\n", ctx_arg_u8(4)/255.0f,
+                                         ctx_arg_u8(4+1)/255.0f,
+                                         ctx_arg_u8(4+2)/255.0f);
+        break;
+      case CTX_TEXT:
+        ctx_pdf_print("1 0 0 -1 ");
+        ctx_pdf_print2f(state->x, state->y);
+        ctx_pdf_print("Tm ");
+        if (0)
+        {
+          char *encoded = ctx_utf8_to_mac_roman ((uint8_t*)ctx_arg_string ());
+          ctx_pdf_printf ("(%s) Tj\n", encoded);
+          ctx_free (encoded);
+        }
+        else
+        {
+          char *encoded = ctx_utf8_to_windows_1252 ((uint8_t*)ctx_arg_string ());
+          ctx_pdf_printf ("(%s) Tj\n", encoded);
+          ctx_free (encoded);
+        }
+        break;
+      case CTX_CONT:
+      case CTX_EDGE:
+      case CTX_DATA:
+      case CTX_DATA_REV:
+      case CTX_END_FRAME:
+        break;
+      case CTX_VIEW_BOX:
+        pdf->page_size[0] = ctx_arg_float(0);
+        pdf->page_size[1] = ctx_arg_float(1);
+        pdf->page_size[2] = ctx_arg_float(2);
+        pdf->page_size[3] = ctx_arg_float(3);
+        ctx_set_size (ctx, 
+          ctx_arg_float(2),
+          ctx_arg_float(3));
+        break;
+    }
+  ctx_interpret_pos_bare (&pdf->state, entry, pdf);
+#if CTX_CURRENT_PATH
+  ctx_update_current_path (ctx, entry);
+#endif
+
+  if (preserved)
+  {
+    CtxIterator iterator;
+    CtxCommand *command;
+    
+    ctx_iterator_init (&iterator, preserved, 0, CTX_ITERATOR_EXPAND_BITPACK);
+    while ( (command = ctx_iterator_next (&iterator) ) )
+      { ctx_pdf_process (ctx, command); }
+    ctx_free (preserved);
+  }
+}
+
+void ctx_pdf_destroy (CtxPDF *pdf)
+{
+  FILE *f = fopen (pdf->path, "w");
+  char buf[12];
+
+  pdf_end_page (pdf);
+
+  int outlines=pdf_add_object (pdf);
+  ctx_pdf_print("<</Type/Outlines/Count 0>>");
+  int catalog=pdf_add_object (pdf);
+  ctx_pdf_printf("<</Type/Catalog/Outlines %i 0 R/Pages %i 0 R>>", outlines, pdf->pages);
+
+
+  // patch-back the value in pages earlier
+  snprintf (buf, 11, "% 10d", pdf->page_count);
+  memcpy   (&pdf->document->str[pdf->page_count_offset], buf, 10);
+
+  // patch-back the value in pages earlier
+  int kids = pdf_add_object (pdf); 
+  snprintf (buf, 11, "% 10d", kids);
+  memcpy   (&pdf->document->str[pdf->kids_offset], buf, 10);
+
+  ctx_pdf_print ("[");
+  for (int page_no =1; page_no <= pdf->page_count; page_no++)
+    ctx_pdf_printf ("%i 0 R ", pdf->page_objs[page_no]);
+  ctx_pdf_print ("]");
+  pdf_end_object(pdf);
+
+  int start_xref = pdf->document->length;
+  ctx_pdf_printf ("xref\n0 %i\n", pdf->objs + 1);
+  ctx_pdf_print ("0000000000 65535 f\n");
+        for(int i = 1; i <= pdf->objs; i++)
+        {
+          ctx_pdf_printf ("%010d 65535 n\n", pdf->xref[i]);
+        }
+  ctx_pdf_printf ("trailer\n\n"
+"<</Root %i 0 R\n/Size %i>>\n"
+"startxref\n"
+"%d\n"
+"%%%%EOF\n", catalog, pdf->objs+1,
+       start_xref);
+
+  fwrite (pdf->document->str, pdf->document->length, 1, f);
+  ctx_string_free (pdf->document, 1);
+  ctx_free (pdf);
+}
+
+Ctx *
+ctx_new_pdf (const char *path, float width, float height)
+{
+  Ctx *ctx = _ctx_new_drawlist (width, height);
+  CtxPDF *pdf = ctx_calloc(sizeof(CtxPDF),1);
+  CtxBackend *backend  = (CtxBackend*)pdf;
+  if (width <= 0) width = 595;
+  if (width <= 0) height = 842;
+
+  pdf->width = width;
+  pdf->height = height;
+
+  backend->destroy = (void*)ctx_pdf_destroy;
+  backend->process = ctx_pdf_process;
+  backend->ctx     = ctx;
+  pdf->document    = ctx_string_new("");
+
+  pdf->path = ctx_strdup (path);
+  ctx_state_init (&pdf->state);
+  ctx_set_backend (ctx, (void*)pdf);
+  ctx_pdf_print ("%PDF-1.4\n%ÆØÅ\n");
+  //ctx_pdf_printf ("%%PDF-1.4\n%%%c%c%c%c\n", 0xe2, 0xe3, 0xcf, 0xd3);
+  pdf->pages=pdf_add_object (pdf); // 1
+  pdf->font = CTX_PDF_HELVETICA;
+  //pdf->encoding = "/MacRomanEncoding";
+  pdf->encoding = "/WinAnsiEncoding";
+
+  ctx_pdf_print ("<</Kids ");
+  pdf->kids_offset = pdf->document->length;
+  ctx_pdf_print ("XXXXXXXXXX 0 R/Type/Pages/Count ");
+  pdf->page_count_offset = pdf->document->length;
+  ctx_pdf_print ("XXXXXXXXXX");
+  ctx_pdf_print (">>");
+
+  { // shared fontmap for all pages
+    // good enough without TTF fonts
+    int font[16];
+
+    char *font_names[]={"","Times","Helvetica","Courier","Symbol",
+"Times-Bold", "Helvetica-Bold", "Courier-Bold",
+"ZapfDingbats", "Times-Italic", "Helvetica-Oblique",
+"Courier-Oblique", "Times-BoldItalic", "Helvetica-BoldItalic", "Courier-BoldItalic"
+    };
+
+    for (int font_no = 1; font_no <= 14; font_no++)
+    {
+      font[font_no]= pdf_add_object (pdf);
+      ctx_pdf_printf ("<</Name/F%i/Subtype/Type1/Type/Font/BaseFont /%s /Encoding %s>>",
+                      font_no, font_names[font_no], pdf->encoding);
+    }
+
+    pdf->font_map=pdf_add_object(pdf);
+    ctx_pdf_print ("<<");
+    for (int font_no = 1; font_no <= 14; font_no++)
+      ctx_pdf_printf ("/F%i %i 0 R", font_no, font[font_no]);
+    ctx_pdf_print (">>");
+  }
+
+  pdf->page_size[0] = 0;
+  pdf->page_size[1] = 0;
+  pdf->page_size[2] = pdf->width;
+  pdf->page_size[3] = pdf->height;
+
+  pdf_start_page (pdf);
+
+  return ctx;
+}
+
+void
+ctx_render_pdf (Ctx *ctx, const char *path)
+{
+  Ctx *pdf = ctx_new_pdf (path, 0, 0);
+  CtxIterator iterator;
+  CtxCommand *command;
+  ctx_iterator_init (&iterator, &ctx->drawlist, 0, CTX_ITERATOR_EXPAND_BITPACK);
+  while ( (command = ctx_iterator_next (&iterator) ) )
+    { ctx_pdf_process (pdf, command); }
+  ctx_destroy (pdf);
+}
+
+
+
+
+static char *ctx_utf8_to_mac_roman (const uint8_t *string)
+{
+  CtxString *ret = ctx_string_new ("");
+  if (*string)
+  for (const uint8_t *utf8 = (uint8_t*)string; utf8[0]; utf8 = *utf8?(uint8_t*)ctx_utf8_skip ((char*)utf8, 
1):(utf8+1))
+  {
+    uint8_t copy[5];
+
+    memcpy (copy, utf8, ctx_utf8_len (utf8[0]));
+    copy[ctx_utf8_len (utf8[0])]=0;
+    if (copy[0] <=127)
+    {
+      ctx_string_append_byte (ret, copy[0]);
+    }
+    else
+    {
+      int code = 128;
+      /* it would be better to to this comparison on a unicode table,
+       * but this was easier to create
+       */
+#define C(a) \
+      if (!strcmp ((char*)&copy[0], a)) { ctx_string_append_byte (ret, code); continue; }; code++
+      
C("Ä");C("Å");C("Ç");C("É");C("Ñ");C("Ö");C("Ü");C("á");C("à");C("â");C("ä");C("ã");C("å");C("ç");C("é");C("è");
+      
C("ê");C("ë");C("í");C("ì");C("î");C("ï");C("ñ");C("ó");C("ò");C("ô");C("ö");C("õ");C("ú");C("ù");C("û");C("ü");
+      
C("†");C("°");C("¢");C("£");C("§");C("•");C("¶");C("ß");C("®");C("©");C("™");C("´");C("¨");C("≠");C("Æ");C("Ø");
+      
C("∞");C("±");C("≤");C("≥");C("¥");C("µ");C("∂");C("∑");C("∏");C("π");C("∫");C("ª");C("º");C("Ω");C("æ");C("ø");
+      C("¿");C("¡");C("¬");C("√");C("ƒ");C("≈");C("∆");C("«");C("»");C("…");C(" 
");C("À");C("Ã");C("Õ");C("Œ");C("œ");
+      
C("–");C("—");C("“");C("”");C("‘");C("’");C("÷");C("◊");C("ÿ");C("Ÿ");C("⁄");C("€");C("‹");C("›");C("fi");C("fl");
+      
C("‡");C("·");C("‚");C("„");C("‰");C("Â");C("Ê");C("Á");C("Ë");C("È");C("Í");C("Î");C("Ï");C("Ì");C("Ó");C("Ô");
+      
C("?");C("Ò");C("Ú");C("Û");C("Ù");C("ı");C("ˆ");C("˜");C("¯");C("˘");C("˙");C("˚");C("¸");C("˝");C("˛");C("ˇ");
+      ctx_string_append_byte (ret, '?');
+    }
+  }
+
+  return ctx_string_dissolve (ret);
+}
+
+static char *ctx_utf8_to_windows_1252 (const uint8_t *string)
+{
+  CtxString *ret = ctx_string_new ("");
+  if (*string)
+  for (const uint8_t *utf8 = (uint8_t*)string; utf8[0]; utf8 = *utf8?(uint8_t*)ctx_utf8_skip ((char*)utf8, 
1):(utf8+1))
+  {
+    uint8_t copy[5];
+
+    memcpy (copy, utf8, ctx_utf8_len (utf8[0]));
+    copy[ctx_utf8_len (utf8[0])]=0;
+    if (copy[0] == '(' || copy[0] == ')')
+    {
+      ctx_string_append_byte (ret, '\\');
+      ctx_string_append_byte (ret, copy[0]);
+    }
+    else if (copy[0] <=127)
+    {
+      ctx_string_append_byte (ret, copy[0]);
+    }
+    else
+    {
+      int code = 128;
+      /* it would be better to to this comparison on a unicode table,
+       * but this was easier to create
+       */
+C("€");C(" ");C("‚");C("ƒ");C("„");C("…");C("†");C("‡");C("ˆ");C("‰");C("Š");C("‹");C("Œ");C(" ");C("Ž");C(" 
");
+C(" ");C("‘");C("’");C("“");C("”");C("•");C("–");C("—");C("˜");C("™");C("š");C("›");C("œ");C(" 
");C("ž");C("Ÿ");
+C(" 
");C("¡");C("¢");C("£");C("¤");C("¥");C("¦");C("§");C("¨");C("©");C("ª");C("«");C("¬");C("-");C("®");C("¯");
+C("°");C("±");C("²");C("³");C("´");C("µ");C("¶");C("·");C("¸");C("¹");C("º");C("»");C("¼");C("½");C("¾");C("¿");
+C("À");C("Á");C("Â");C("Ã");C("Ä");C("Å");C("Æ");C("Ç");C("È");C("É");C("Ê");C("Ë");C("Ì");C("Í");C("Î");C("Ï");
+C("Ð");C("Ñ");C("Ò");C("Ó");C("Ô");C("Õ");C("Ö");C("×");C("Ø");C("Ù");C("Ú");C("Û");C("Ü");C("Ý");C("Þ");C("ß");
+C("à");C("á");C("â");C("ã");C("ä");C("å");C("æ");C("ç");C("è");C("é");C("ê");C("ë");C("ì");C("í");C("î");C("ï");
+C("ð");C("ñ");C("ò");C("ó");C("ô");C("õ");C("ö");C("÷");C("ø");C("ù");C("ú");C("û");C("ü");C("ý");C("þ");C("ÿ");
+#undef C
+      ctx_string_append_byte (ret, '?');
+    }
+  }
+  return ctx_string_dissolve (ret);
+}
+
+
+
 #endif
 
 #if CTX_CAIRO
@@ -32022,6 +34985,33 @@ ctx_cairo_process (Ctx *ctx, CtxCommand *c)
                                ctx_u8_to_float (ctx_arg_u8 (2) ),
                                ctx_u8_to_float (ctx_arg_u8 (3) ) );
         break;
+
+      case CTX_COLOR:
+        int space =  ((int) ctx_arg_float (0)) & 511;
+        switch (space) // XXX remove 511 after stroke source is complete
+        {
+           case CTX_RGBA:
+           case CTX_DRGBA:
+             cairo_set_source_rgba (cr, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
+             break;
+           case CTX_RGB:
+             cairo_set_source_rgba (cr, c->rgba.r, c->rgba.g, c->rgba.b, 1.0f);
+             break;
+           case CTX_CMYKA:
+           case CTX_DCMYKA:
+           case CTX_CMYK:
+           case CTX_DCMYK:
+              break;
+           case CTX_GRAYA:
+             cairo_set_source_rgba (cr, c->graya.g, c->graya.g, c->graya.g, c->graya.a);
+             break;
+               /*FALLTHROUGH*/
+           case CTX_GRAY:
+             cairo_set_source_rgba (cr, c->graya.g, c->graya.g, c->graya.g, 1.0f);
+             break;
+            }
+        break;
+
 #if 0
       case CTX_SET_RGBA_STROKE: // XXX : we need to maintain
         //       state for the two kinds
@@ -32080,7 +35070,6 @@ ctx_cairo_process (Ctx *ctx, CtxCommand *c)
           cairo_clip (cr);
         }
         break;
-        break;
       case CTX_BEGIN_PATH:
         cairo_new_path (cr);
         break;
@@ -32219,19 +35208,19 @@ ctx_cairo_process (Ctx *ctx, CtxCommand *c)
       case CTX_EDGE:
       case CTX_DATA:
       case CTX_DATA_REV:
-      case CTX_FLUSH:
+      case CTX_END_FRAME:
         break;
     }
   ctx_process (ctx_cairo->backend.ctx, entry);
 }
 
-void ctx_cairo_free (CtxCairo *ctx_cairo)
+void ctx_cairo_destroy (CtxCairo *ctx_cairo)
 {
   if (ctx_cairo->pat)
     { cairo_pattern_destroy (ctx_cairo->pat); }
   if (ctx_cairo->image)
     { cairo_surface_destroy (ctx_cairo->image); }
-  free (ctx_cairo);
+  ctx_free (ctx_cairo);
 }
 
 void
@@ -32254,9 +35243,9 @@ Ctx *
 ctx_new_for_cairo (cairo_t *cr)
 {
   Ctx *ctx = _ctx_new_drawlist (640, 480);
-  CtxCairo *ctx_cairo = calloc(sizeof(CtxCairo),1);
+  CtxCairo *ctx_cairo = ctx_calloc(sizeof(CtxCairo),1);
   CtxBackend *backend  = (CtxBackend*)ctx_cairo;
-  backend->free    = (void*)ctx_cairo_free;
+  backend->destroy = (void*)ctx_cairo_destroy;
   backend->process = ctx_cairo_process;
   backend->ctx = ctx;
   ctx_cairo->cr = cr;
@@ -32266,8 +35255,9 @@ ctx_new_for_cairo (cairo_t *cr)
 
 #endif
 
-#if CTX_EVENTS
+#if CTX_TERMINAL_EVENTS
 
+#if 0
 static int ctx_find_largest_matching_substring
  (const char *X, const char *Y, int m, int n, int *offsetY, int *offsetX) 
 { 
@@ -32295,6 +35285,7 @@ static int ctx_find_largest_matching_substring
   }
   return best_length;
 } 
+#endif
 
 typedef struct CtxSpan {
   int from_prev;
@@ -32325,6 +35316,7 @@ static void _dassert(int line, int condition, const char *str, int foo, int bar,
  * matching 3-4 characters in previous.. or even
  * a naive approach that expects rough alignment..
  */
+#if 0
 static char *encode_in_terms_of_previous (
                 const char *src,  int src_len,
                 const char *prev, int prev_len,
@@ -32342,7 +35334,7 @@ static char *encode_in_terms_of_previous (
   int length = CHUNK_SIZE;
   for (start = 0; start < src_len; start += length)
   {
-    CtxSpan *span = calloc (sizeof (CtxSpan), 1);
+    CtxSpan *span = ctx_calloc (sizeof (CtxSpan), 1);
     span->start = start;
     if (start + length > src_len)
       span->length = src_len - start;
@@ -32397,7 +35389,7 @@ static char *encode_in_terms_of_previous (
 
             if (curr_pos)
             {
-              CtxSpan *prev = calloc (sizeof (CtxSpan), 1);
+              CtxSpan *prev = ctx_calloc (sizeof (CtxSpan), 1);
               prev->start = start;
               prev->length =  curr_pos;
             dassert (prev->start >= 0, prev_pos, prev_start, prev->start);
@@ -32409,7 +35401,7 @@ static char *encode_in_terms_of_previous (
 
             if (match_len + curr_pos < start + length)
             {
-              CtxSpan *next = calloc (sizeof (CtxSpan), 1);
+              CtxSpan *next = ctx_calloc (sizeof (CtxSpan), 1);
               next->start = start + curr_pos + match_len;
               next->length = (start + length) - next->start;
             dassert (next->start >= 0, prev_pos, prev_start, next->start);
@@ -32423,7 +35415,7 @@ static char *encode_in_terms_of_previous (
                   ctx_list_append (&encoded_list, next);
               }
               else
-                free (next);
+                ctx_free (next);
             }
 
             if (curr_pos) // step one item back for forloop
@@ -32493,7 +35485,7 @@ again:
         }
       }
     }
-    free (span);
+    ctx_free (span);
     ctx_list_remove (&encoded_list, span);
   }
 
@@ -32502,6 +35494,7 @@ again:
   ctx_string_free (string, 0);
   return ret;
 }
+#endif
 
 #if 0 // for documentation/reference purposes
 static char *decode_ctx (const char *encoded, int enc_len, const char *prev, int prev_len, int *out_len)
@@ -32559,7 +35552,7 @@ static char *decode_ctx (const char *encoded, int enc_len, const char *prev, int
 }
 #endif
 
-#define CTX_START_STRING "U\n"  // or " reset "
+#define CTX_START_STRING "U\n"  // or " start_frame "
 #define CTX_END_STRING   "\nX"  // or "\ndone"
 #define CTX_END_STRING2  "\n"
 
@@ -32569,7 +35562,7 @@ static int   prev_frame_len = 0;
 
 static int ctx_native_events = 1;
 
-static void ctx_ctx_flush (Ctx *ctx)
+static void ctx_ctx_end_frame (Ctx *ctx)
 {
   CtxCtx *ctxctx = (CtxCtx*)ctx->backend;
 #if 0
@@ -32588,13 +35581,13 @@ static void ctx_ctx_flush (Ctx *ctx)
   {
     int cur_frame_len = 0;
     char *rest = ctx_render_string (ctxctx->ctx, 0, &cur_frame_len);
-    char *cur_frame_contents = malloc (cur_frame_len + strlen(CTX_START_STRING) + strlen (CTX_END_STRING) + 
1);
+    char *cur_frame_contents = ctx_malloc (cur_frame_len + strlen(CTX_START_STRING) + strlen 
(CTX_END_STRING) + 1);
 
     cur_frame_contents[0]=0;
     strcat (cur_frame_contents, CTX_START_STRING);
     strcat (cur_frame_contents, rest);
     strcat (cur_frame_contents, CTX_END_STRING);
-    free (rest);
+    ctx_free (rest);
     cur_frame_len += strlen (CTX_START_STRING) + strlen (CTX_END_STRING);
 
     if (prev_frame_contents && 0)  // XXX : 
@@ -32604,8 +35597,8 @@ static void ctx_ctx_flush (Ctx *ctx)
       //uint64_t ticks_start = ctx_ticks ();
 
       encoded = encode_in_terms_of_previous (cur_frame_contents, cur_frame_len, prev_frame_contents, 
prev_frame_len, &encoded_len, 1000 * 10);
-//    encoded = strdup (cur_frame_contents);
-//    encoded_len = strlen (encoded);
+//    encoded = ctx_strdup (cur_frame_contents);
+//    encoded_len = ctx_strlen (encoded);
       //uint64_t ticks_end = ctx_ticks ();
 
       fwrite (encoded, encoded_len, 1, stdout);
@@ -32617,7 +35610,7 @@ static void ctx_ctx_flush (Ctx *ctx)
                       (ticks_end-ticks_start)/1000.0,
                       (int)strlen(encoded), encoded);
 #endif
-      free (encoded);
+      ctx_free (encoded);
     }
     else
     {
@@ -32625,7 +35618,7 @@ static void ctx_ctx_flush (Ctx *ctx)
     }
 
     if (prev_frame_contents)
-      free (prev_frame_contents);
+      ctx_free (prev_frame_contents);
     prev_frame_contents = cur_frame_contents;
     prev_frame_len = cur_frame_len;
   }
@@ -32648,10 +35641,10 @@ static void ctx_ctx_flush (Ctx *ctx)
 #endif
 }
 
-void ctx_ctx_free (CtxCtx *ctx)
+void ctx_ctx_destroy (CtxCtx *ctx)
 {
   nc_at_exit ();
-  free (ctx);
+  ctx_free (ctx);
   /* we're not destoring the ctx member, this is function is called in ctx' teardown */
 }
 
@@ -32678,7 +35671,7 @@ void ctx_ctx_consume_events (Ctx *ctx)
 #endif
     //char *cmd = ctx_strdup_printf ("touch /tmp/ctx-%ix%i", ctxctx->width, ctxctx->height);
     //system (cmd);
-    //free (cmd);
+    //ctx_free (cmd);
 
   if (ctx_native_events)
     do {
@@ -32722,7 +35715,7 @@ void ctx_ctx_consume_events (Ctx *ctx)
         ctx_set_size (ctx, ctx_terminal_width(), ctx_terminal_height());
 
         if (prev_frame_contents)
-          free (prev_frame_contents);
+          ctx_free (prev_frame_contents);
         prev_frame_contents = NULL;
         prev_frame_len = 0;
         ctx_queue_draw (ctx);
@@ -32731,12 +35724,12 @@ void ctx_ctx_consume_events (Ctx *ctx)
       }
       else if (!strcmp (event_type, "keyup"))
       {
-        char buf[4]={ x, 0 };
+        char buf[4]={ (int)x, 0 };
         ctx_key_up (ctx, (int)x, buf, 0);
       }
       else if (!strcmp (event_type, "keydown"))
       {
-        char buf[4]={ x, 0 };
+        char buf[4]={ (int)x, 0 };
         ctx_key_down (ctx, (int)x, buf, 0);
       }
       else
@@ -32751,7 +35744,7 @@ Ctx *ctx_new_ctx (int width, int height)
 {
   float font_size = 12.0;
   Ctx *ctx = _ctx_new_drawlist (width, height);
-  CtxCtx *ctxctx = (CtxCtx*)calloc (sizeof (CtxCtx), 1);
+  CtxCtx *ctxctx = (CtxCtx*)ctx_calloc (sizeof (CtxCtx), 1);
   CtxBackend *backend = (CtxBackend*)ctxctx;
   fprintf (stdout, "\e[?1049h");
   fflush (stdout);
@@ -32762,23 +35755,23 @@ Ctx *ctx_new_ctx (int width, int height)
   {
     ctxctx->cols = ctx_terminal_cols ();
     ctxctx->rows = ctx_terminal_rows ();
-    width  = ctx->width  = ctx_terminal_width ();
-    height = ctx->height = ctx_terminal_height ();
+    width  = ctx->width  = ctxctx->width = ctx_terminal_width ();
+    height = ctx->height = ctxctx->width = ctx_terminal_height ();
     font_size = height / ctxctx->rows;
     ctx_font_size (ctx, font_size);
   }
   else
   {
-    ctx->width  = width;
-    ctx->height = height;
+    ctxctx->width = ctx->width  = width;
+    ctxctx->height = ctx->height = height;
     ctxctx->cols   = width / 80;
     ctxctx->rows   = height / 24;
   }
   backend->ctx = ctx;
   if (!ctx_native_events)
     _ctx_mouse (ctx, NC_MOUSE_DRAG);
-  backend->flush = ctx_ctx_flush;
-  backend->free  = (void(*)(void *))ctx_ctx_free;
+  backend->end_frame = ctx_ctx_end_frame;
+  backend->destroy = (void(*)(void *))ctx_ctx_destroy;
   backend->process = (void*)ctx_drawlist_process;
   backend->consume_events = ctx_ctx_consume_events;
   ctx_set_backend (ctx, ctxctx);
@@ -32806,7 +35799,7 @@ ctx_tiled_threads_done (CtxTiled *tiled)
 
 int _ctx_damage_control = 0;
 
-void ctx_tiled_free (CtxTiled *tiled)
+void ctx_tiled_destroy (CtxTiled *tiled)
 {
   tiled->quit = 1;
   mtx_lock (&tiled->mtx);
@@ -32818,22 +35811,15 @@ void ctx_tiled_free (CtxTiled *tiled)
 
   if (tiled->pixels)
   {
-    free (tiled->pixels);
+    ctx_free (tiled->pixels);
     tiled->pixels = NULL;
     for (int i = 0 ; i < _ctx_max_threads; i++)
     {
       if (tiled->host[i])
-        ctx_free (tiled->host[i]);
+        ctx_destroy (tiled->host[i]);
       tiled->host[i]=NULL;
     }
-    ctx_free (tiled->ctx_copy);
-  }
-
-  if (tiled->active_info)
-  {
-    free (tiled->active_info);
-    tiled->active_info = 0;
-    tiled->active_info_count = 0;
+    ctx_destroy (tiled->ctx_copy);
   }
 
   // leak?
@@ -32841,7 +35827,7 @@ void ctx_tiled_free (CtxTiled *tiled)
 static unsigned char *sdl_icc = NULL;
 static long sdl_icc_length = 0;
 
-static void ctx_tiled_flush (Ctx *ctx)
+static void ctx_tiled_end_frame (Ctx *ctx)
 {
   CtxTiled *tiled = (CtxTiled*)ctx->backend;
   mtx_lock (&tiled->mtx);
@@ -32853,7 +35839,7 @@ static void ctx_tiled_flush (Ctx *ctx)
     if (_ctx_enable_hash_cache)
     {
       Ctx *hasher = ctx_hasher_new (tiled->width, tiled->height,
-                        CTX_HASH_COLS, CTX_HASH_ROWS);
+                        CTX_HASH_COLS, CTX_HASH_ROWS, &tiled->ctx_copy->drawlist);
       ctx_render_ctx (tiled->ctx_copy, hasher);
 
       for (int row = 0; row < CTX_HASH_ROWS; row++)
@@ -32873,16 +35859,8 @@ static void ctx_tiled_flush (Ctx *ctx)
           }
         }
       }
-      if (tiled->active_info)
-      {
-        free (tiled->active_info);
-        tiled->active_info = 0;
-        tiled->active_info_count = 0;
-      }
 
-      tiled->active_info = ctx_hasher_get_active_info (hasher, &tiled->active_info_count);
-      free (((CtxHasher*)(hasher->backend))->hashes);
-      ctx_free (hasher);
+      ctx_destroy (hasher);
     }
     else
     {
@@ -32996,19 +35974,36 @@ void ctx_tiled_render_fun (void **data)
               active_mask |= 1 << hno;
             }
 #endif
-            int swap_red_green = ((CtxRasterizer*)(host->backend))->swap_red_green;
+            int swap_red_green = rasterizer->swap_red_green;
+            int compressed_scanlines = 0;
+#if CTX_ENABLE_CBRLE
+            // compressed_scanlines = 1;
+#endif
             ctx_rasterizer_init (rasterizer,
                                  host, tiled->backend.ctx, &host->state,
                                  &tiled->pixels[tiled->width * 4 * y0 + x0 * 4],
                                  0, 0, width, height,
-                                 tiled->width*4, CTX_FORMAT_BGRA8,
+                                 tiled->width*4, compressed_scanlines?CTX_FORMAT_CBRLE_32:CTX_FORMAT_BGRA8,
                                  tiled->antialias);
             ((CtxRasterizer*)(host->backend))->swap_red_green = swap_red_green;
             if (sdl_icc_length)
               ctx_colorspace (host, CTX_COLOR_SPACE_DEVICE_RGB, sdl_icc, sdl_icc_length);
 
             ctx_translate (host, -x0, -y0);
-            ctx_render_ctx_masked (tiled->ctx_copy, host, tiled->active_info, tiled->active_info_count, 
active_mask);
+            ctx_render_ctx_masked (tiled->ctx_copy, host, active_mask);
+
+#if CTX_ENABLE_CBRLE
+            if (compressed_scanlines)
+            for (int i = 0; i < height; i ++)
+            {
+              uint8_t temp[width*4];
+              _ctx_CBRLE_decompress (&tiled->pixels[tiled->width * 4 * (y0+i) + x0 * 4],
+                                      temp,
+                                      width,
+                                      width * 4, 0, width);
+              memcpy (&tiled->pixels[tiled->width * 4 * (y0+i) + x0 * 4], temp, sizeof (temp));
+            }
+#endif
           }
         }
       tiled->rendered_frame[no] = tiled->render_frame;
@@ -33043,7 +36038,7 @@ static inline int ctx_is_in_cursor (int x, int y, int size, CtxCursor shape)
     case CTX_CURSOR_RESIZE_SW:
     case CTX_CURSOR_RESIZE_NE:
       {
-        float theta = -45.0/180 * M_PI;
+        float theta = -45.0f/180 * (float)(M_PI);
         float cos_theta;
         float sin_theta;
 
@@ -33059,8 +36054,8 @@ static inline int ctx_is_in_cursor (int x, int y, int size, CtxCursor shape)
           cos_theta = ctx_cosf (theta);
           sin_theta = ctx_sinf (theta);
         }
-        int rot_x = x * cos_theta - y * sin_theta;
-        int rot_y = y * cos_theta + x * sin_theta;
+        int rot_x = (int)(x * cos_theta - y * sin_theta);
+        int rot_y = (int)(y * cos_theta + x * sin_theta);
         x = rot_x;
         y = rot_y;
       }
@@ -33144,10 +36139,10 @@ static void ctx_tiled_undraw_cursor (CtxTiled *tiled)
     }
 }
 
-static void ctx_tiled_draw_cursor (CtxTiled *tiled)
+static inline void ctx_tiled_draw_cursor (CtxTiled *tiled)
 {
-    int cursor_x    = ctx_pointer_x (tiled->backend.ctx);
-    int cursor_y    = ctx_pointer_y (tiled->backend.ctx);
+    int cursor_x = (int)ctx_pointer_x (tiled->backend.ctx);
+    int cursor_y = (int)ctx_pointer_y (tiled->backend.ctx);
     int cursor_size = ctx_height (tiled->backend.ctx) / 28;
     CtxCursor cursor_shape = tiled->backend.ctx->cursor;
     int no = 0;
@@ -33209,7 +36204,7 @@ static void ctx_tiled_draw_cursor (CtxTiled *tiled)
 
 
 
-#if CTX_EVENTS
+#if CTX_TERMINAL_EVENTS
 #if CTX_HEADLESS
 
 #include <fcntl.h>
@@ -33220,21 +36215,21 @@ static char *ctx_fb_clipboard = NULL;
 static void ctx_headless_set_clipboard (Ctx *ctx, const char *text)
 {
   if (ctx_fb_clipboard)
-    free (ctx_fb_clipboard);
+    ctx_free (ctx_fb_clipboard);
   ctx_fb_clipboard = NULL;
   if (text)
   {
-    ctx_fb_clipboard = strdup (text);
+    ctx_fb_clipboard = ctx_strdup (text);
   }
 }
 
 static char *ctx_headless_get_clipboard (Ctx *ctx)
 {
-  if (ctx_fb_clipboard) return strdup (ctx_fb_clipboard);
-  return strdup ("");
+  if (ctx_fb_clipboard) return ctx_strdup (ctx_fb_clipboard);
+  return ctx_strdup ("");
 }
 
-static int ctx_headless_get_mice_fd (Ctx *ctx)
+static inline int ctx_headless_get_mice_fd (Ctx *ctx)
 {
   //CtxHeadless *fb = (void*)ctx->backend;
   return _ctx_mice_fd;
@@ -33352,30 +36347,26 @@ void ctx_headless_consume_events (Ctx *ctx)
   event_check_pending (&fb->tiled);
 }
 
-inline static void ctx_headless_reset (Ctx *ctx)
+inline static void ctx_headless_start_frame (Ctx *ctx)
 {
   ctx_headless_show_frame ((CtxHeadless*)ctx->backend, 1);
 }
 
-void ctx_headless_free (CtxHeadless *fb)
+void ctx_headless_destroy (CtxHeadless *fb)
 {
   CtxTiled *tiled=(CtxTiled*)fb;
 
   if (tiled->fb)
   {
-  free (tiled->fb); // it is not the tiled renderers responsibilty,
+  ctx_free (tiled->fb); // it is not the tiled renderers responsibilty,
                     // since it might not be allocated this way
   tiled->fb = NULL;
-  ctx_babl_exit (); // we do this together with the fb,
-                    // which makes it happen only once
-                    // even if the headless_free is called
-                    // twice
   }
   //munmap (tiled->fb, fb->fb_mapped_size);
   //close (fb->fb_fd);
   //if (system("stty sane")){};
-  ctx_tiled_free ((CtxTiled*)fb);
-  //free (fb);
+  ctx_tiled_destroy ((CtxTiled*)fb);
+  //ctx_free (fb);
 }
 
 //static unsigned char *fb_icc = NULL;
@@ -33392,7 +36383,7 @@ Ctx *ctx_new_headless (int width, int height)
     height = 780;
   }
 #if CTX_RASTERIZER
-  CtxHeadless *fb = calloc (sizeof (CtxHeadless), 1);
+  CtxHeadless *fb = ctx_calloc (sizeof (CtxHeadless), 1);
   CtxBackend *backend = (CtxBackend*)fb;
   CtxTiled *tiled     = (CtxTiled*)fb;
   ctx_headless = fb;
@@ -33405,13 +36396,12 @@ Ctx *ctx_new_headless (int width, int height)
   fb->fb_mapped_size = width * height * 4;
 #endif
 
-  tiled->fb = calloc (fb->fb_mapped_size, 1);
+  tiled->fb = ctx_calloc (fb->fb_mapped_size, 1);
   if (!tiled->fb)
     return NULL;
-  tiled->pixels = calloc (fb->fb_mapped_size, 1);
+  tiled->pixels = ctx_calloc (fb->fb_mapped_size, 1);
   tiled->show_frame = (void*)ctx_headless_show_frame;
 
-  ctx_babl_init ();
 
  // ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
  //
@@ -33419,10 +36409,10 @@ Ctx *ctx_new_headless (int width, int height)
  // perhaps rec2020 or similar?
 
   backend->ctx = _ctx_new_drawlist (width, height);
-  backend->flush = ctx_tiled_flush;
+  backend->end_frame = ctx_tiled_end_frame;
   backend->process = (void*)ctx_drawlist_process;
-  backend->reset = ctx_headless_reset;
-  backend->free  = (void*)ctx_headless_free;
+  backend->start_frame = ctx_headless_start_frame;
+  backend->destroy = (void*)ctx_headless_destroy;
   backend->set_clipboard = ctx_headless_set_clipboard;
   backend->get_clipboard = ctx_headless_get_clipboard;
   backend->consume_events = ctx_headless_consume_events;
@@ -33480,7 +36470,7 @@ Ctx *ctx_new_headless (int width, int height)
 #endif
 #endif
 
-#if CTX_EVENTS
+#if CTX_TERMINAL_EVENTS
 
 #if !__COSMOPOLITAN__
 #include <fcntl.h>
@@ -33491,6 +36481,10 @@ Ctx *ctx_new_headless (int width, int height)
 
 #if CTX_KMS || CTX_FB
 
+static int ctx_fb_single_buffer = 0;  // used with the framebuffer this
+                               // causes flicker, but brings single
+                               // threaded memory use <2mb 
+
 static int ctx_fb_get_mice_fd (Ctx *ctx)
 {
   //CtxFb *fb = (void*)ctx->backend;
@@ -33649,6 +36643,7 @@ static void ctx_fb_show_frame (CtxFb *fb, int block)
     }
 #endif
      ctx_tiled_undraw_cursor (tiled);
+     if (!ctx_fb_single_buffer)
      switch (fb->fb_bits)
      {
        case 32:
@@ -33781,12 +36776,13 @@ void ctx_fb_consume_events (Ctx *ctx)
   event_check_pending (&fb->tiled);
 }
 
-inline static void ctx_fb_reset (Ctx *ctx)
+inline static void ctx_fb_start_frame (Ctx *ctx)
 {
+  // show pending frame if any
   ctx_fb_show_frame ((CtxFb*)ctx->backend, 1);
 }
 
-void ctx_fb_free (CtxFb *fb)
+void ctx_fb_destroy (CtxFb *fb)
 {
   CtxTiled*tiled=(CtxTiled*)fb;
 
@@ -33800,11 +36796,12 @@ void ctx_fb_free (CtxFb *fb)
   }
 #endif
   munmap (tiled->fb, fb->fb_mapped_size);
+  if (!ctx_fb_single_buffer)
+    ctx_free (tiled->pixels);
   close (fb->fb_fd);
   if (system("stty sane")){};
-  ctx_tiled_free ((CtxTiled*)fb);
-  //free (fb);
-  ctx_babl_exit ();
+  ctx_tiled_destroy ((CtxTiled*)fb);
+  //ctx_free (fb);
 }
 
 //static unsigned char *fb_icc = NULL;
@@ -33846,7 +36843,9 @@ static void fb_vt_switch_cb (int sig)
 Ctx *ctx_new_fb (int width, int height)
 {
 #if CTX_RASTERIZER
-  CtxFb *fb = calloc (sizeof (CtxFb), 1);
+  if (getenv ("CTX_FB_SINGLE_BUFFER"))
+    ctx_fb_single_buffer = atoi (getenv ("CTX_FB_SINGLE_BUFFER"));
+  CtxFb *fb = ctx_calloc (sizeof (CtxFb), 1);
   CtxTiled *tiled = (void*)fb;
   CtxBackend *backend = (void*)fb;
   ctx_fb = fb;
@@ -33862,19 +36861,19 @@ Ctx *ctx_new_fb (int width, int height)
 #endif
   fb->fb_fd = open (dev_path, O_RDWR);
   if (fb->fb_fd > 0)
-    fb->fb_path = strdup (dev_path);
+    fb->fb_path = ctx_strdup (dev_path);
   else
   {
 #ifdef __linux__
     fb->fb_fd = open ("/dev/graphics/fb0", O_RDWR);
     if (fb->fb_fd > 0)
     {
-      fb->fb_path = strdup ("/dev/graphics/fb0");
+      fb->fb_path = ctx_strdup ("/dev/graphics/fb0");
     }
     else
 #endif
     {
-      free (fb);
+      ctx_free (fb);
       return NULL;
     }
   }
@@ -33884,8 +36883,8 @@ Ctx *ctx_new_fb (int width, int height)
     {
       fprintf (stderr, "error getting fbinfo\n");
       close (fb->fb_fd);
-      free (fb->fb_path);
-      free (fb);
+      ctx_free (fb->fb_path);
+      ctx_free (fb);
       return NULL;
     }
 
@@ -33893,8 +36892,8 @@ Ctx *ctx_new_fb (int width, int height)
      {
        fprintf (stderr, "error getting fbinfo\n");
       close (fb->fb_fd);
-      free (fb->fb_path);
-      free (fb);
+      ctx_free (fb->fb_path);
+      ctx_free (fb);
       return NULL;
      }
   ioctl (0, KDSETMODE, KD_GRAPHICS);
@@ -33989,12 +36988,15 @@ Ctx *ctx_new_fb (int width, int height)
   }
   if (!tiled->fb)
     return NULL;
-  tiled->pixels = calloc (fb->fb_mapped_size, 1);
+  if (ctx_fb_single_buffer)
+    tiled->pixels = tiled->fb;
+  else
+    tiled->pixels = ctx_calloc (fb->fb_mapped_size, 1);
   tiled->show_frame = (void*)ctx_fb_show_frame;
 
-  ctx_babl_init ();
-
+#if CTX_BABL
   ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
+#endif
 
   backend->ctx    = _ctx_new_drawlist (width, height);
   tiled->ctx_copy = _ctx_new_drawlist (width, height);
@@ -34006,11 +37008,11 @@ Ctx *ctx_new_fb (int width, int height)
   ctx_set_texture_cache (tiled->ctx_copy, backend->ctx);
 
 
-  backend->flush = ctx_tiled_flush;
+  backend->end_frame = ctx_tiled_end_frame;
   backend->process = (void*)ctx_drawlist_process;
 
-  backend->reset = ctx_fb_reset;
-  backend->free  = (void*)ctx_fb_free;
+  backend->start_frame = ctx_fb_start_frame;
+  backend->destroy = (void*)ctx_fb_destroy;
   backend->set_clipboard = ctx_headless_set_clipboard;
   backend->get_clipboard = ctx_headless_get_clipboard;
   backend->consume_events = ctx_fb_consume_events;
@@ -34104,7 +37106,7 @@ Ctx *ctx_new_fb (int width, int height)
 #endif
 #endif
 
-#if CTX_EVENTS
+#if CTX_TERMINAL_EVENTS
 
 #if !__COSMOPOLITAN__
 #include <fcntl.h>
@@ -34517,12 +37519,12 @@ void ctx_kms_consume_events (Ctx *ctx)
   event_check_pending (&fb->tiled);
 }
 
-inline static void ctx_kms_reset (Ctx *ctx)
+inline static void ctx_kms_start_frame (Ctx *ctx)
 {
   ctx_kms_show_frame ((CtxKMS*)ctx->backend, 1);
 }
 
-void ctx_kms_free (CtxKMS *fb)
+void ctx_kms_destroy (CtxKMS *fb)
 {
   if (fb->is_kms)
   {
@@ -34532,9 +37534,8 @@ void ctx_kms_free (CtxKMS *fb)
   ioctl (0, KDSETMODE, KD_TEXT);
 #endif
   if (system("stty sane")){};
-  ctx_tiled_free ((CtxTiled*)fb);
-  //free (fb);
-  ctx_babl_exit ();
+  ctx_tiled_destroy ((CtxTiled*)fb);
+  //ctx_free (fb);
 }
 
 //static unsigned char *fb_icc = NULL;
@@ -34592,7 +37593,7 @@ static int ctx_kms_get_mice_fd (Ctx *ctx)
 Ctx *ctx_new_kms (int width, int height)
 {
 #if CTX_RASTERIZER
-  CtxKMS *fb = calloc (sizeof (CtxKMS), 1);
+  CtxKMS *fb = ctx_calloc (sizeof (CtxKMS), 1);
   CtxBackend *backend = (CtxBackend*)fb;
 
   CtxTiled *tiled = (void*)fb;
@@ -34613,11 +37614,11 @@ Ctx *ctx_new_kms (int width, int height)
   }
   if (!tiled->fb)
     return NULL;
-  tiled->pixels = calloc (fb->fb_mapped_size, 1);
-
-  ctx_babl_init ();
+  tiled->pixels = ctx_calloc (fb->fb_mapped_size, 1);
 
+#if CTX_BABL
   ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
+#endif
 
   backend->ctx = _ctx_new_drawlist (width, height);
   tiled->ctx_copy = _ctx_new_drawlist (width, height);
@@ -34630,9 +37631,9 @@ Ctx *ctx_new_kms (int width, int height)
   ctx_set_backend (tiled->ctx_copy, fb);
   ctx_set_texture_cache (tiled->ctx_copy, backend->ctx);
 
-  backend->flush = ctx_tiled_flush;
-  backend->reset = ctx_kms_reset;
-  backend->free  = (void*)ctx_kms_free;
+  backend->end_frame = ctx_tiled_end_frame;
+  backend->start_frame = ctx_kms_start_frame;
+  backend->destroy = (void*)ctx_kms_destroy;
   backend->process = (void*)ctx_drawlist_process;
   backend->consume_events = ctx_kms_consume_events;
   backend->get_event_fds = (void*) ctx_fb_get_event_fds;
@@ -34753,49 +37754,6 @@ struct _CtxSDL
 };
 
 
-void ctx_screenshot (Ctx *ctx, const char *output_path)
-{
-#if CTX_SCREENSHOT
-  CtxTiled *tiled = (CtxTiled*)ctx->backend;
-
-   if (ctx_backend_type (ctx) == CTX_BACKEND_RASTERIZER)
-   {
-      CtxRasterizer *rasterizer = (CtxRasterizer*)ctx->backend;
-      // XXX  only valid for RGBA8
-      if (rasterizer->format->pixel_format == CTX_FORMAT_RGBA8)
-      {
-#ifdef INCLUDE_STB_IMAGE_WRITE_H
-        stbi_write_png (output_path, rasterizer->blit_width, rasterizer->blit_height, 4, rasterizer->buf, 
rasterizer->blit_stride);
-#endif
-        return;
-      }
-   }
-
-  if (!ctx_backend_is_tiled (ctx))
-    return;
-
-  // we rely on the same struxt layout XXX !
-  for (int i = 0; i < tiled->width * tiled->height; i++)
-  {
-    int tmp = tiled->pixels[i*4];
-    tiled->pixels[i*4] = tiled->pixels[i*4 + 2];
-    tiled->pixels[i*4 + 2] = tmp;
-  }
-
-#if 1
-  if (ctx_backend_type (ctx) != CTX_BACKEND_HEADLESS)
-  for (int i = 0; i < tiled->width * tiled->height; i++)
-  {
-    int tmp = tiled->pixels[i*4];
-    tiled->pixels[i*4] = tiled->pixels[i*4 + 2];
-    tiled->pixels[i*4 + 2] = tmp;
-  }
-#endif
-#ifdef INCLUDE_STB_IMAGE_WRITE_H
-  stbi_write_png (output_path, tiled->width, tiled->height, 4, tiled->pixels, tiled->width*4);
-#endif
-#endif
-}
 
 int ctx_show_fps = 1;
 void ctx_sdl_set_title (void *self, const char *new_title)
@@ -34940,17 +37898,18 @@ static void ctx_sdl_show_frame (CtxSDL *sdl, int block)
     static char tmp_title[1024];
     static uint64_t prev_time = 0;
     uint64_t time = ctx_ticks ();
-    float fps = 1000000.0/  (time - ctx_sdl_start_time);
-    float fps2 = 1000000.0/  (time - prev_time);
+    float fps = 1000000.0f/  (time - ctx_sdl_start_time);
+    float fps2 = 1000000.0f/  (time - prev_time);
     prev_time = time;
     static float fps_avg = 0.0f;
 
-    if (time - prev_time < 1000 * 1000 * 0.05)
+    if (time - prev_time < 1000 * 1000 * 0.05f)
     fps_avg = (fps_avg * 0.9f + fps2 *  0.1f);
 
-    sprintf (tmp_title, "FPS: %.1f %.1f %.1f", (fps2*0.75+fps_avg*0.25), fps2, fps);
-    
-    sprintf (&tmp_title[strlen(tmp_title)], " shape hit rate: %.2f", ctx_shape_cache_rate);
+    sprintf (tmp_title, "FPS: %.1f %.1f %.1f", (double)(fps2*0.75f+fps_avg*0.25f), (double)fps2, 
(double)fps);
+#if CTX_SHAPE_CACHE 
+    sprintf (&tmp_title[strlen(tmp_title)], " shape hit rate: %.2f", (double)ctx_shape_cache_rate);
+#endif
 
     SDL_SetWindowTitle (sdl->window, tmp_title);
   }
@@ -35220,8 +38179,8 @@ void ctx_sdl_consume_events (Ctx *ctx)
           SDL_DestroyTexture (sdl->texture);
           sdl->texture = SDL_CreateTexture (sdl->backend, SDL_PIXELFORMAT_ABGR8888,
                           SDL_TEXTUREACCESS_STREAMING, width, height);
-          free (tiled->pixels);
-          tiled->pixels = calloc (4, width * height);
+          ctx_free (tiled->pixels);
+          tiled->pixels = ctx_calloc (4, width * height);
 
           tiled->width  = width;
           tiled->height = height;
@@ -35232,13 +38191,6 @@ void ctx_sdl_consume_events (Ctx *ctx)
     }
   }
 }
-#else
-void ctx_screenshot (Ctx *ctx, const char *path)
-{
-}
-#endif
-
-#if CTX_SDL
 
 static void ctx_sdl_set_clipboard (Ctx *ctx, const char *text)
 {
@@ -35252,14 +38204,14 @@ static char *ctx_sdl_get_clipboard (Ctx *ctx)
 }
 
 
-inline static void ctx_sdl_reset (Ctx *ctx)
+inline static void ctx_sdl_start_frame (Ctx *ctx)
 {
   CtxSDL  *sdl = (CtxSDL*)ctx->backend;
   ctx_sdl_show_frame (sdl, 1);
   ctx_sdl_start_time = ctx_ticks ();
 }
 
-void ctx_sdl_free (CtxSDL *sdl)
+void ctx_sdl_destroy (CtxSDL *sdl)
 {
   if (sdl->texture)
     SDL_DestroyTexture (sdl->texture);
@@ -35268,11 +38220,10 @@ void ctx_sdl_free (CtxSDL *sdl)
   if (sdl->window)
   {
     SDL_DestroyWindow (sdl->window);
-    ctx_babl_exit ();
   }
   sdl->texture = NULL;sdl->backend = NULL;sdl->window = NULL;
 
-  ctx_tiled_free ((CtxTiled*)sdl);
+  ctx_tiled_destroy ((CtxTiled*)sdl);
 }
 
 
@@ -35302,11 +38253,12 @@ Ctx *ctx_new_sdl (int width, int height)
 {
 #if CTX_RASTERIZER
 
-  CtxSDL *sdl = (CtxSDL*)calloc (sizeof (CtxSDL), 1);
+  CtxSDL *sdl = (CtxSDL*)ctx_calloc (sizeof (CtxSDL), 1);
   CtxTiled *tiled = (void*)sdl;
   CtxBackend *backend = (CtxBackend*)sdl;
-
+#if CTX_BABL
   ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
+#endif
   if (width <= 0 || height <= 0)
   {
     width  = 1920;
@@ -35317,11 +38269,10 @@ Ctx *ctx_new_sdl (int width, int height)
   sdl->backend = SDL_CreateRenderer (sdl->window, -1, 0);
   if (!sdl->backend)
   {
-     ctx_free (backend->ctx);
-     free (sdl);
+     ctx_destroy (backend->ctx);
+     ctx_free (sdl);
      return NULL;
   }
-  ctx_babl_init ();
   sdl->fullscreen = 0;
 
 
@@ -35346,15 +38297,15 @@ Ctx *ctx_new_sdl (int width, int height)
   ctx_set_backend (tiled->ctx_copy, sdl);
   ctx_set_texture_cache (tiled->ctx_copy, backend->ctx);
 
-  tiled->pixels = (uint8_t*)malloc (width * height * 4);
+  tiled->pixels = (uint8_t*)ctx_malloc (width * height * 4);
   tiled->show_frame = (void*)ctx_sdl_show_frame;
 
 
   backend->set_windowtitle = (void*)ctx_sdl_set_title;
-  backend->flush = ctx_tiled_flush;
+  backend->end_frame = ctx_tiled_end_frame;
   backend->process = (void*)ctx_drawlist_process;
-  backend->reset = ctx_sdl_reset;
-  backend->free  = (void*)ctx_sdl_free;
+  backend->start_frame = ctx_sdl_start_frame;
+  backend->destroy = (void*)ctx_sdl_destroy;
   backend->consume_events = ctx_sdl_consume_events;
 
   backend->set_clipboard = ctx_sdl_set_clipboard;
@@ -35403,7 +38354,7 @@ Ctx *ctx_new_sdl (int width, int height)
 }
 #endif
 
-#if CTX_EVENTS
+#if CTX_TERMINAL_EVENTS
 
 #if !__COSMOPOLITAN__
 #include <fcntl.h>
@@ -35465,14 +38416,14 @@ void ctx_term_set (CtxTerm *term,
   if (col < 1 || row < 1 || col > term->cols  || row > term->rows) return;
   while (ctx_list_length (term->lines) < row)
   {
-    ctx_list_append (&term->lines, calloc (sizeof (CtxTermLine), 1));
+    ctx_list_append (&term->lines, ctx_calloc (sizeof (CtxTermLine), 1));
   }
   CtxTermLine *line = ctx_list_nth_data (term->lines, row-1);
   assert (line);
   if (line->size < col)
   {
      int new_size = ((col + 128)/128)*128;
-     line->cells = realloc (line->cells, sizeof (CtxTermCell) * new_size);
+     line->cells = ctx_realloc (line->cells, line->size, sizeof (CtxTermCell) * new_size);
      memset (&line->cells[line->size], 0, sizeof (CtxTermCell) * (new_size - line->size) );
      line->size = new_size;
   }
@@ -35500,14 +38451,14 @@ static void ctx_term_set_fg (int red, int green, int blue)
   _ctx_curfg=lc;
   if (_ctx_term256 == 0)
   {
-    printf("\e[38;2;%i;%i;%im", red,green,blue);
+    fprintf(stderr, "\e[38;2;%i;%i;%im", red,green,blue);
   }
   else
   {
-    int gray = (green /255.0) * 24 + 0.5;
-    int r    = (red/255.0)    * 6 + 0.5;
-    int g    = (green/255.0)  * 6 + 0.5;
-    int b    = (blue/255.0)   * 6 + 0.5;
+    int gray = (int)((green /255.0f) * 24 + 0.5f);
+    int r    = (int)((red/255.0f)    * 6 + 0.5f);
+    int g    = (int)((green/255.0f)  * 6 + 0.5f);
+    int b    = (int)((blue/255.0f)   * 6 + 0.5f);
     if (gray > 23) gray = 23;
 
     if (r > 5) r = 5;
@@ -35516,10 +38467,10 @@ static void ctx_term_set_fg (int red, int green, int blue)
 
     if (((int)(r/1.66)== (int)(g/1.66)) && ((int)(g/1.66) == ((int)(b/1.66))))
     {
-      printf("\e[38;5;%im", 16 + 216 + gray);
+      fprintf(stderr,"\e[38;5;%im", 16 + 216 + gray);
     }
     else
-      printf("\e[38;5;%im", 16 + r * 6 * 6 + g * 6  + b);
+      fprintf(stderr,"\e[38;5;%im", 16 + r * 6 * 6 + g * 6  + b);
   }
 }
 
@@ -35531,14 +38482,14 @@ static void ctx_term_set_bg(int red, int green, int blue)
   _ctx_curbg=lc;
   if (_ctx_term256 == 0)
   {
-    printf("\e[48;2;%i;%i;%im", red,green,blue);
+    fprintf(stderr,"\e[48;2;%i;%i;%im", red,green,blue);
   }
   else
   {
-    int gray = (green /255.0) * 24 + 0.5;
-    int r    = (red/255.0)    * 6 + 0.5;
-    int g    = (green/255.0)  * 6 + 0.5;
-    int b    = (blue/255.0)   * 6 + 0.5;
+    int gray = (int)((green /255.0f) * 24 + 0.5f);
+    int r    = (int)((red/255.0f)    * 6 + 0.5f);
+    int g    = (int)((green/255.0f)  * 6 + 0.5f);
+    int b    = (int)((blue/255.0f)   * 6 + 0.5f);
     if (gray > 23) gray = 23;
 
     if (r > 5) r = 5;
@@ -35547,10 +38498,10 @@ static void ctx_term_set_bg(int red, int green, int blue)
 
     if (((int)(r/1.66)== (int)(g/1.66)) && ((int)(g/1.66) == ((int)(b/1.66))))
     {
-      printf("\e[48;5;%im", 16 + 216 + gray);
+      fprintf(stderr,"\e[48;5;%im", 16 + 216 + gray);
     }
     else
-      printf("\e[48;5;%im", 16 + r * 6 * 6 + g * 6  + b);
+      fprintf(stderr,"\e[48;5;%im", 16 + r * 6 * 6 + g * 6  + b);
   }
 }
 
@@ -35559,9 +38510,9 @@ static int _ctx_term_force_full = 0;
 void ctx_term_scanout (CtxTerm *term)
 {
   int row = 1;
-  printf ("\e[H");
+  fprintf (stderr,"\e[H");
 //  printf ("\e[?25l");
-  printf ("\e[0m");
+  fprintf (stderr, "\e[0m");
 
   int cur_fg[3]={-1,-1,-1};
   int cur_bg[3]={-1,-1,-1};
@@ -35595,24 +38546,24 @@ void ctx_term_scanout (CtxTerm *term)
           cur_bg[1]=cell->bg[1];
           cur_bg[2]=cell->bg[2];
         }
-        printf ("%s", cell->utf8);
+        fprintf (stderr, "%s", cell->utf8);
       }
       else
       {
         // TODO: accumulate succesive such to be ignored items,
         // and compress them into one, making us compress largely
         // reused screens well
-        printf ("\e[C");
+        fprintf (stderr, "\e[C");
       }
       strcpy (cell->prev_utf8, cell->utf8);
       memcpy (cell->prev_fg, cell->fg, 3);
       memcpy (cell->prev_bg, cell->bg, 3);
     }
     if (row != term->rows)
-      printf ("\n\r");
+      fprintf (stderr, "\n\r");
     row ++;
   }
-  printf ("\e[0m");
+  fprintf (stderr, "\e[0m");
   //printf ("\e[?25h");
   //
 }
@@ -35623,16 +38574,16 @@ void ctx_term_scanout (CtxTerm *term)
 //
 
 static inline int _ctx_rgba8_manhattan_diff (const uint8_t *a, const uint8_t *b)
-{
+{ // wrongly named!
   int c;
   int diff = 0;
   for (c = 0; c<3;c++)
-    diff += ctx_pow2(a[c]-b[c]);
-  return ctx_sqrtf(diff);
+    diff += (int)ctx_pow2(a[c]-b[c]);
+  return (int)ctx_sqrtf(diff);
   return diff;
 }
 
-static void ctx_term_output_buf_half (uint8_t *pixels,
+static inline void ctx_term_output_buf_half (uint8_t *pixels,
                           int width,
                           int height,
                           CtxTerm *term)
@@ -36168,7 +39119,7 @@ inline static void ctx_term_process (Ctx *ctx,
             col < (shape_rect.x+(int)shape_rect.width);
             col++)
 
-       {
+       if (0){ // disabled - offset is wrong (or offset of cursor in stuff is wrong
          for (CtxList *l = rasterizer->glyphs; l; l=l?l->next:NULL)
          {
            CtxTermGlyph *glyph = l->data;
@@ -36176,7 +39127,7 @@ inline static void ctx_term_process (Ctx *ctx,
                (glyph->col == col+1))
            {
               ctx_list_remove (&rasterizer->glyphs, glyph);
-              free (glyph);
+              ctx_free (glyph);
               l = NULL;
            }
          }
@@ -36196,7 +39147,7 @@ inline static void ctx_term_process (Ctx *ctx,
   ctx_process (term->host, &command->entry);
 }
 
-inline static void ctx_term_flush (Ctx *ctx)
+inline static void ctx_term_end_frame (Ctx *ctx)
 {
   CtxTerm *term = (CtxTerm*)ctx->backend;
   int width =  term->width;
@@ -36256,31 +39207,33 @@ inline static void ctx_term_flush (Ctx *ctx)
     utf8[ctx_unichar_to_utf8(glyph->unichar, (uint8_t*)utf8)]=0;
     ctx_term_set (term, glyph->col, glyph->row, 
                      utf8, glyph->rgba_fg, glyph->rgba_bg);
-    free (glyph);
+    ctx_free (glyph);
   }
 
+#endif
   printf ("\e[H");
   printf ("\e[0m");
   ctx_term_scanout (term);
   printf ("\e[0m");
-  fflush(NULL);
+  fflush (NULL);
+#if CTX_BRAILLE_TEXT
   while (rasterizer->glyphs)
     ctx_list_remove (&rasterizer->glyphs, rasterizer->glyphs->data);
 #endif
 }
 
-void ctx_term_free (CtxTerm *term)
+void ctx_term_destroy (CtxTerm *term)
 {
   while (term->lines)
   {
-    free (term->lines->data);
+    ctx_free (term->lines->data);
     ctx_list_remove (&term->lines, term->lines->data);
   }
   printf ("\e[?25h"); // cursor on
   nc_at_exit ();
-  free (term->pixels);
-  ctx_free (term->host);
-  free (term);
+  ctx_free (term->pixels);
+  ctx_destroy (term->host);
+  ctx_free (term);
   /* we're not destoring the ctx member, this is function is called in ctx' teardown */
 }
 
@@ -36298,7 +39251,7 @@ Ctx *ctx_new_term (int width, int height)
 {
   Ctx *ctx = _ctx_new_drawlist (width, height);
 #if CTX_RASTERIZER
-  CtxTerm *term = (CtxTerm*)calloc (sizeof (CtxTerm), 1);
+  CtxTerm *term = (CtxTerm*)ctx_calloc (sizeof (CtxTerm), 1);
   CtxBackend *backend = (void*)term;
  
   const char *mode = getenv ("CTX_TERM_MODE");
@@ -36328,8 +39281,8 @@ Ctx *ctx_new_term (int width, int height)
   if (mode && strcmp (mode, "0") && strcmp (mode, "no"))
     _ctx_term_force_full = 1;
 
-  fprintf (stdout, "\e[?1049h");
-  fprintf (stdout, "\e[?25l"); // cursor off
+  fprintf (stderr, "\e[?1049h");
+  fprintf (stderr, "\e[?25l"); // cursor off
 
   int maxwidth = ctx_terminal_cols  () * ctx_term_cw;
   int maxheight = (ctx_terminal_rows ()) * ctx_term_ch;
@@ -36347,7 +39300,7 @@ Ctx *ctx_new_term (int width, int height)
   term->cols = (width + 1) / ctx_term_cw;
   term->rows = (height + 2) / ctx_term_ch;
   term->lines = 0;
-  term->pixels = (uint8_t*)malloc (width * height * 4);
+  term->pixels = (uint8_t*)ctx_malloc (width * height * 4);
   term->host = ctx_new_for_framebuffer (term->pixels,
                                            width, height,
                                            width * 4, CTX_FORMAT_RGBA8);
@@ -36357,8 +39310,8 @@ Ctx *ctx_new_term (int width, int height)
   _ctx_mouse (ctx, NC_MOUSE_DRAG);
   ctx_set_backend (ctx, term);
   backend->process = ctx_term_process;
-  backend->flush   = ctx_term_flush;
-  backend->free    = (void(*)(void*))ctx_term_free;
+  backend->end_frame = ctx_term_end_frame;
+  backend->destroy = (void(*)(void*))ctx_term_destroy;
   backend->consume_events = ctx_nct_consume_events;
   backend->get_event_fds = (void*) ctx_stdin_get_event_fds;
   ctx_set_size (ctx, width, height);
@@ -36371,7 +39324,7 @@ Ctx *ctx_new_term (int width, int height)
 
 #endif
 
-#if CTX_EVENTS
+#if CTX_TERMINAL_EVENTS
 
 #if !__COSMOPOLITAN__
 #include <fcntl.h>
@@ -36405,13 +39358,13 @@ inline static void ctx_termimg_process (Ctx        *ctx,
   ctx_process (termimg->host, &command->entry);
 }
 
-inline static void ctx_termimg_flush (Ctx *ctx)
+inline static void ctx_termimg_end_frame (Ctx *ctx)
 {
   CtxTermImg *termimg = (CtxTermImg*)ctx->backend;
   int width =  termimg->width;
   int height = termimg->height;
   if (!termimg->pixels) return;
-  char *encoded = malloc (width * height * 3 * 3);
+  char *encoded = ctx_malloc (width * height * 3 * 3);
   ctx_bin2base64 (termimg->pixels, width * height * 3,
                   encoded);
   int encoded_len = strlen (encoded);
@@ -36437,23 +39390,23 @@ inline static void ctx_termimg_flush (Ctx *ctx)
      }
      printf ("\e\\");
   }
-  free (encoded);
+  ctx_free (encoded);
   
   fflush (NULL);
 }
 
-void ctx_termimg_free (CtxTermImg *termimg)
+void ctx_termimg_destroy (CtxTermImg *termimg)
 {
   while (termimg->lines)
   {
-    free (termimg->lines->data);
+    ctx_free (termimg->lines->data);
     ctx_list_remove (&termimg->lines, termimg->lines->data);
   }
   printf ("\e[?25h"); // cursor on
   nc_at_exit ();
-  free (termimg->pixels);
-  ctx_free (termimg->host);
-  free (termimg);
+  ctx_free (termimg->pixels);
+  ctx_destroy (termimg->host);
+  ctx_free (termimg);
   /* we're not destoring the ctx member, this is function is called in ctx' teardown */
 }
 
@@ -36463,7 +39416,7 @@ Ctx *ctx_new_termimg (int width, int height)
 #if CTX_RASTERIZER
   fprintf (stdout, "\e[?1049h");
   fprintf (stdout, "\e[?25l"); // cursor off
-  CtxTermImg *termimg = (CtxTermImg*)calloc (sizeof (CtxTermImg), 1);
+  CtxTermImg *termimg = (CtxTermImg*)ctx_calloc (sizeof (CtxTermImg), 1);
   CtxBackend *backend = (void*)termimg;
 
 
@@ -36483,7 +39436,7 @@ Ctx *ctx_new_termimg (int width, int height)
   termimg->width  = width;
   termimg->height = height;
   termimg->lines = 0;
-  termimg->pixels = (uint8_t*)malloc (width * height * 3);
+  termimg->pixels = (uint8_t*)ctx_malloc (width * height * 3);
   termimg->host = ctx_new_for_framebuffer (termimg->pixels,
                                            width, height,
                                            width * 3, CTX_FORMAT_RGB8);
@@ -36492,8 +39445,8 @@ Ctx *ctx_new_termimg (int width, int height)
 
   backend->ctx = ctx;
   backend->process = ctx_termimg_process;
-  backend->flush = ctx_termimg_flush;
-  backend->free  = (void(*)(void*))ctx_termimg_free;
+  backend->end_frame = ctx_termimg_end_frame;
+  backend->destroy = (void(*)(void*))ctx_termimg_destroy;
   backend->consume_events = ctx_nct_consume_events;
   backend->get_event_fds = (void*) ctx_stdin_get_event_fds;
   ctx_set_size (ctx, width, height);
@@ -36511,24 +39464,40 @@ typedef struct CtxCbBackend
   CtxBackend     backend;
   CtxPixelFormat format;
   int            flags;
+  int            memory_budget;
+  int            min_col; // hasher cols and rows
+  int            min_row; // hasher cols and rows
+  int            max_col; // hasher cols and rows
+  int            max_row; // hasher cols and rows
   uint16_t      *fb;
+  Ctx           *ctx;
 
   void (*set_pixels) (Ctx *ctx, void *user_data, 
-                      int x, int y, int w, int h, void *buf);
-  void (*update_fb) (Ctx *ctx, void *user_data);
+                      int x, int y, int w, int h, void *buf, int buf_size);
+  void   *set_pixels_user_data;
+  int  (*update_fb) (Ctx *ctx, void *user_data);
+  void   *update_fb_user_data;
 
-  int     min_col; // hasher cols and rows
-  int     min_row; // hasher cols and rows
-  int     max_col; // hasher cols and rows
-  int     max_row; // hasher cols and rows
   uint32_t hashes[CTX_HASH_ROWS * CTX_HASH_COLS];
-  int     memory_budget;
-  void   *user_data;
+
+  CtxHasher     rasterizer;
+  uint8_t res[CTX_HASH_ROWS * CTX_HASH_COLS]; // when non-0 we have non-full res rendered
 } CtxCbBackend;
 
 void ctx_cb_set_flags (Ctx *ctx, int flags)
 {
   CtxCbBackend *backend_cb = (CtxCbBackend*)ctx->backend;
+  if (flags & CTX_FLAG_GRAY2)
+    flags |= CTX_FLAG_LOWFI;
+  if (flags & CTX_FLAG_GRAY4)
+    flags |= CTX_FLAG_LOWFI;
+  if (flags & CTX_FLAG_GRAY8)
+    flags |= CTX_FLAG_LOWFI;
+  if (flags & CTX_FLAG_RGB332)
+    flags |= CTX_FLAG_LOWFI;
+
+  if (flags & CTX_FLAG_LOWFI)
+    flags |= CTX_FLAG_HASH_CACHE;
   backend_cb->flags = flags;
 }
 
@@ -36538,111 +39507,355 @@ int ctx_cb_get_flags (Ctx *ctx)
   return backend_cb->flags;
 }
 
-static void ctx_render_cb (Ctx *ctx, 
-                            int x0, int y0,
-                            int x1, int y1)
+static inline uint16_t ctx_rgb332_to_rgb565 (uint8_t rgb, int byteswap)
+{
+   uint8_t red, green, blue;
+   ctx_332_unpack (rgb, &red, &green, &blue);
+   return ctx_565_pack (red, green, blue, byteswap);
+}
+
+void
+ctx_cb_set_memory_budget (Ctx *ctx, int memory_budget)
 {
   CtxCbBackend *backend_cb = (CtxCbBackend*)ctx->backend;
-  int flags                  = backend_cb->flags;
-  int memory_budget          = backend_cb->memory_budget;
-  int width                  = x1 - x0 + 1;
-  int height                 = y1 - y0 + 1;
-  uint16_t *fb;
-  CtxPixelFormat             format = backend_cb->format;
-  int bpp                    = ctx_pixel_format_bits_per_pixel (format)/ 8;
+  backend_cb->memory_budget = memory_budget;
+  if (backend_cb->fb)
+  {
+    ctx_free (backend_cb->fb);
+    backend_cb->fb = NULL;
+  }
+}
+
+#define CTX_MEMDEBUG 0  // by setting this to 1 we get reports about
+                        // scratch buffer overflows into the 1kb buffer
+                        // area
+                        //
+#if CTX_MEMDEBUG
+#define CTX_SCRATCH_PAD  512
 
-  int chunk_size = 16; /* wanting chunks of 16 scanlines at a
-                          time to go out seems to give good
-                          spi bandwidth use */
-  while (chunk_size * width * 2 > memory_budget/2)
+static void
+ctx_memdebug (CtxCbBackend *cb_backend, int line_no)
+{
+  int started = 0;
+  int last = 0;
+  int first = 0;
+  if (!cb_backend->fb)
+    return;
+  for (int i = cb_backend->memory_budget/2; i < cb_backend->memory_budget/2 + CTX_SCRATCH_PAD/2;i++)
   {
-    chunk_size/=2;
+    if (cb_backend->fb[i] != 42)
+    {
+      if (!started)
+      {
+        first = i;
+        started = 1;
+      }
+      last = i;
+      cb_backend->fb[i] = 42;
+    }
   }
- 
+  if (started)
+  fprintf (stderr, "%i scratch overreach - first wrong byte at buf + %i last: %i\n",
+                  line_no,
+                  first - cb_backend->memory_budget/2,
+                                                                          last - 
cb_backend->memory_budget/2);
+}
+                        
+#define CTX_VERIFY_MEM()  do{ctx_memdebug(backend_cb, __LINE__);}while(0)
+#else
+#define CTX_SCRATCH_PAD   1024
+#define CTX_VERIFY_MEM()  do{}while(0)
+#endif
+
+static int ctx_render_cb (CtxCbBackend *backend_cb, 
+                          int x0, int y0,
+                          int x1, int y1,
+                          uint32_t active_mask)
+{
+  Ctx *ctx           = backend_cb->ctx;
+  int flags          = backend_cb->flags;
+  int memory_budget  = backend_cb->memory_budget;
+  uint16_t *fb;
+  CtxPixelFormat format = backend_cb->format;
+  int bpp            = ctx_pixel_format_bits_per_pixel (format) / 8;
+  int abort          = 0;
+  
+  int width          = x1 - x0 + 1;
+  int height         = y1 - y0 + 1;
+  int byteswap;
+  byteswap = (format == CTX_FORMAT_RGB565_BYTESWAPPED);
+
   if (!backend_cb->fb)
-    backend_cb->fb = (uint16_t*)malloc (memory_budget);
+  {
+    backend_cb->fb = (uint16_t*)ctx_malloc (memory_budget + CTX_SCRATCH_PAD);
+#if CTX_MEMDEBUG
+    for (int i = backend_cb->memory_budget/2; i < backend_cb->memory_budget/2 + CTX_SCRATCH_PAD/2;i++)
+      backend_cb->fb[i] = 42;
+#endif
+  }
   fb = backend_cb->fb;
 
-  if (flags & CTX_CB_332)
+#if CTX_ENABLE_CBRLE
+  if (flags & CTX_FLAG_CBRLE)
   {
-    int render_height = height;
-    memory_budget -= chunk_size * width * 2;
-
-    if (width * render_height > memory_budget)
+    int bitdepth = memory_budget * 8 / height / width;
+    int zformat;
+    if (bitdepth < 1)
     {
-       render_height = memory_budget / width;
+      fprintf (stderr, "not enough memory for 1bit cbrle\n");
+      return 1;
     }
-    do
-    {
-
-    render_height = ctx_mini (render_height, y1-y0);
-    memset (fb, 0, width * render_height);
-    Ctx *renderer = ctx_new_for_framebuffer (fb,
-       width, render_height, width,
-       CTX_FORMAT_RGB332);
+    switch (bitdepth)
+    {
+      case 1: zformat = CTX_FORMAT_CBRLE_1; break;
+      case 2: zformat = CTX_FORMAT_CBRLE_2; break;
+      case 3: zformat = CTX_FORMAT_CBRLE_3; break;
+      case 4: zformat = CTX_FORMAT_CBRLE_4; break;
+      case 5: zformat = CTX_FORMAT_CBRLE_5; break;
+      case 6: zformat = CTX_FORMAT_CBRLE_6; break;
+      case 7: zformat = CTX_FORMAT_CBRLE_7; break;
+      case 8: zformat = CTX_FORMAT_CBRLE_8; break;
+      case 9: zformat = CTX_FORMAT_CBRLE_9; break;
+      case 10: zformat = CTX_FORMAT_CBRLE_10; break;
+      case 11: zformat = CTX_FORMAT_CBRLE_11; break;
+      case 12: zformat = CTX_FORMAT_CBRLE_12; break;
+      case 13: zformat = CTX_FORMAT_CBRLE_13; break;
+      case 14: zformat = CTX_FORMAT_CBRLE_14; break;
+      case 15: zformat = CTX_FORMAT_CBRLE_15; break;
+      case 16: zformat = CTX_FORMAT_CBRLE_16; break;
+      case 17: zformat = CTX_FORMAT_CBRLE_17; break;
+      case 18: zformat = CTX_FORMAT_CBRLE_18; break;
+      case 19: zformat = CTX_FORMAT_CBRLE_19; break;
+      case 20: zformat = CTX_FORMAT_CBRLE_20; break;
+      case 21: zformat = CTX_FORMAT_CBRLE_21; break;
+      case 22: zformat = CTX_FORMAT_CBRLE_22; break;
+      case 23: zformat = CTX_FORMAT_CBRLE_23; break;
+      default:
+      case 24: zformat = CTX_FORMAT_CBRLE_24; break;
+    }
+    //zformat = CTX_FORMAT_GRAY4;
+    //bitdepth = 4;
+    int stride = (width * bitdepth + 7) / 8;
+
+    memset(fb, 0, stride * height);
+    CtxRasterizer *r = ctx_rasterizer_init ((CtxRasterizer*)&backend_cb->rasterizer,
+                ctx, NULL, &ctx->state, fb, x0, y0, width, height,
+                stride, zformat, CTX_ANTIALIAS_DEFAULT);
+    ((CtxBackend*)r)->destroy = (CtxDestroyNotify)ctx_rasterizer_deinit;
+    ctx_push_backend (ctx, r);
+
+    //ctx_scale (ctx, 1.0f/scale_factor, 1.0f/scale_factor);
+    ctx_translate (ctx, -1.0f * x0, -1.0f * y0);
+    if (active_mask)
+      ctx_render_ctx_masked (ctx, ctx, active_mask);
+    else
+      ctx_render_ctx (ctx, ctx);
 
-    ctx_translate (renderer, -1.0 * x0, -1.0 * y0);
-    ctx_render_ctx (ctx, renderer);
-    ctx_free (renderer);
+    for (int y = 0; y < height;y++)
+    {
+      uint8_t rgba8[width*4];
+      uint16_t rgb565[width];
 
-    uint8_t *temp = ((uint8_t*)fb)+memory_budget;
-    uint8_t *src = (uint8_t*)fb;
+      _ctx_CBRLE_decompress ((uint8_t*)&fb[stride * y/2], 
+                              rgba8, width, stride, 0, width);
 
-    for (int y = y0; y < y0 + render_height; y+=chunk_size)
-    {
-      uint16_t *dst = (uint16_t*)temp;
-      float h = ctx_mini (chunk_size, y1-y);
-      for (int i = 0; i < width * h; i++)
+      for (int i = 0; i < width; i++)
       {
-        int val = *src++;
-        uint8_t r, g, b;
-        ctx_332_unpack (val, &r, &g, &b);
-        *dst++ = ctx_565_pack (r, g, b, 1);
+         rgb565[i] = ctx_888_to_565 ( ((uint32_t*)&rgba8[i*4])[0], 1);
       }
-      backend_cb->set_pixels (ctx, backend_cb->user_data, 
-                              x0, y, width, h, (uint16_t*)temp);
+
+      backend_cb->set_pixels (ctx, backend_cb->set_pixels_user_data, 
+                            //x0, y0, width, render_height, (uint16_t*)scaled,
+                            //width * render_height * bpp);
+                            x0,y0+y,width,1,(void*)rgb565,
+                            stride);// * height);
     }
-      y0 += render_height;
-    } while (y0 < y1);
+
+    ctx_pop_backend (ctx);    
+
+    return abort;
   }
-  else if (flags & CTX_CB_GRAY)
+#endif
+
+  if (flags & CTX_FLAG_LOWFI)
   {
-     int render_height = height;
-     memory_budget -= chunk_size * width * 2;
-     if (width * render_height > memory_budget)
-     {
-       render_height = memory_budget / width;
-     }
-    do
+    int scale_factor  = 1;
+    int small_width   = width / scale_factor;
+    int small_height  = height / scale_factor;
+
+    int tbpp = bpp * 8;
+    CtxPixelFormat tformat = format;
+      if   (flags & CTX_FLAG_GRAY2)
+      {
+        tformat = CTX_FORMAT_GRAY2;
+        tbpp = 2;
+      }
+      else if (flags & CTX_FLAG_GRAY4)
+      {
+        tformat = CTX_FORMAT_GRAY4;
+        tbpp = 4;
+      }
+      else if (flags & CTX_FLAG_GRAY8)
+      {
+        tformat = CTX_FORMAT_GRAY8;
+        tbpp = 8;
+      }
+      else
+      if (flags & (CTX_FLAG_RGB332))
+      {
+        tbpp = 8;
+        tformat = CTX_FORMAT_RGB332;
+      }
+    int small_stride = (small_width * tbpp + 7) / 8;
+    int min_scanlines = 4;
+
+    while (memory_budget - (small_height * small_stride) < width * bpp * min_scanlines)
     {
+      scale_factor ++;
+      small_width   = width / scale_factor;
+      small_height  = height / scale_factor;
+      min_scanlines = scale_factor * 2;
+      small_stride  = (small_width * tbpp + 7) / 8;
+    }
+
+    int render_height = (memory_budget - (small_height * small_stride)) /
+                        (width * bpp);
 
-    render_height = ctx_mini (render_height, y1-y0);
-    memset (fb, 0, width * render_height);
-    Ctx *renderer = ctx_new_for_framebuffer (fb,
-       width, render_height, width,
-       CTX_FORMAT_GRAY8);
+    const uint8_t *fb_u8 = (uint8_t*)fb;
+    uint16_t *scaled = (uint16_t*)&fb_u8[small_height*small_stride];
 
-    ctx_translate (renderer, -1.0 * x0, -1.0 * y0);
-    ctx_render_ctx (ctx, renderer);
-    ctx_free (renderer);
+    memset(fb, 0, small_stride * small_height);
+    CtxRasterizer *r = ctx_rasterizer_init ((CtxRasterizer*)&backend_cb->rasterizer,
+                ctx, NULL, &ctx->state, fb, 0, 0, small_width, small_height,
+                small_stride, tformat, CTX_ANTIALIAS_DEFAULT);
+    ((CtxBackend*)r)->destroy = (CtxDestroyNotify)ctx_rasterizer_deinit;
+    ctx_push_backend (ctx, r);
 
-    uint8_t *temp = ((uint8_t*)fb)+memory_budget;
-    uint8_t *src = (uint8_t*)fb;
+    ctx_scale (ctx, 1.0f/scale_factor, 1.0f/scale_factor);
+    ctx_translate (ctx, -1.0f * x0, -1.0f * y0);
+    if (active_mask)
+      ctx_render_ctx_masked (ctx, ctx, active_mask);
+    else
+      ctx_render_ctx (ctx, ctx);
+    ctx_pop_backend (ctx);
 
-    for (int y = y0; y < y0 + render_height; y+=chunk_size)
+    if (backend_cb->update_fb && (flags & CTX_FLAG_INTRA_UPDATE))
+      backend_cb->update_fb (ctx, backend_cb->update_fb_user_data);
+    int yo = 0;
+    do
     {
-      uint16_t *dst = (uint16_t*)temp;
-      float h = ctx_mini (chunk_size, y1-y);
-      for (int i = 0; i < width * h; i++)
+      render_height = ctx_mini (render_height, y1-y0+1);
+      int off = 0;
+      for (int y = 0; y < render_height; y++)
       {
-        int val = *src++;
-        *dst++ = ctx_565_pack (val, val, val, 1);
+        int sbase = (small_stride * ((yo+y)/scale_factor));
+        off = y * width;
+        switch (tformat)
+        {
+          case CTX_FORMAT_GRAY1:
+            {
+              int sx = 0;
+              for (int x = 0; x < width;)
+              {
+                int     soff = sbase + ((sx)/8);
+                uint8_t bits = fb_u8[soff];
+                uint16_t val = (bits & (1<<(sx&7)))?0xffff:0;
+                sx++;
+
+                for (int i = 0; i < scale_factor && x < width; i++, x++)
+                  scaled[off++]  = val;
+              }
+            }
+            break;
+          case CTX_FORMAT_GRAY2:
+            {
+              int sx = 0;
+              for (int x = 0; x < width;)
+              {
+                int     soff = sbase + ((sx)/4);
+                uint8_t bits = fb_u8[soff];
+                uint8_t g    = 85 * ((bits >> (2*(sx&3)))&3);
+                uint16_t val = ctx_565_pack (g, g, g, byteswap);
+                sx++;
+
+                for (int i = 0; i < scale_factor && x < width; i++, x++)
+                  scaled[off++]  = val;
+              }
+            }
+            break;
+          case CTX_FORMAT_GRAY4:
+            {
+              int sx = 0;
+              for (int x = 0; x < width;)
+              {
+                int     soff = sbase + ((sx)/2);
+                uint8_t bits = fb_u8[soff];
+                uint8_t g    = 17 * ((bits >> (4*(sx&1)))&15);
+                uint16_t val = ctx_565_pack (g, g, g, byteswap);
+                sx++;
+
+                for (int i = 0; i < scale_factor && x < width; i++, x++)
+                  scaled[off++]  = val;
+              }
+            }
+
+
+            break;
+          case CTX_FORMAT_GRAY8:
+            {
+              int sx = 0;
+              for (int x = 0; x < width;)
+              {
+                uint8_t g   = fb_u8[sbase + (sx++)];
+                uint16_t val = ctx_565_pack (g, g, g, byteswap);
+                for (int i = 0; i < scale_factor && x < width; i++, x++)
+                  scaled[off++]  = val;
+              }
+            }
+            break;
+          case CTX_FORMAT_RGB332:
+            {
+              int sx = 0;
+              for (int x = 0; x < width;)
+              {
+                uint16_t val = ctx_rgb332_to_rgb565 (
+                   fb_u8[sbase + (sx++)], byteswap);
+                for (int i = 0; i < scale_factor && x < width; i++, x++)
+                  scaled[off++]  = val;
+              }
+            }
+            break;
+          default:
+          case CTX_FORMAT_RGB565:
+          case CTX_FORMAT_RGB565_BYTESWAPPED:
+            {
+              int sx = 0;
+              for (int x = 0; x < width;)
+              {
+                uint16_t val = fb[sbase/2+(sx++)];
+                for (int i = 0; i < scale_factor && x < width; i++, x++)
+                  scaled[off++]  = val;
+              }
+            }
+            break;
+        }
+        for (int ty = 1; ty < scale_factor && y + 1< render_height; ty++)
+        {
+           memcpy (&scaled[off], &scaled[off-width], 2 * width);
+           off += width;
+           y++;
+        }
       }
-      backend_cb->set_pixels (ctx, backend_cb->user_data, 
-                              x0, y, width, h, (uint16_t*)temp);
-    }
+      backend_cb->set_pixels (ctx, backend_cb->set_pixels_user_data, 
+                              x0, y0, width, render_height, (uint16_t*)scaled,
+                              width * render_height * bpp);
       y0 += render_height;
+      yo += render_height;
     } while (y0 < y1);
+
+    if (backend_cb->update_fb && (flags & CTX_FLAG_INTRA_UPDATE))
+      backend_cb->update_fb (ctx, backend_cb->update_fb_user_data);
+    // abort does not happen for low-res update
   }
   else
   {
@@ -36651,72 +39864,105 @@ static void ctx_render_cb (Ctx *ctx,
     {
        render_height = memory_budget / width / bpp;
     }
+    CtxRasterizer *r = ctx_rasterizer_init((CtxRasterizer*)&backend_cb->rasterizer,
+                         ctx, NULL, &ctx->state, fb, 0, 0, width, height,
+                         width * bpp, format, CTX_ANTIALIAS_DEFAULT);
+    ((CtxBackend*)r)->destroy = (CtxDestroyNotify)ctx_rasterizer_deinit;
+    ctx_push_backend (ctx, r);
 
     do
     {
-      render_height = ctx_mini (render_height, y1-y0);
-      memset (fb, 0, width * bpp * render_height);
-      Ctx *renderer = ctx_new_for_framebuffer (fb, width, render_height, width * bpp,
-            format);
-      ctx_translate (renderer, -1.0 * x0, -1.0 * y0);
-      ctx_render_ctx (ctx, renderer);
-      backend_cb->set_pixels (ctx, backend_cb->user_data, 
-                              x0, y0, width, render_height, (uint16_t*)fb);
-      ctx_free (renderer);    
+      render_height = ctx_mini (render_height, y1-y0+1);
+      ctx_rasterizer_init (r, ctx, NULL, &ctx->state, fb, 0, 0, width,
+                   render_height, width * bpp, format, CTX_ANTIALIAS_DEFAULT);
+    ((CtxBackend*)r)->destroy = (CtxDestroyNotify)ctx_rasterizer_deinit;
+
+      if ((flags & CTX_FLAG_KEEP_DATA) == 0)
+        memset (fb, 0, width * bpp * render_height);
+
+      ctx_translate (ctx, -1.0f * x0, -1.0f * y0);
+      if (active_mask)
+        ctx_render_ctx_masked (ctx, ctx, active_mask);
+      else
+        ctx_render_ctx (ctx, ctx);
+
+      backend_cb->set_pixels (ctx, backend_cb->set_pixels_user_data, 
+                              x0, y0, width, render_height, (uint16_t*)fb,
+                              width * render_height * bpp);
+
+      if (backend_cb->update_fb && (flags & CTX_FLAG_INTRA_UPDATE))
+        abort = backend_cb->update_fb (ctx, backend_cb->update_fb_user_data);
 
       y0 += render_height;
-    } while (y0 < y1);
-  }
-  if (flags & CTX_CB_CYCLE_BUF)
-  {
-    free (fb);
-    backend_cb->fb = NULL;
+    } while (y0 < y1 && !abort);
+    ctx_pop_backend (ctx);    
   }
+  return abort;
 }
 
-CTX_EXPORT int
+
+/* XXX: todo replace this with a single function that writes
+ * to pointers, like path_extent
+ */
+static int
 ctx_cb_x0 (Ctx *ctx)
 {
   CtxCbBackend *cb_backend = (CtxCbBackend*)ctx->backend;
   return cb_backend->min_col * (ctx_width (ctx)/CTX_HASH_COLS);
 }
 
-CTX_EXPORT int
+static int
 ctx_cb_x1 (Ctx *ctx)
 {
   CtxCbBackend *cb_backend = (CtxCbBackend*)ctx->backend;
   return (cb_backend->max_col+1) * (ctx_width (ctx)/CTX_HASH_COLS)-1;
 }
 
-CTX_EXPORT int
+static int
 ctx_cb_y0 (Ctx *ctx)
 {
   CtxCbBackend *cb_backend = (CtxCbBackend*)ctx->backend;
   return cb_backend->min_row * (ctx_height (ctx)/CTX_HASH_ROWS);
 }
 
-CTX_EXPORT int
+static int
 ctx_cb_y1 (Ctx *ctx)
 {
   CtxCbBackend *cb_backend = (CtxCbBackend*)ctx->backend;
   return (cb_backend->max_row+1) * (ctx_height (ctx)/CTX_HASH_ROWS)-1;
 }
 
+void
+ctx_cb_extent (Ctx *ctx, float *x0, float *y0, float *x1, float *y1)
+{
+  if (x0) *x0 = ctx_cb_x0 (ctx);
+  if (y0) *y0 = ctx_cb_y0 (ctx);
+  if (x1) *x1 = ctx_cb_x1 (ctx);
+  if (y1) *y1 = ctx_cb_y1 (ctx);
+}
+
 static void
-ctx_cb_flush (Ctx *ctx)
+ctx_cb_end_frame (Ctx *ctx)
 {
   CtxCbBackend *cb_backend = (CtxCbBackend*)ctx->backend;
   static int64_t prev_time = 0;
   int64_t cur_time = ctx_ticks () / 1000;
+  int width = ctx_width (ctx);
+  int height = ctx_height (ctx);
+
+  int tile_width = width / CTX_HASH_COLS;
+  int tile_height = height / CTX_HASH_ROWS;
+  if (cb_backend->flags & (CTX_FLAG_GRAY2|CTX_FLAG_GRAY4|CTX_FLAG_GRAY8|CTX_FLAG_RGB332))
+      cb_backend->flags|=CTX_FLAG_LOWFI;
 
-  if (cb_backend->flags & CTX_CB_SHOW_FPS)
+  if (cb_backend->flags & CTX_FLAG_SHOW_FPS)
   {
    
-  float em = ctx_height (ctx) * 0.08;
+  float em = ctx_height (ctx) * 0.08f;
   float y = em;
   ctx_font_size (ctx, em);
-  ctx_rectangle (ctx, ctx_width(ctx)-(em*4), 0, em *4, em * 1.1);
-  ctx_rgba (ctx, 0, 0, 0, 0.7);
+  ctx_rectangle (ctx, ctx_width(ctx)-(em*4), 0, em *4, em * 1.1f);
+  ctx_rgba (ctx, 0, 0, 0, 0.7f);
   ctx_fill (ctx);
 
   ctx_rgba (ctx, 1, 1, 0, 1);
@@ -36725,8 +39971,8 @@ ctx_cb_flush (Ctx *ctx)
   {
     char buf[22];
     float fps = 1.0f/((cur_time-prev_time)/1000.0f);
-    ctx_move_to (ctx, ctx_width (ctx) - (em * 3.8), y);
-    sprintf (buf, "%2.1f fps", fps);
+    ctx_move_to (ctx, width - (em * 3.8f), y);
+    sprintf (buf, "%2.1f fps", (double)fps);
     ctx_text (ctx, buf);
     ctx_begin_path (ctx);
   }
@@ -36734,116 +39980,260 @@ ctx_cb_flush (Ctx *ctx)
   }
 
 
-  if (cb_backend->flags & CTX_CB_HASH_CACHE)
+  if (cb_backend->flags & CTX_FLAG_HASH_CACHE)
   {
-    Ctx *hasher = ctx_hasher_new (ctx_width (ctx), ctx_height (ctx),
-                                  CTX_HASH_COLS, CTX_HASH_ROWS);
+    CtxState    *state = &ctx->state;
+
+    CtxPixelFormat format = cb_backend->format;
+    int bpp               = ctx_pixel_format_bits_per_pixel (format) / 8;
+    int tile_dim          = tile_width * tile_height * bpp;
+
+    CtxRasterizer *rasterizer = (CtxRasterizer*)&cb_backend->rasterizer;
+    ctx_hasher_init (rasterizer, ctx, state, width, height, CTX_HASH_COLS, CTX_HASH_ROWS, &ctx->drawlist);
+    ((CtxBackend*)rasterizer)->destroy = (CtxDestroyNotify)ctx_rasterizer_deinit;
+
+    ctx_push_backend (ctx, rasterizer);
+
     int dirty_tiles = 0;
-    ctx_render_ctx (ctx, hasher);
+    ctx_render_ctx (ctx, ctx);
 
     cb_backend->max_col = -100;
     cb_backend->min_col = 100;
     cb_backend->max_row = -100;
     cb_backend->min_row = 100;
 
+    uint32_t active_mask = 0;
+    uint32_t *hashes = ((CtxHasher*)(ctx->backend))->hashes;
+    int tile_no =0;
+    int low_res_tiles = 0;
+
       for (int row = 0; row < CTX_HASH_ROWS; row++)
-        for (int col = 0; col < CTX_HASH_COLS; col++)
+        for (int col = 0; col < CTX_HASH_COLS; col++, tile_no++)
         {
-          uint32_t new_hash = ctx_hasher_get_hash (hasher, col, row);
+          uint32_t new_hash = hashes[tile_no];
           if (new_hash &&
-              new_hash != cb_backend->hashes[(row * CTX_HASH_COLS + col)])
+              new_hash != cb_backend->hashes[tile_no])
           {
-            cb_backend->hashes[(row * CTX_HASH_COLS +  col)]= new_hash;
             dirty_tiles++;
-
             cb_backend->max_col = ctx_maxi (cb_backend->max_col, col);
             cb_backend->max_row = ctx_maxi (cb_backend->max_row, row);
             cb_backend->min_col = ctx_mini (cb_backend->min_col, col);
             cb_backend->min_row = ctx_mini (cb_backend->min_row, row);
           }
+          else
+          {
+            low_res_tiles += cb_backend->res[tile_no];
+          }
         }
-      free (((CtxHasher*)(hasher->backend))->hashes);
-      ctx_free (hasher);
 
 
-      if (dirty_tiles)
+      int in_low_res = 0;
+      int old_flags = cb_backend->flags;
+      if (cb_backend->flags & CTX_FLAG_LOWFI)
       {
-         int x0 = cb_backend->min_col * (ctx_width (ctx)/CTX_HASH_COLS);
-         int x1 = (cb_backend->max_col+1) * (ctx_width (ctx)/CTX_HASH_COLS)-1;
-         int y0 = cb_backend->min_row * (ctx_height (ctx)/CTX_HASH_ROWS);
-         int y1 = (cb_backend->max_row+1) * (ctx_height (ctx)/CTX_HASH_ROWS)-1;
+        in_low_res = 1; // default to assume we're in low res
+        if (dirty_tiles == 0 && low_res_tiles !=0) // no dirty and got low_res_tiles
+        {
+            cb_backend->max_col = -100;
+            cb_backend->min_col = 100;
+            cb_backend->max_row = -100;
+            cb_backend->min_row = 100;
+            tile_no = 0;
+            for (int row = 0; row < CTX_HASH_ROWS; row++)
+              for (int col = 0; col < CTX_HASH_COLS; col++, tile_no++)
+              {
+                if (cb_backend->res[tile_no])
+              {
+                cb_backend->max_col = ctx_maxi (cb_backend->max_col, col);
+                cb_backend->max_row = ctx_maxi (cb_backend->max_row, row);
+                cb_backend->min_col = ctx_mini (cb_backend->min_col, col);
+                cb_backend->min_row = ctx_mini (cb_backend->min_row, row);
+                dirty_tiles++;
+              }
+              }
 
-         if (cb_backend->flags & CTX_CB_DAMAGE_CONTROL)
+            active_mask = 0;
+            for (int row = cb_backend->min_row; row <= cb_backend->max_row; row++)
+            for (int col = cb_backend->min_col; col <= cb_backend->max_col; col++)
+            {
+              tile_no = row * CTX_HASH_COLS + col;
+              int tile_no = 0;
+              active_mask |= (1<<tile_no);
+            }
+            if ((cb_backend->flags & CTX_FLAG_STAY_LOW) == 0)
+              cb_backend->flags &= ~CTX_FLAG_LOWFI;
+            in_low_res = 0;
+        }
+        else if (dirty_tiles)
+        {
+            int memory = (cb_backend->max_col-cb_backend->min_col+1)*
+                          (cb_backend->max_row-cb_backend->min_row+1)*tile_dim;
+            if (memory < cb_backend->memory_budget && 0)
+            {
+              in_low_res = 0;
+              if ((cb_backend->flags & CTX_FLAG_STAY_LOW) == 0)
+                cb_backend->flags &= ~CTX_FLAG_LOWFI;
+            }
+        }
+      }
+
+      ctx_pop_backend (ctx); // done with hasher
+      if (dirty_tiles)
+      {
+         int x0 = cb_backend->min_col     * tile_width;
+         int y0 = cb_backend->min_row     * tile_height;
+         int x1 = (cb_backend->max_col+1) * tile_width - 1;
+         int y1 = (cb_backend->max_row+1) * tile_height - 1;
+#if 0
+         if (cb_backend->flags & CTX_FLAG_DAMAGE_CONTROL)
          {
-#if 1
-         ctx_save (ctx);
-         ctx_rectangle (ctx, x0, y0, x1-x0+1, y1-y0+1);
-         ctx_rgba (ctx, 1,0,0,0.5);
-         ctx_line_width (ctx, 4.0);
-         ctx_stroke (ctx);
-         ctx_restore (ctx);
-#endif
+           ctx_save (ctx);
+           ctx_rectangle (ctx, x0, y0, x1-x0+1, y1-y0+1);
+           ctx_rgba (ctx, 1,0,0,0.5);
+           ctx_line_width (ctx, 4.0);
+           ctx_stroke (ctx);
+           ctx_restore (ctx);
          }
-#if 0
-         //ctx_move_to (ctx, (x0+x1)/2, (y0+y1)/2);
-         //char buf[44];
-         //sprintf (buf, "%ix%i", ctx_width(ctx), ctx_height(ctx));
-         //ctx_text (ctx, buf);
-
-         //ctx_rgba (ctx, 0,1,0,0.5);
-         //ctx_rectangle (ctx, 0, 0, ctx_width(ctx)/2, ctx_height(ctx)/2);
-         //ctx_fill (ctx);
-#endif
-         int width = x1 - x0 + 1;
-         int height = y1 - y0 + 1;
-         if ( (cb_backend->flags & CTX_CB_AUTO_332) &&
-              ((width) * height * 2 > cb_backend->memory_budget))
+#endif
+
+         //int width = x1 - x0 + 1;
+         //int height = y1 - y0 + 1;
+         int abort = 0;
+         int abortable = 1;
+
+         if (dirty_tiles <= 4 && low_res_tiles <= 4)
          {
-           cb_backend->flags |= CTX_CB_332;
-           ctx_render_cb (ctx, x0, y0, x1, y1);
-           cb_backend->flags -= CTX_CB_332;
+           in_low_res = 0;
+           abortable = 0;
          }
-         else
+
+         if (in_low_res)
          {
-           ctx_render_cb (ctx, x0, y0, x1, y1);
+             abort = ctx_render_cb (cb_backend, x0, y0, x1, y1, active_mask);
+             for (int row = cb_backend->min_row; row <= cb_backend->max_row; row++)
+               for (int col = cb_backend->min_col; col <= cb_backend->max_col; col++)
+               {
+                 int tile_no = row * CTX_HASH_COLS + col;
+                 //if (abort)
+                 //{
+                   //cb_backend->res[tile_no]=0;
+                   //cb_backend->hashes[tile_no]= 23;
+                 //}
+                 //else
+                 {
+                   cb_backend->hashes[tile_no]= hashes[tile_no];
+                   cb_backend->res[tile_no]=in_low_res;
+                 }
+               }
          }
-      }
+         else // full res
+         {
+           tile_no = 0;
+
+           for (int row = 0; row < CTX_HASH_ROWS; row++)
+           {
+             for (int col = 0; col < CTX_HASH_COLS; col++)
+               if (!abort)
+             {
+               tile_no = row * CTX_HASH_COLS + col;
+               active_mask = 1<<tile_no;
+               uint32_t new_hash = hashes[tile_no];
+               int used_tiles = 1;
+
+               if ((new_hash != cb_backend->hashes[tile_no]) ||
+                   cb_backend->res[tile_no])
+               {
+                    int x0 = col * tile_width;
+                    int y0 = row * tile_height;
+                    int x1 = x0 +  tile_width-1;
+                    int y1 = y0 +  tile_height-1;
+
+#if 1
+             int max_tiles = (cb_backend->memory_budget / tile_dim);
+                    int cont = 1;
+                    /* merge horizontal adjecant dirty tiles */
+                    if (used_tiles < max_tiles && col + 1 < CTX_HASH_COLS) do {
+                      uint32_t next_new_hash = hashes[tile_no+used_tiles];
+                      if ((next_new_hash != cb_backend->hashes[tile_no+used_tiles]) ||
+                        cb_backend->res[tile_no+used_tiles])
+                      {
+                        active_mask |= (1 << (tile_no+used_tiles));
+                        used_tiles ++;
+                        x1 += (ctx_width (ctx)/CTX_HASH_COLS);
+                      }
+                      else
+                      {
+                        cont = 0;
+                      }
+                    } while (used_tiles < max_tiles && cont && col + used_tiles < CTX_HASH_COLS);
+#endif
+
+
+                    abort = ctx_render_cb (cb_backend, x0, y0, x1, y1, active_mask);
+                    {
+                      for (int i = 0; i < used_tiles; i ++)
+                      {
+                        cb_backend->res[tile_no + i]=0;
+                        cb_backend->hashes[tile_no + i] = hashes[tile_no+i];
+                      }
+                    }
+                    if (!abortable)
+                       abort = 0;
+                    col += used_tiles - 1;
+                  }
+               }
+           }
+             }
+           }
+      cb_backend->flags = old_flags;
   }
   else
   {
-    ctx_render_cb (ctx, 0, 0, ctx_width(ctx)-1, ctx_height(ctx)-1);
+    ctx_render_cb (cb_backend, 0, 0, ctx_width(ctx)-1, ctx_height(ctx)-1, 0);
   }
   if (cb_backend->update_fb)
-    cb_backend->update_fb (ctx, cb_backend->user_data);
+    cb_backend->update_fb (ctx, cb_backend->update_fb_user_data);
 }
 
 Ctx *ctx_new_cb (int width, int height, CtxPixelFormat format,
                  void (*set_pixels) (Ctx *ctx, void *user_data, 
-                                     int x, int y, int w, int h, void *buf),
-                 void (*update_fb) (Ctx *ctx, void *user_data),
-                 void *user_data,
+                                     int x, int y, int w, int h, void *buf,
+                                     int buf_size),
+                 void *set_pixels_user_data,
+                 int (*update_fb) (Ctx *ctx, void *user_data),
+                 void *update_fb_user_data,
                  int   memory_budget,
                  void *scratch_fb,
                  int   flags)
 {
   Ctx *ctx                   = ctx_new_drawlist (width, height);
-  CtxBackend    *backend     = (CtxBackend*)calloc (sizeof (CtxCbBackend), 1);
+  CtxBackend    *backend     = (CtxBackend*)ctx_calloc (sizeof (CtxCbBackend), 1);
   CtxCbBackend  *cb_backend  = (CtxCbBackend*)backend;
-  backend->flush             = ctx_cb_flush;
+  backend->end_frame         = ctx_cb_end_frame;
   cb_backend->format         = format;
   cb_backend->fb             = (uint16_t*)scratch_fb;
-  cb_backend->flags          = flags;
   cb_backend->set_pixels     = set_pixels;
   cb_backend->update_fb      = update_fb;
-  cb_backend->user_data      = user_data;
+  cb_backend->set_pixels_user_data = set_pixels_user_data;
+  cb_backend->update_fb_user_data   = update_fb_user_data;
   cb_backend->memory_budget  = memory_budget;
   ctx_set_backend (ctx, backend);
+  ctx_cb_set_flags (ctx, flags);
+  cb_backend->ctx = ctx;
+  if (!scratch_fb)
+  {
+    cb_backend->memory_budget = 0;
+    ctx_cb_set_memory_budget (ctx, memory_budget);
+  }
+#if CTX_EVENTS
+  ctx_get_event (ctx);
+#endif
   return ctx;
 }
 
 #if CTX_TFT_ESPI
 
-static void ctx_tft_set_pixels (Ctx *ctx, void *user_data, int x, int y, int w, int h, void *buf)
+static void ctx_tft_set_pixels (Ctx *ctx, void *user_data, int x, int y, int w, int h, void *buf, int 
buf_size)
 {
   TFT_eSPI *tft = (TFT_eSPI*)user_data;
   tft->pushRect (x, y, w, h, (uint16_t*)buf);
@@ -36857,13 +40247,13 @@ Ctx *ctx_new_tft (TFT_eSPI *tft,
   return ctx_new_cb (tft->width(), tft->height(), 
                      CTX_FORMAT_RGB565_BYTESWAPPED,
                      ctx_tft_set_pixels,
-                     NULL,
                      tft,
+                     NULL,
+                     NULL,
                      memory_budget,
                      scratch_fb,
                      flags);
 }
-
 #endif
 
 #ifdef EMSCRIPTEN
@@ -36871,7 +40261,6 @@ Ctx *ctx_new_tft (TFT_eSPI *tft,
 
 #include <unistd.h>
 
-
 int width = 512;
 int height = 384;
 
@@ -36883,127 +40272,203 @@ get_fb(int w, int h) {
   if (fb)
   {
     if (width == w && height == h) return fb;
-    free (fb);
+    free (fb); // this is not using the ctx allocator
+               // and will thus not be part of the micropython heap budget
     fb = NULL;
   }
   width  = w;
   height = h;
   fb = calloc (w *h, 4);
-  if (em_ctx) free (em_ctx);
+  if (em_ctx) ctx_destroy (em_ctx);
   em_ctx = NULL;
   return fb;
 }
 
-void  update_fb (Ctx *ctx, void *user_data)
+EMSCRIPTEN_KEEPALIVE
+float pointer_x = 0;
+EMSCRIPTEN_KEEPALIVE
+float pointer_y = 0;
+EMSCRIPTEN_KEEPALIVE
+int32_t pointer_down = 0;
+int32_t pointer_was_down = 0;
+
+
+static uint32_t key_queue[32];
+static int key_queue_head = 0; // read head
+static int key_queued = 0;
+
+EMSCRIPTEN_KEEPALIVE
+void ctx_wasm_queue_key_event (int type, int keycode)
+{
+  if (key_queued >= 31) return;
+  int pos = (key_queue_head + key_queued) % 32;
+  key_queue[pos * 2 + 0] = type;
+  key_queue[pos * 2 + 1] = keycode;
+  key_queued ++;
+}
+
+int ctx_wasm_get_key_event (int *type, int *keycode)
+{
+  if (!key_queued)
+    return -1;
+
+  *type = key_queue[key_queue_head * 2 + 0];
+  *keycode = key_queue[key_queue_head * 2 + 1];
+
+  key_queued--;
+  key_queue_head++;
+  key_queue_head = key_queue_head % 16;
+
+  return 0;
+}
+
+int update_fb (Ctx *ctx, void *user_data)
 {
   EM_ASM(
     var canvas = document.getElementById('c');
     var context = canvas.getContext('2d');
-    const offset = _get_fb(canvas.width, canvas.height);
-    var _ctx = _get_context();
-    const imgData = context.createImageData(canvas.width,canvas.height);
-                  //console.log(offset);
-    var x0 = _ctx_cb_x0 (_ctx);
-    var y0 = _ctx_cb_y0 (_ctx);
-    var x1 = _ctx_cb_x1 (_ctx);
-    var y1 = _ctx_cb_y1 (_ctx);
-
-    var updatew = x1 - x0 + 1;
-    var updateh = y1 - y0 + 1;
-    const linearMem = new Uint8Array(wasmMemory.buffer, offset,
-                          canvas.width * canvas.height * 4);
-
-    for (let y = y0; y < y1; y++)
-    {
-      let dsto = y * canvas.width * 4 + x0;
-      let srco = y * updatew * 4;
-      for (let x = x0; x < x1; x++)
-      {
-        var a = linearMem[srco+3];
-        var r = 1.0;
-        if (a!=0) r = 255.0/a;
-        imgData.data[dsto+0] = linearMem[srco+0] * r;
-        imgData.data[dsto+1] = linearMem[srco+1] * r;
-        imgData.data[dsto+2] = linearMem[srco+2] * r;
-        imgData.data[dsto+3] = a;
-        srco+=4;
-        dsto+=4;
-      }
-    }
-
-    for (let i = 0; i < canvas.width * canvas.height;i++)
-    {
-      var a = linearMem[i*4+3];
-      var r = 1.0;
-      // if (a!=0) r = 255.0/a;
-      imgData.data[i*4+0] = linearMem[i*4+0] * r;
-      imgData.data[i*4+1] = linearMem[i*4+1] * r;
-      imgData.data[i*4+2] = linearMem[i*4+2] * r;
-      imgData.data[i*4+3] = 255;
-    }
-    context.putImageData(imgData,0,0);
-
 
      if (!canvas.regevents)
      {
-
-       canvas.addEventListener('mousedown', function (e){
+       canvas.onmousedown = function (e){
           var loc = windowToCanvas (canvas, e.clientX, e.clientY);
-          _ctx_pointer_press (_ctx, loc.x, loc.y, 0, 0);
-                       }
-       );
-       canvas.addEventListener('mouseup', function (e){
+          setValue(_pointer_x, loc.x, "float");
+          setValue(_pointer_y, loc.y, "float");
+          setValue(_pointer_down, 1, "i32");
+          e.stopPropagate=1;
+                       };
+       canvas.onmouseup = function (e){
           var loc = windowToCanvas (canvas, e.clientX, e.clientY);
-          _ctx_pointer_release (_ctx, loc.x, loc.y, 0, 0);
-                       });
-       canvas.addEventListener('mousemove', function (e){
+          setValue(_pointer_x, loc.x, "float");
+          setValue(_pointer_y, loc.y, "float");
+          setValue(_pointer_down, 0, "i32");
+          e.stopPropagate=1;
+                       };
+       canvas.onmousemove = function (e){
           var loc = windowToCanvas (canvas, e.clientX, e.clientY);
-          _ctx_pointer_motion (_ctx, loc.x, loc.y, 0, 0);
-                       });
-       canvas.addEventListener('keydown', function (e){
-                       _ctx_key_down(_ctx,e.keyCode,0,0);
-                       _ctx_key_press(_ctx,e.keyCode,0,0);
-                       // XXX : todo, pass some tings like ctrl+l and ctrl+r
-                       //       through?
+          setValue(_pointer_x, loc.x, "float");
+          setValue(_pointer_y, loc.y, "float");
+          e.stopPropagate=1;
+                       };
+       canvas.onkeydown = function (e){
+          _ctx_wasm_queue_key_event (1, e.keyCode);
                        e.preventDefault();
                        e.stopPropagate = 1;
-                       });
+                       };
 
-       canvas.addEventListener('keyup', function (e){
-                       _ctx_key_up(_ctx,e.keyCode,0,0);
+       canvas.onkeyup = function (e){
+          _ctx_wasm_queue_key_event (2, e.keyCode);
                        e.preventDefault();
                        e.stopPropagate = 1;
-                       });
+                       };
        canvas.regevents = true;
      }
-
-
   );
 
-   
-
 #ifdef EMSCRIPTEN
 #ifdef ASYNCIFY
    emscripten_sleep(0);
 #endif
 #endif
+
+   int ret = 0;
+
+   if (key_queued)
+     while (key_queued)
+   {
+     int type = 0 , keycode = 0;
+
+     ctx_wasm_get_key_event (&type, &keycode);
+     switch (type)
+     {
+       case 1:
+         ctx_key_down(ctx,keycode,NULL,0);
+         ctx_key_press(ctx,keycode,NULL,0);
+         ret = 1;
+         break;
+       case 2:
+         ctx_key_up(ctx,keycode,NULL,0);
+         ret = 1;
+         break;
+     }
+   }
+
+   if (pointer_down && !pointer_was_down)
+   {
+      ctx_pointer_press (ctx, pointer_x, pointer_y, 0, 0);
+      ret = 1;
+   } else if (!pointer_down && pointer_was_down)
+   {
+      ctx_pointer_release (ctx, pointer_x, pointer_y, 0, 0);
+      ret = 1;
+   } else if (pointer_down)
+   {
+      ctx_pointer_motion (ctx, pointer_x, pointer_y, 0, 0);
+      ret = 1;
+   }
+
+   pointer_was_down = pointer_down;
+
+   return ret;
 }
 
-static void set_pixels (Ctx *ctx, void *user_data, int x0, int y0, int w, int h, void *buf)
+EMSCRIPTEN_KEEPALIVE
+uint8_t wasm_scratch[1024*1024*4];
+
+static void set_pixels (Ctx *ctx, void *user_data, int x0, int y0, int w, int h, void *buf, int buf_size)
 {
-  //TFT_eSPI *tft = (TFT_eSPI*)user_data;
-  //tft->pushRect (x, y, w, h, (uint16_t*)buf);
-  int stride = ctx_width (ctx) * 4;
   uint8_t *src = (uint8_t*)buf;
-  uint8_t *dst = fb + y0 * stride + x0 * 4;
-  for (int y = y0; y < y0 + h; y++)
+  int in_w = w;
+  if (x0 < 0) x0 = 0;
+  if (y0 < 0) y0 = 0;
+  if (x0 + w > ctx_width (ctx))
+  {
+     fprintf (stderr, "adjusting xbounds from %i %i\n", x0, w);
+     w = ctx_width (ctx) - x0;
+  }
+  if (y0 + h > ctx_height (ctx))
   {
-    memcpy (dst, src, w * 4);
-    dst += stride;
-    src += w * 4;
+     h = ctx_height (ctx) - y0;
+     fprintf (stderr, "adjusting ybounds\n");
   }
+  for (int i = 0; i < h; i++)
+  {
+    ctx_RGB565_BS_to_RGBA8 (NULL, x0, src + i * in_w * 2,
+                    wasm_scratch + i * w * 4, w);
+  }
+
+  EM_ASM(
+    var x0 = $0;
+    var y0 = $1;
+    var w = $2;
+    var h = $3;
+    var canvas = document.getElementById('c');
+    var context = canvas.getContext('2d');
+    var _ctx = _ctx_wasm_get_context(0); // we presume an earlier
+                                         // call to have passed
+                                         // the memory budget
+    const offset = _get_fb(canvas.width, canvas.height);
+    const imgData = context.createImageData(w,h);
+
+    const linearMem = new Uint8Array(wasmMemory.buffer, _wasm_scratch,
+                                     w*h*4);
+
+    for (let i = 0; i < w * h;i++)
+    {
+      //var a = linearMem[i*4+3];
+      //var r = 1.0;
+      //if (a!=0) r = 255.0/a;
+      imgData.data[i*4+0] = linearMem[i*4+0];// * r;
+      imgData.data[i*4+1] = linearMem[i*4+1];// * r;
+      imgData.data[i*4+2] = linearMem[i*4+2];// * r;
+      imgData.data[i*4+3] = 255;
+    }
+    context.putImageData(imgData,x0,y0);
+  , x0,y0, w, h);
+
 }
 
+#if 0
 int wasm_damage_control = 0;
 
 CTX_EXPORT
@@ -37011,50 +40476,85 @@ void wasm_set_damage_control(int val)
 {
   wasm_damage_control = val;
 }
+#endif
 
+void ctx_wasm_reset (void)
+{
+  if (fb) free (fb); fb = NULL;
+  em_ctx = NULL;
+}
 
-Ctx *get_context (void)
+Ctx *ctx_wasm_get_context (int memory_budget)
 {
 
+
 EM_ASM(
     {var canvas = document.getElementById('c');
      const offset = _get_fb(canvas.width, canvas.height);
 
-     var dc = document.getElementById('damagecontrol');
-     if (dc)
-     {
-       _wasm_set_damage_control(dc.checked?1:0);
-     }
+     //var dc = document.getElementById('damagecontrol');
+     //if (dc)
+     //{
+     //  _wasm_set_damage_control(dc.checked?1:0);
+     //}
    }
 );
 
-   if (!em_ctx){em_ctx = ctx_new_cb (width, height, CTX_FORMAT_RGBA8, set_pixels, 
-                               update_fb,
-                               fb,
-                               width * height * 4, NULL, 
-                               CTX_CB_DEFAULTS|CTX_CB_HASH_CACHE);
+   if (em_ctx && memory_budget)
+   {
+      CtxCbBackend *cb_backend = (CtxCbBackend*)em_ctx->backend;
+      if (memory_budget != cb_backend->memory_budget)
+      {
+         ctx_cb_set_memory_budget (em_ctx, memory_budget);
+         ctx_cb_set_flags (em_ctx, 0);
+      }
+   }
+
+
+
+   if (!em_ctx){
+      em_ctx = ctx_new_cb (width, height, CTX_FORMAT_RGB565_BYTESWAPPED,
+                           set_pixels, 
+                           NULL,
+                           update_fb,
+                           NULL,
+                           memory_budget, NULL, 
+                           0);
    }
 
+#if 0
    if (wasm_damage_control)
    {
      int flags = ctx_cb_get_flags (em_ctx);
-     flags |= CTX_CB_DAMAGE_CONTROL;
+     flags |= CTX_FLAG_DAMAGE_CONTROL;
      ctx_cb_set_flags (em_ctx, flags);
    }
    else
    {
      int flags = ctx_cb_get_flags (em_ctx);
-     flags &= ~CTX_CB_DAMAGE_CONTROL;
+     flags &= ~CTX_FLAG_DAMAGE_CONTROL;
      ctx_cb_set_flags (em_ctx, flags);
    }
+#endif
    return em_ctx;
 }
 
 #endif
 
-static CtxFont ctx_fonts[CTX_MAX_FONTS];
+static CtxFont ctx_fonts[CTX_MAX_FONTS];// = NULL;
 static int     ctx_font_count = 0;
 
+static void ctx_font_setup (Ctx *ctx);
+
+static inline int ctx_font_is_monospaced (CtxFont *font)
+{
+#if CTX_ONE_FONT_ENGINE
+  return 0; // XXX
+#else
+  return font->monospaced;
+#endif
+}
+
 #if CTX_FONT_ENGINE_STB
 static float
 ctx_glyph_width_stb (CtxFont *font, Ctx *ctx, uint32_t unichar);
@@ -37074,20 +40574,50 @@ CtxFontEngine ctx_font_engine_stb =
   ctx_glyph_kern_stb,
 };
 
+
 int
 ctx_load_font_ttf (const char *name, const void *ttf_contents, int length)
 {
+  char buf[256];
+  ctx_font_setup (NULL);
   if (ctx_font_count >= CTX_MAX_FONTS)
     { return -1; }
-  ctx_fonts[ctx_font_count].type = 1;
-  ctx_fonts[ctx_font_count].name = (char *) malloc (strlen (name) + 1);
-  ctx_strcpy ( (char *) ctx_fonts[ctx_font_count].name, name);
+
   if (!stbtt_InitFont (&ctx_fonts[ctx_font_count].stb.ttf_info, ttf_contents, 0) )
     {
       ctx_log ( "Font init failed\n");
       return -1;
     }
+
+  if (name == NULL || !strcmp (name, "import")){
+  int length = 0;
+  const char *val = stbtt_GetFontNameDefault (&ctx_fonts[ctx_font_count].stb.ttf_info,
+                          &length);
+  if (val)
+  {
+    memset(buf,0,sizeof(buf));
+    memcpy(buf,val, length);
+    name = buf;
+  }
+  else
+    name = "import";
+  }
+
+  ctx_fonts[ctx_font_count].type = 1;
+  ctx_fonts[ctx_font_count].stb.name = (char *) ctx_malloc (ctx_strlen (name) + 1);
+  ctx_strcpy ( (char *) ctx_fonts[ctx_font_count].stb.name, name);
+
   ctx_fonts[ctx_font_count].engine = &ctx_font_engine_stb;
+
+  CtxFont *font = &ctx_fonts[ctx_font_count];
+  if (font->engine->glyph_width (font, NULL, 'O') ==
+      font->engine->glyph_width (font, NULL, 'I'))
+  {
+    font->monospaced = 1;
+  }
+  else
+    font->monospaced = 0;
+
   ctx_font_count ++;
   return ctx_font_count-1;
 }
@@ -37096,6 +40626,7 @@ ctx_load_font_ttf (const char *name, const void *ttf_contents, int length)
 int
 ctx_load_font_ttf_file (const char *name, const char *path)
 {
+  ctx_font_setup (NULL);
   uint8_t *contents = NULL;
   long length = 0;
   ctx_get_contents (path, &contents, &length);
@@ -37109,17 +40640,32 @@ ctx_load_font_ttf_file (const char *name, const char *path)
 #endif
 
 static int
-ctx_glyph_stb_find (CtxFont *font, uint32_t unichar)
+ctx_glyph_stb_find (Ctx *ctx, CtxFont *font, uint32_t unichar)
 {
   stbtt_fontinfo *ttf_info = &font->stb.ttf_info;
-  int index = font->stb.cache_index;
-  if (font->stb.cache_unichar == unichar)
-    {
-      return index;
-    }
-  font->stb.cache_unichar = 0;
-  index = font->stb.cache_index = stbtt_FindGlyphIndex (ttf_info, unichar);
-  font->stb.cache_unichar = unichar;
+
+#if CTX_GLYPH_CACHE
+  uint32_t hash = ((((size_t)(font) * 23) ^ unichar) * 17) %
+            (CTX_GLYPH_CACHE_SIZE);
+  if (ctx)
+  {
+    if (ctx->glyph_index_cache[hash].font == font &&
+        ctx->glyph_index_cache[hash].unichar == unichar)
+          return ctx->glyph_index_cache[hash].offset;
+  }
+#endif
+
+  int index = stbtt_FindGlyphIndex (ttf_info, unichar);
+
+#if CTX_GLYPH_CACHE
+  if (ctx)
+  {
+    ctx->glyph_index_cache[hash].font    = font;
+    ctx->glyph_index_cache[hash].unichar = unichar;
+    ctx->glyph_index_cache[hash].offset  = index;
+  }
+#endif
+
   return index;
 }
 
@@ -37127,13 +40673,15 @@ static float
 ctx_glyph_width_stb (CtxFont *font, Ctx *ctx, uint32_t unichar)
 {
   stbtt_fontinfo *ttf_info = &font->stb.ttf_info;
-  float font_size          = ctx->state.gstate.font_size;
+  float font_size          = 1.0f;
+  if (ctx)
+      font_size = ctx->state.gstate.font_size;
   float scale              = stbtt_ScaleForPixelHeight (ttf_info, font_size);
   int advance, lsb;
-  int glyph = ctx_glyph_stb_find (font, unichar);
+  int glyph = ctx_glyph_stb_find (ctx, font, unichar);
 
 #if CTX_EVENTS
-  if (ctx_backend_type (ctx) == CTX_BACKEND_TERM && ctx_fabsf(3.0 - font_size) < 0.03)
+  if (ctx && ctx_backend_type (ctx) == CTX_BACKEND_TERM && ctx_fabsf(3.0f - font_size) < 0.03f)
     return 2;
 #endif
 
@@ -37149,8 +40697,8 @@ ctx_glyph_kern_stb (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unichar
   stbtt_fontinfo *ttf_info = &font->stb.ttf_info;
   float font_size = ctx->state.gstate.font_size;
   float scale = stbtt_ScaleForPixelHeight (ttf_info, font_size);
-  int glyphA = ctx_glyph_stb_find (font, unicharA);
-  int glyphB = ctx_glyph_stb_find (font, unicharB);
+  int glyphA = ctx_glyph_stb_find (ctx, font, unicharA);
+  int glyphB = ctx_glyph_stb_find (ctx, font, unicharB);
   return stbtt_GetGlyphKernAdvance (ttf_info, glyphA, glyphB) * scale;
 }
 
@@ -37158,7 +40706,7 @@ static int
 ctx_glyph_stb (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke)
 {
   stbtt_fontinfo *ttf_info = &font->stb.ttf_info;
-  int glyph = ctx_glyph_stb_find (font, unichar);
+  int glyph = ctx_glyph_stb_find (ctx, font, unichar);
   if (glyph==0)
     { return -1; }
   float font_size = ctx->state.gstate.font_size;
@@ -37206,62 +40754,108 @@ ctx_glyph_stb (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke)
 }
 #endif
 
-#if CTX_FONT_ENGINE_CTX
-
-static int ctx_font_find_glyph_cached (CtxFont *font, uint32_t glyph)
+static inline int ctx_font_get_length (CtxFont *font)
 {
-#if 1
-  int min       = 0;
-  int max       = font->ctx.glyphs-1;
-  uint32_t found;
-
-  do {
-    int pos = (min + max)/2;
-    found = font->ctx.index[pos*2];
-    if (found == glyph)
-    {
-      return font->ctx.index[pos*2+1];
-    } else if (min == max)
-      return -1;
-    else if (min == max-1)
-      return -1;
-    else if (found < glyph)
-    {
-      min = pos;
-    } else {
-      max = pos;
-    }
+   return font->ctx.data->data.u32[1];
+}
 
-  } while (min != max);
+#if CTX_FONT_ENGINE_CTX
 
-  return -1;
-#else
-  for (int i = 0; i < font->ctx.glyphs; i++)
+static inline uint32_t
+ctx_glyph_find_next (CtxFont *font, Ctx *ctx, int offset)
+{
+  int length = ctx_font_get_length (font);
+  for (int i = offset; i < length; i++)
+  {
+    CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
+    if (entry->code == CTX_DEFINE_GLYPH)
     {
-      if (font->ctx.index[i * 2] == glyph)
-        { return font->ctx.index[i * 2 + 1]; }
+      return entry->data.u32[0];
     }
-  return -1;
-#endif
+  }
+  return 0;
 }
 
 static int ctx_glyph_find_ctx (CtxFont *font, Ctx *ctx, uint32_t unichar)
 {
-  int ret = ctx_font_find_glyph_cached (font, unichar);
-  if (ret >= 0) return ret;
-
-  for (int i = 0; i < font->ctx.length; i++)
+#if CTX_GLYPH_CACHE
+  uint32_t hash = ((((size_t)(font) * 23) ^ unichar) * 17) %
+            (CTX_GLYPH_CACHE_SIZE);
+  if (ctx)
+  {
+    if (ctx->glyph_index_cache[hash].font == font &&
+        ctx->glyph_index_cache[hash].unichar == unichar)
+          return ctx->glyph_index_cache[hash].offset;
+  }
+#endif
+#if 1
+  int length = ctx_font_get_length (font);
+  for (int i = 0; i < length; i++)
   {
     CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
     if (entry->code == CTX_DEFINE_GLYPH &&
         entry->data.u32[0] == unichar)
     {
+#if CTX_GLYPH_CACHE
+       if (ctx)
+       {
+         ctx->glyph_index_cache[hash].font    = font;
+         ctx->glyph_index_cache[hash].unichar = unichar;
+         ctx->glyph_index_cache[hash].offset  = i;
+       }
+#endif
        return i;
        // XXX this could be prone to insertion of valid header
        // data in included bitmaps.. is that an issue?
        //   
     }
   }
+#else
+  int start = 0;
+  int end = ctx_font_get_length (font);
+  int max_iter = 10;
+    uint32_t start_glyph = ctx_glyph_find_next (font, ctx, start);
+    if (unichar  == start_glyph)
+    {
+#if CTX_GLYPH_CACHE
+       if (ctx)
+       {
+         ctx->glyph_index_cache[hash].font    = font;
+         ctx->glyph_index_cache[hash].unichar = unichar;
+         ctx->glyph_index_cache[hash].offset  = start;
+       }
+#endif
+       return start;
+    }
+
+  do {
+    int middle = (start + end) / 2;
+
+    uint32_t middle_glyph = ctx_glyph_find_next (font, ctx, middle);
+    if (unichar  == middle_glyph)
+    {
+#if CTX_GLYPH_CACHE
+       if (ctx)
+       {
+         ctx->glyph_index_cache[hash].font    = font;
+         ctx->glyph_index_cache[hash].unichar = unichar;
+         ctx->glyph_index_cache[hash].offset  = middle;
+       }
+#endif
+       return middle;
+    }
+    else if (unichar < middle_glyph)
+    {
+       end = middle;
+    } else
+    {
+       start = middle;
+    }
+
+    if (start == end)
+      return -1;
+  } while (max_iter -- > 0);
+#endif
   return -1;
 }
 
@@ -37274,59 +40868,52 @@ ctx_glyph_kern_ctx (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unichar
   if (first_kern < 0) return 0.0;
 
 #if CTX_EVENTS
-  if (ctx_backend_type (ctx) == CTX_BACKEND_TERM && ctx_fabsf(3.0f - font_size) < 0.03)
+  if (ctx_backend_type (ctx) == CTX_BACKEND_TERM && ctx_fabsf(3.0f - font_size) < 0.03f)
     return 0.0f;
 #endif
 
-  for (int i = first_kern + 1; i < font->ctx.length; i++)
+  int length = ctx_font_get_length (font);
+  for (int i = first_kern + 1; i < length; i++)
     {
       CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
       if (entry->code == CTX_KERNING_PAIR)
         {
           if (entry->data.u16[0] == unicharA && entry->data.u16[1] == unicharB)
-            { return entry->data.s32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE; }
+            { return entry->data.s32[1] / 255.0f * font_size / CTX_BAKE_FONT_SIZE; }
         }
       if (entry->code == CTX_DEFINE_GLYPH)
         return 0.0;
     }
   return 0.0;
 }
-#if 0
-static int ctx_glyph_find (Ctx *ctx, CtxFont *font, uint32_t unichar)
-{
-  for (int i = 0; i < font->ctx.length; i++)
-    {
-      CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
-      if (entry->code == CTX_DEFINE_GLYPH && entry->data.u32[0] == unichar)
-        { return i; }
-    }
-  return 0;
-}
-#endif
-
 
 static float
 ctx_glyph_width_ctx (CtxFont *font, Ctx *ctx, uint32_t unichar)
 {
-  CtxState *state = &ctx->state;
-  float font_size = state->gstate.font_size;
+  float font_size = 1.0f;
+  if (ctx)
+  {
+    CtxState *state = &ctx->state;
+    font_size = state->gstate.font_size;
+  }
   int   start     = ctx_glyph_find_ctx (font, ctx, unichar);
   if (start < 0)
     { return 0.0; }  // XXX : fallback
 
 #if CTX_EVENTS
-  if (ctx_backend_type (ctx) == CTX_BACKEND_TERM && 
-                  ctx_fabsf(3.0 - font_size) < 0.03 
+  if (ctx && ctx_backend_type (ctx) == CTX_BACKEND_TERM && 
+                  ctx_fabsf(3.0f - font_size) < 0.03f 
                   )
     return 2.0f;
 #endif
 
-  for (int i = start; i < font->ctx.length; i++)
+  int length = ctx_font_get_length (font);
+  for (int i = start; i < length; i++)
     {
       CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
       if (entry->code == CTX_DEFINE_GLYPH)
         if (entry->data.u32[0] == (unsigned) unichar)
-          { return (entry->data.u32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE); }
+          { return (entry->data.u32[1] / 255.0f * font_size / CTX_BAKE_FONT_SIZE); }
     }
   return 0.0;
 }
@@ -37342,7 +40929,9 @@ ctx_glyph_drawlist (CtxFont *font, Ctx *ctx, CtxDrawlist *drawlist, uint32_t uni
   int in_glyph = 0;
   float font_size = state->gstate.font_size;
   int start = 0;
+#if CTX_ONE_FONT_ENGINE==0
   if (font->type == 0)
+#endif
   {
   start = ctx_glyph_find_ctx (font, ctx, unichar);
   if (start < 0)
@@ -37421,51 +41010,25 @@ ctx_glyph_ctx (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke)
 {
   CtxDrawlist drawlist;
   drawlist.entries = font->ctx.data;
-  drawlist.count = font->ctx.length;
-  drawlist.size  = font->ctx.length;
+  int length = ctx_font_get_length (font);
+  drawlist.count = length;
+  drawlist.size  = length;
   drawlist.flags = CTX_DRAWLIST_DOESNT_OWN_ENTRIES;
   return ctx_glyph_drawlist (font, ctx, &drawlist, unichar, stroke);
 }
 
-#if 1
+#if 0
 uint32_t ctx_glyph_no (Ctx *ctx, int no)
 {
   CtxFont *font = &ctx_fonts[ctx->state.gstate.font];
   if (no < 0 || no >= font->ctx.glyphs)
     { return 0; }
-  return font->ctx.index[no*2];
+  return font->ctx.index[no*2]; // needs index
 }
 #endif
 
 static void ctx_font_init_ctx (CtxFont *font)
 {
-  int glyph_count = 0;
-  for (int i = 0; i < font->ctx.length; i++)
-    {
-      CtxEntry *entry = &font->ctx.data[i];
-      if (entry->code == CTX_DEFINE_GLYPH)
-        { glyph_count ++; }
-    }
-  font->ctx.glyphs = glyph_count;
-#if CTX_DRAWLIST_STATIC
-  static uint32_t idx[512]; // one might have to adjust this for
-  // larger fonts XXX
-  // should probably be made a #define
-  font->ctx.index = &idx[0];
-#else
-  font->ctx.index = (uint32_t *) malloc (sizeof (uint32_t) * 2 * glyph_count);
-#endif
-  int no = 0;
-  for (int i = 0; i < font->ctx.length; i++)
-    {
-      CtxEntry *entry = &font->ctx.data[i];
-      if (entry->code == CTX_DEFINE_GLYPH)
-        {
-          font->ctx.index[no*2]   = entry->data.u32[0];
-          font->ctx.index[no*2+1] = i;
-          no++;
-        }
-    }
 }
 
 int
@@ -37475,6 +41038,7 @@ int
 ctx_load_font_ctx_file (const char *name, const char *path);
 #endif
 
+#if CTX_ONE_FONT_ENGINE==0
 static CtxFontEngine ctx_font_engine_ctx =
 {
 #if CTX_FONTS_FROM_FILE
@@ -37485,21 +41049,39 @@ static CtxFontEngine ctx_font_engine_ctx =
   ctx_glyph_width_ctx,
   ctx_glyph_kern_ctx,
 };
+#endif
 
 int
 ctx_load_font_ctx (const char *name, const void *data, int length)
 {
+  ctx_font_setup (NULL);
   if (length % sizeof (CtxEntry) )
     { return -1; }
   if (ctx_font_count >= CTX_MAX_FONTS)
     { return -1; }
+
+#if CTX_ONE_FONT_ENGINE==0
   ctx_fonts[ctx_font_count].type = 0;
-  ctx_fonts[ctx_font_count].name = name;
+  ctx_fonts[ctx_font_count].engine = &ctx_font_engine_ctx;
+#endif
+  //ctx_fonts[ctx_font_count].name = name;
   ctx_fonts[ctx_font_count].ctx.data = (CtxEntry *) data;
-  ctx_fonts[ctx_font_count].ctx.length = length / sizeof (CtxEntry);
+  //ctx_fonts[ctx_font_count].ctx.length = length / sizeof (CtxEntry);
   ctx_font_init_ctx (&ctx_fonts[ctx_font_count]);
-  ctx_fonts[ctx_font_count].engine = &ctx_font_engine_ctx;
+
   ctx_font_count++;
+
+#if CTX_ONE_FONT_ENGINE==0
+  CtxFont *font = &ctx_fonts[ctx_font_count-1];
+  if (font->engine->glyph_width (font, NULL, 'O') ==
+      font->engine->glyph_width (font, NULL, 'I'))
+  {
+    font->monospaced = 1;
+  }
+  else
+    font->monospaced = 0;
+#endif
+
   return ctx_font_count-1;
 }
 
@@ -37507,6 +41089,7 @@ ctx_load_font_ctx (const char *name, const void *data, int length)
 int
 ctx_load_font_ctx_file (const char *name, const char *path)
 {
+  ctx_font_setup (NULL);
   uint8_t *contents = NULL;
   long length = 0;
   ctx_get_contents (path, &contents, &length);
@@ -37535,7 +41118,7 @@ ctx_glyph_kern_ctx_fs (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unic
       if (entry->code == CTX_KERNING_PAIR)
         {
           if (entry->data.u16[0] == unicharA && entry->data.u16[1] == unicharB)
-            { return entry->data.s32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE; }
+            { return entry->data.s32[1] / 255.0f * font_size / CTX_BAKE_FONT_SIZE; }
         }
       if (entry->code == CTX_DEFINE_GLYPH)
         return 0.0;
@@ -37549,23 +41132,23 @@ ctx_glyph_width_ctx_fs (CtxFont *font, Ctx *ctx, uint32_t unichar)
 {
   CtxState *state = &ctx->state;
   char path[1024];
-  sprintf (path, "%s/%010p", font->ctx_fs.path, unichar);
+  sprintf (path, "%s/%010x", font->ctx_fs.path, (uint32_t)unichar);
   uint8_t *data = NULL;
   long int len_bytes = 0;
   ctx_get_contents (path, &data, &len_bytes);
   float ret = 0.0;
   float font_size = state->gstate.font_size;
   if (data){
-    Ctx *glyph_ctx = ctx_new ();
-    ctx_parse (glyph_ctx, data);
-    for (int i = 0; i < glyph_ctx->drawlist.count; i++)
+    Ctx *glyph_ctx = ctx_new_drawlist (100, 100);
+    ctx_parse (glyph_ctx, (char*)data);
+    for (uint32_t i = 0; i < glyph_ctx->drawlist.count; i++)
     {
       CtxEntry *e = &glyph_ctx->drawlist.entries[i];
       if (e->code == CTX_DEFINE_GLYPH)
-        ret = e->data.u32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE;
+        ret = e->data.u32[1] / 255.0f * font_size / CTX_BAKE_FONT_SIZE;
     }
-    free (data);
-    ctx_free (glyph_ctx);
+    ctx_free (data);
+    ctx_destroy (glyph_ctx);
   }
   return ret;
 }
@@ -37574,18 +41157,18 @@ static int
 ctx_glyph_ctx_fs (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke)
 {
   char path[1024];
-  sprintf (path, "file://%s/%010p", font->ctx_fs.path, unichar);
+  sprintf (path, "file://%s/%010x", font->ctx_fs.path, unichar);
   uint8_t *data = NULL;
   long int len_bytes = 0;
   ctx_get_contents (path, &data, &len_bytes);
 
   if (data){
-    Ctx *glyph_ctx = ctx_new ();
-    ctx_parse (glyph_ctx, data);
+    Ctx *glyph_ctx = ctx_new_drawlist (100, 100);
+    ctx_parse (glyph_ctx, (char*)data);
     int ret = ctx_glyph_drawlist (font, ctx, &(glyph_ctx->drawlist),
                                   unichar, stroke);
-    free (data);
-    ctx_free (glyph_ctx);
+    ctx_free (data);
+    ctx_destroy (glyph_ctx);
     return ret;
   }
   return -1;
@@ -37608,13 +41191,14 @@ static CtxFontEngine ctx_font_engine_ctx_fs =
 int
 ctx_load_font_ctx_fs (const char *name, const void *path, int length) // length is ignored
 {
+  ctx_font_setup (NULL);
   if (ctx_font_count >= CTX_MAX_FONTS)
     { return -1; }
 
-  ctx_fonts[ctx_font_count].type = 42;
-  ctx_fonts[ctx_font_count].name = name;
-  ctx_fonts[ctx_font_count].ctx_fs.path = strdup (path);
-  int path_len = strlen (path);
+  ctx_fonts[ctx_font_count].type = 3;
+  ctx_fonts[ctx_font_count].ctx_fs.name = strdup (name);
+  ctx_fonts[ctx_font_count].ctx_fs.path = ctx_strdup (path);
+  int path_len = ctx_strlen (path);
   if (ctx_fonts[ctx_font_count].ctx_fs.path[path_len-1] == '/')
    ctx_fonts[ctx_font_count].ctx_fs.path[path_len-1] = 0;
   ctx_fonts[ctx_font_count].engine = &ctx_font_engine_ctx_fs;
@@ -37629,7 +41213,12 @@ _ctx_glyph (Ctx *ctx, uint32_t unichar, int stroke)
 {
   CtxFont *font = &ctx_fonts[ctx->state.gstate.font];
   // a begin-path here did not remove stray spikes in terminal
+#if CTX_ONE_FONT_ENGINE
+  return ctx_glyph_ctx (font, ctx, unichar, stroke);
+#else
   return font->engine->glyph (font, ctx, unichar, stroke);
+#endif
+
 }
 
 int
@@ -37638,8 +41227,10 @@ ctx_glyph (Ctx *ctx, uint32_t unichar, int stroke)
 #if CTX_BACKEND_TEXT
   CtxEntry commands[3]; // 3 to silence incorrect warning from static analysis
   ctx_memset (commands, 0, sizeof (commands) );
+  if (stroke)
+    unichar = unichar | (1<<31);
   commands[0] = ctx_u32 (CTX_GLYPH, unichar, 0);
-  commands[0].data.u8[4] = stroke;
+  //commands[1].data.u8[4] = stroke;
   ctx_process (ctx, commands);
   return 0; // XXX is return value used?
 #else
@@ -37651,15 +41242,22 @@ float
 ctx_glyph_width (Ctx *ctx, int unichar)
 {
   CtxFont *font = &ctx_fonts[ctx->state.gstate.font];
-
+#if CTX_ONE_FONT_ENGINE
+  return ctx_glyph_width_ctx (font, ctx, unichar);
+#else
   return font->engine->glyph_width (font, ctx, unichar);
+#endif
 }
 
 static float
 ctx_glyph_kern (Ctx *ctx, int unicharA, int unicharB)
 {
   CtxFont *font = &ctx_fonts[ctx->state.gstate.font];
+#if CTX_ONE_FONT_ENGINE
+  return ctx_glyph_kern_ctx (font, ctx, unicharA, unicharB);
+#else
   return font->engine->glyph_kern (font, ctx, unicharA, unicharB);
+#endif
 }
 
 float
@@ -37692,15 +41290,76 @@ _ctx_glyphs (Ctx     *ctx,
     }
 }
 
+
+#define CTX_MAX_WORD_LEN 128
+
+#if 1
+static int ctx_glyph_find (Ctx *ctx, CtxFont *font, uint32_t unichar)
+{
+  int length = ctx_font_get_length (font);
+  for (int i = 0; i < length; i++)
+    {
+      CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
+      if (entry->code == CTX_DEFINE_GLYPH && entry->data.u32[0] == unichar)
+        { return i; }
+    }
+  return 0;
+}
+#endif
+
+static inline int
+_ctx_text_substitute_ligatures (Ctx *ctx, CtxFont *font,
+                                uint32_t *unichar, uint32_t next_unichar)
+{
+  if (ctx_font_is_monospaced (font))
+    return 0;
+  if (*unichar == 'f')
+    switch (next_unichar)
+    {
+      case 'f': if (ctx_glyph_find (ctx, font, 0xfb00))
+        {
+          *unichar = 0xfb00;
+          return 1;
+        }
+        break;
+      case 'i':
+        if (ctx_glyph_find (ctx, font, 0xfb01))
+        {
+          *unichar = 0xfb01;
+          return 1;
+        }
+        break;
+      case 'l': 
+        if (ctx_glyph_find (ctx, font, 0xfb02))
+        {
+          *unichar = 0xfb02;
+          return 1;
+        }
+        break;
+      case 't': 
+        if (ctx_glyph_find (ctx, font, 0xfb05))
+        {
+          *unichar = 0xfb05;
+          return 1;
+        }
+        break;
+    }
+  return 0;
+}
+
 static void
 _ctx_text (Ctx        *ctx,
            const char *string,
            int         stroke,
            int         visible)
 {
+  char word[CTX_MAX_WORD_LEN];
+  int word_len = 0;
   CtxState *state = &ctx->state;
+  CtxFont *font = &ctx_fonts[state->gstate.font];
   float x = ctx->state.x;
-  switch ( (int) ctx_state_get (state, CTX_text_align) )
+  word[word_len]=0;
+  switch ( (int) ctx_state_get (state, CTX_textAlign) )
     //switch (state->gstate.text_align)
     {
       case CTX_TEXT_ALIGN_START:
@@ -37716,54 +41375,116 @@ _ctx_text (Ctx        *ctx,
     }
   float y = ctx->state.y;
   float baseline_offset = 0.0f;
-  switch ( (int) ctx_state_get (state, CTX_text_baseline) )
+  switch ( (int) ctx_state_get (state, CTX_textBaseline) )
     {
       case CTX_TEXT_BASELINE_HANGING:
         /* XXX : crude */
-        baseline_offset = ctx->state.gstate.font_size  * 0.55;
+        baseline_offset = ctx->state.gstate.font_size  * 0.55f;
         break;
       case CTX_TEXT_BASELINE_TOP:
         /* XXX : crude */
-        baseline_offset = ctx->state.gstate.font_size  * 0.7;
+        baseline_offset = ctx->state.gstate.font_size  * 0.7f;
         break;
       case CTX_TEXT_BASELINE_BOTTOM:
-        baseline_offset = -ctx->state.gstate.font_size * 0.1;
+        baseline_offset = -ctx->state.gstate.font_size * 0.1f;
         break;
       case CTX_TEXT_BASELINE_ALPHABETIC:
       case CTX_TEXT_BASELINE_IDEOGRAPHIC:
         baseline_offset = 0.0f;
         break;
       case CTX_TEXT_BASELINE_MIDDLE:
-        baseline_offset = ctx->state.gstate.font_size * 0.25;
+        baseline_offset = ctx->state.gstate.font_size * 0.25f;
         break;
     }
   float x0 = x;
-  for (const char *utf8 = string; *utf8; utf8 = ctx_utf8_skip (utf8, 1) )
+  float x1 = x + 10000.0f;
+  
+  float wrap_left = ctx_get_wrap_left (ctx);
+  float wrap_right = ctx_get_wrap_right (ctx);
+  if (wrap_left != wrap_right)
+  {
+    x0 = wrap_left;
+  }
+
+  if (*string)
+  for (const char *utf8 = string; utf8 && ( (utf8==string ) || utf8[-1]); utf8 = *utf8?ctx_utf8_skip (utf8, 
1):NULL)
     {
-      if (*utf8 == '\n')
-        {
-          y += ctx->state.gstate.font_size * ctx_state_get (state, CTX_line_spacing);
-          x = x0;
-          if (visible)
-            { ctx_move_to (ctx, x, y); }
-        }
-      else
+      if (*utf8 == '\n' ||
+          *utf8 == ' ' ||
+          *utf8 == '\0')
         {
-          uint32_t unichar = ctx_utf8_to_unichar (utf8);
-          if (visible)
+          float word_width = 0.0;
+          word[word_len]=0;
+
+          for (const char *bp = &word[0]; *bp; bp = ctx_utf8_skip (bp, 1))
+          {
+            uint32_t unichar      = ctx_utf8_to_unichar (bp);
+            const char *next_utf8 = ctx_utf8_skip (bp, 1);
+            uint32_t next_unichar = *next_utf8?ctx_utf8_to_unichar (next_utf8):0;
+
+            if (_ctx_text_substitute_ligatures (ctx, font, &unichar, next_unichar))
+              bp++;
+
+            float glyph_width     = ctx_glyph_width (ctx, unichar);
+            word_width += glyph_width;
+            if (next_unichar)
+              word_width += ctx_glyph_kern (ctx, unichar, next_unichar);
+          }
+
+          if (wrap_left != wrap_right &&
+              x + word_width >= wrap_right)
+          {
+            y += ctx->state.gstate.font_size * ctx_get_line_height (ctx);
+            x = x0;
+          }
+
+          for (const char *bp = &word[0]; *bp; bp = ctx_utf8_skip (bp, 1))
+          {
+            uint32_t unichar      = ctx_utf8_to_unichar (bp);
+            const char *next_utf8 = ctx_utf8_skip (bp, 1);
+            uint32_t next_unichar = *next_utf8?ctx_utf8_to_unichar (next_utf8):0;
+
+            if (_ctx_text_substitute_ligatures (ctx, font, &unichar, next_unichar))
+              bp++;
+
+            float glyph_width = ctx_glyph_width (ctx, unichar);
+            if (x + glyph_width >= x1)
             {
-              ctx_move_to (ctx, x, y + baseline_offset);
-              _ctx_glyph (ctx, unichar, stroke);
+              y += ctx->state.gstate.font_size * ctx_get_line_height (ctx);
+              x = x0;
             }
-          const char *next_utf8 = ctx_utf8_skip (utf8, 1);
-          if (next_utf8)
+            if (visible)
             {
-              x += ctx_glyph_width (ctx, unichar);
-              x += ctx_glyph_kern (ctx, unichar, ctx_utf8_to_unichar (next_utf8) );
+              ctx_move_to (ctx, x, y + baseline_offset);
+              _ctx_glyph (ctx, unichar, stroke);
             }
-          if (visible)
-            { ctx_move_to (ctx, x, y); }
+            x += glyph_width;
+            if (next_unichar)
+              x += ctx_glyph_kern (ctx, unichar, next_unichar );
+          }
+
+          if (*utf8 == '\n')
+          {
+            y += ctx->state.gstate.font_size * ctx_get_line_height (ctx);
+            x = x0;
+          }
+          else if (*utf8 == ' ')
+          {
+            x += ctx_glyph_width (ctx, ' ');
+          }
+          word_len=0;
+          word[word_len]=0;
         }
+      else
+      {
+        int len = ctx_utf8_len (*utf8);
+        for (int i = 0; i < len; i++)
+        {
+          if (word_len + 1 < CTX_MAX_WORD_LEN-1)
+            word[word_len++]=utf8[i];
+        }
+      }
+
     }
   if (!visible)
     { ctx_move_to (ctx, x, y); }
@@ -37773,12 +41494,12 @@ _ctx_text (Ctx        *ctx,
 CtxGlyph *
 ctx_glyph_allocate (int n_glyphs)
 {
-  return (CtxGlyph *) malloc (sizeof (CtxGlyph) * n_glyphs);
+  return (CtxGlyph *) ctx_malloc (sizeof (CtxGlyph) * n_glyphs);
 }
 void
-gtx_glyph_free     (CtxGlyph *glyphs)
+ctx_glyph_free     (CtxGlyph *glyphs)
 {
-  free (glyphs);
+  ctx_free (glyphs);
 }
 
 void
@@ -37842,21 +41563,117 @@ ctx_stroke_text (Ctx *ctx, const char *string,
   ctx_text_stroke (ctx, string);
 }
 
+static const char *ctx_font_get_name (CtxFont *font)
+{
+#if CTX_ONE_FONT_ENGINE
+    return ((char*)(font->ctx.data+2))+1;
+#else
+  switch (font->type)
+  {
+    case 0:  return ((char*)(font->ctx.data+2))+1;
+#if CTX_FONT_ENGINE_STB
+    case 1:  return font->stb.name;
+    case 2:  return font->stb.name;
+#endif
+#if CTX_FONT_ENGINE_CTX_FS
+    case 3:  return font->ctx_fs.name;
+#endif
+  }
+  return "-";
+#endif
+}
+
 static int _ctx_resolve_font (const char *name)
 {
+  char temp[ctx_strlen (name)+1];
+  /* first we look for exact */
   for (int i = 0; i < ctx_font_count; i ++)
     {
-      if (!ctx_strcmp (ctx_fonts[i].name, name) )
+      if (!ctx_strcmp (ctx_font_get_name (&ctx_fonts[i]), name) )
         { return i; }
     }
+  /* ... and substring matches for passed in string */
   for (int i = 0; i < ctx_font_count; i ++)
     {
-      if (ctx_strstr (ctx_fonts[i].name, name) )
+      if (ctx_strstr (ctx_font_get_name (&ctx_fonts[i]), name) )
         { return i; }
     }
+
+  /* then we normalize some names */
+  if (!strncmp (name, "Helvetica", 9))
+  {
+     memset(temp,0,sizeof(temp));
+     strncpy (temp, name + 4, sizeof(temp)-1);
+     memcpy (temp, "Arrrr", 5);  // we should match Arial and Arimo
+     name = temp;
+  }
+  else if (!strncmp (name, "Monospace", 9))
+  {
+     memset(temp,0,sizeof(temp));
+     strncpy (temp, name + 2, sizeof(temp)-1);
+     memcpy (temp, "Courier", 7); 
+     name = temp;
+  }
+  else if (!strncmp (name, "Mono ", 5))
+  {
+    memset(temp,0,sizeof(temp));
+    strncpy (temp + 3, name, sizeof(temp)-1-3);
+    memcpy (temp, "Courier ", 8); 
+    name = temp;
+  }
+  else if (!strcmp (name, "Mono"))
+  {
+    name = "Courier";
+  }
+
+  /* and attempt substring matching with mangled named
+   * permitting matches with length and two first chars
+   * to be valid
+   */
+  {
+    char *subname = (char*)name;
+    int namelen = 0; 
+    if (strchr (subname, ' '))
+    {
+      subname = strchr (subname, ' ');
+      namelen = subname - name;
+      subname++;
+    }
+    for (int i = 0; i < ctx_font_count; i ++)
+    {
+      const char *font_name = ctx_font_get_name (&ctx_fonts[i]);
+      if (font_name[0]==name[0] &&
+          font_name[1]==name[1] &&
+          font_name[namelen] == name[namelen] &&
+          (namelen == 0 || ctx_strstr (font_name, subname) ))
+        return i;
+    }
+  }
+
+  /* then we look for a match of the substring after the first
+   * space
+   */
+  if (strchr (name, ' '))
+  {
+     char *subname = strchr (name, ' ');
+     for (int i = 0; i < ctx_font_count; i ++)
+     {
+       const char *font_name = ctx_font_get_name (&ctx_fonts[i]);
+       if (ctx_strstr (font_name, subname) )
+         { return i; }
+     }
+  }
+
   return -1;
 }
 
+const char *ctx_get_font_name (Ctx *ctx, int no)
+{
+  if (no >= 0 && no < ctx_font_count)
+    return ctx_font_get_name (&ctx_fonts[no]);
+  return NULL;
+}
+
 int ctx_resolve_font (const char *name)
 {
   int ret = _ctx_resolve_font (name);
@@ -37872,77 +41689,166 @@ int ctx_resolve_font (const char *name)
   return 0;
 }
 
-static void ctx_font_setup (void)
+
+
+#if !( defined(CTX_FONT_0) ||\
+       defined(CTX_FONT_1) ||\
+       defined(CTX_FONT_2) ||\
+       defined(CTX_FONT_3) ||\
+       defined(CTX_FONT_4) ||\
+       defined(CTX_FONT_5) ||\
+       defined(CTX_FONT_6) ||\
+       defined(CTX_FONT_7) ||\
+       defined(CTX_FONT_8) ||\
+       defined(CTX_FONT_9) ||\
+       defined(CTX_FONT_10) ||\
+       defined(CTX_FONT_11) ||\
+       defined(CTX_FONT_12) ||\
+       defined(CTX_FONT_13) ||\
+       defined(CTX_FONT_14) ||\
+       defined(CTX_FONT_15) ||\
+       defined(CTX_FONT_16) ||\
+       defined(CTX_FONT_17) ||\
+       defined(CTX_FONT_18) ||\
+       defined(CTX_FONT_19) ||\
+       defined(CTX_FONT_20) ||\
+       defined(CTX_FONT_21))
+#define static_FONT(font_string, font_data) \
+  ctx_load_font_ctx(font_string, ctx_font_##font_data, sizeof (ctx_font_##font_data))
+#define CTX_FONT_0 static_FONT("sans-ctx", ascii)
+#endif
+
+
+
+static void ctx_font_setup (Ctx *ctx)
 {
   static int initialized = 0;
-  if (initialized) { return; }
+  if (initialized) { 
+    if (ctx)
+      ctx->fonts = ctx_fonts;
+    return;
+  }
   initialized = 1;
-#if CTX_FONT_ENGINE_CTX
-  ctx_font_count = 0; // oddly - this is needed in arduino
 
-#if CTX_FONT_ENGINE_CTX_FS
-  ctx_load_font_ctx_fs ("sans-ctx", "/tmp/ctx-regular", 0);
+  //if (!ctx_fonts)
+#ifdef EMSCRIPTEN
+    //ctx_fonts = calloc (CTX_MAX_FONTS, sizeof (CtxFont));
 #else
-#if CTX_FONT_ascii
-  ctx_load_font_ctx ("sans-ctx", ctx_font_ascii, sizeof (ctx_font_ascii) );
-#endif
-#if CTX_FONT_regular
-  ctx_load_font_ctx ("sans-ctx", ctx_font_regular, sizeof (ctx_font_regular) );
+    //ctx_fonts = ctx_calloc (CTX_MAX_FONTS, sizeof (CtxFont));
 #endif
+  if (ctx)
+    ctx->fonts = &ctx_fonts[0];
+
+  ctx_font_count = 0; 
+
+#if CTX_FONT_ENGINE_CTX_FS
+  if (getenv ("CTX_FONT_LIVE_PATH"))
+  {
+    if (getenv ("CTX_FONT_LIVE_NAME"))
+      ctx_load_font_ctx_fs (getenv ("CTX_FONT_LIVE_NAME"), getenv ("CTX_FONT_LIVE_PATH"), 0);
+    else
+      ctx_load_font_ctx_fs ("Arrrr Regular", getenv ("CTX_FONT_LIVE_PATH"),0);
+  }
 #endif
 
-#if CTX_FONT_mono
-  ctx_load_font_ctx ("mono-ctx", ctx_font_mono, sizeof (ctx_font_mono) );
+#if CTX_FONT_ENGINE_CTX
+
+#ifdef CTX_FONT_0
+  CTX_FONT_0;
 #endif
-#if CTX_FONT_bold
-  ctx_load_font_ctx ("bold-ctx", ctx_font_bold, sizeof (ctx_font_bold) );
+#ifdef CTX_FONT_1
+  CTX_FONT_1;
 #endif
-#if CTX_FONT_italic
-  ctx_load_font_ctx ("italic-ctx", ctx_font_italic, sizeof (ctx_font_italic) );
+#ifdef CTX_FONT_2
+  CTX_FONT_2;
 #endif
-#if CTX_FONT_sans
-  ctx_load_font_ctx ("sans-ctx", ctx_font_sans, sizeof (ctx_font_sans) );
+#ifdef CTX_FONT_3
+  CTX_FONT_3;
 #endif
-#if CTX_FONT_serif
-  ctx_load_font_ctx ("serif-ctx", ctx_font_serif, sizeof (ctx_font_serif) );
+#ifdef CTX_FONT_4
+  CTX_FONT_4;
 #endif
-#if CTX_FONT_symbol
-  ctx_load_font_ctx ("symbol-ctx", ctx_font_symbol, sizeof (ctx_font_symbol) );
+#ifdef CTX_FONT_5
+  CTX_FONT_5;
 #endif
-#if CTX_FONT_emoji
-  ctx_load_font_ctx ("emoji-ctx", ctx_font_emoji, sizeof (ctx_font_emoji) );
+#ifdef CTX_FONT_6
+  CTX_FONT_6;
 #endif
+#ifdef CTX_FONT_7
+  CTX_FONT_7;
 #endif
-
-#if NOTO_EMOJI_REGULAR
-  ctx_load_font_ttf ("sans-NotoEmoji_Regular", ttf_NotoEmoji_Regular_ttf, ttf_NotoEmoji_Regular_ttf_len);
+#ifdef CTX_FONT_8
+  CTX_FONT_8;
+#endif
+#ifdef CTX_FONT_9
+  CTX_FONT_9;
+#endif
+#ifdef CTX_FONT_10
+  CTX_FONT_10;
+#endif
+#ifdef CTX_FONT_11
+  CTX_FONT_11;
+#endif
+#ifdef CTX_FONT_12
+  CTX_FONT_12;
+#endif
+#ifdef CTX_FONT_13
+  CTX_FONT_13;
+#endif
+#ifdef CTX_FONT_14
+  CTX_FONT_14;
+#endif
+#ifdef CTX_FONT_15
+  CTX_FONT_15;
+#endif
+#ifdef CTX_FONT_16
+  CTX_FONT_16;
+#endif
+#ifdef CTX_FONT_17
+  CTX_FONT_17;
+#endif
+#ifdef CTX_FONT_18
+  CTX_FONT_18;
+#endif
+#ifdef CTX_FONT_19
+  CTX_FONT_19;
+#endif
+#ifdef CTX_FONT_20
+  CTX_FONT_20;
 #endif
-#if ROBOTO_LIGHT
-  ctx_load_font_ttf ("sans-light-Roboto_Light", ttf_Roboto_Light_ttf, ttf_Roboto_Light_ttf_len);
+#ifdef CTX_FONT_21
+  CTX_FONT_21;
 #endif
-#if ROBOTO_REGULAR
-  ctx_load_font_ttf ("sans-Roboto_Regular", ttf_Roboto_Regular_ttf, ttf_Roboto_Regular_ttf_len);
+#ifdef CTX_FONT_22
+  CTX_FONT_22;
 #endif
-#if ROBOTO_BOLD
-  ctx_load_font_ttf ("sans-bold-Roboto_Bold", ttf_Roboto_Bold_ttf, ttf_Roboto_Bold_ttf_len);
+#ifdef CTX_FONT_23
+  CTX_FONT_23;
 #endif
-#if DEJAVU_SANS
-  ctx_load_font_ttf ("sans-DejaVuSans", ttf_DejaVuSans_ttf, ttf_DejaVuSans_ttf_len);
+#ifdef CTX_FONT_24
+  CTX_FONT_24;
 #endif
-#if VERA
-  ctx_load_font_ttf ("sans-Vera", ttf_Vera_ttf, ttf_Vera_ttf_len);
+#ifdef CTX_FONT_25
+  CTX_FONT_25;
 #endif
-#if UNSCII_16
-  ctx_load_font_ttf ("mono-unscii16", ttf_unscii_16_ttf, ttf_unscii_16_ttf_len);
+#ifdef CTX_FONT_26
+  CTX_FONT_26;
 #endif
-#if XA000_MONO
-  ctx_load_font_ttf ("mono-0xA000", ttf_0xA000_Mono_ttf, ttf_0xA000_Mono_ttf_len);
+#ifdef ctx_font_27
+  ctx_font_27;
 #endif
-#if DEJAVU_SANS_MONO
-  ctx_load_font_ttf ("mono-DejaVuSansMono", ttf_DejaVuSansMono_ttf, ttf_DejaVuSansMono_ttf_len);
+#ifdef ctx_font_28
+  ctx_font_28;
+#endif
+#ifdef CTX_FONT_29
+  CTX_FONT_29;
+#endif
+#ifdef CTX_FONT_30
+  CTX_FONT_30;
+#endif
+#ifdef CTX_FONT_31
+  CTX_FONT_31;
 #endif
-#if NOTO_MONO_REGULAR
-  ctx_load_font_ttf ("mono-NotoMono_Regular", ttf_NotoMono_Regular_ttf, ttf_NotoMono_Regular_ttf_len);
 #endif
 }
 
@@ -37973,13 +41879,13 @@ static inline void ctx_formatter_addstrf (CtxFormatter *formatter, const char *f
    char *buffer;
    va_start (ap, format);
    needed = vsnprintf (NULL, 0, format, ap) + 1;
-   buffer = (char*) malloc (needed);
+   buffer = (char*) ctx_malloc (needed);
    va_end (ap);
    va_start (ap, format);
    vsnprintf (buffer, needed, format, ap);
    va_end (ap);
    ctx_formatter_addstr (formatter, buffer, -1);
-   free (buffer);
+   ctx_free (buffer);
 }
 #endif
 
@@ -38020,9 +41926,18 @@ ctx_print_int (CtxFormatter *formatter, int val)
 static void
 ctx_print_float (CtxFormatter *formatter, float val)
 {
-  // XXX : does truncation instead of rounding
-  int remainder = ((int)(val*1000))%1000;
-  ctx_print_int (formatter, val);
+  if (val < 0.0f)
+  {
+    ctx_formatter_addstr (formatter, "-", 1);
+    val = -val;
+  }
+  int remainder = ((int)(val*10000))%10000;
+  if (remainder % 10 > 5)
+    remainder = remainder/10+1;
+  else
+    remainder /= 10;
+
+  ctx_print_int (formatter, (int)val);
   if (remainder)
   {
     ctx_formatter_addstr (formatter, ".", 1);
@@ -38040,7 +41955,7 @@ static void _ctx_stream_addstr (CtxFormatter *formatter, const char *str, int le
   {
     return;
   }
-  if (len < 0) len = strlen (str);
+  if (len < 0) len = ctx_strlen (str);
   fwrite (str, len, 1, (FILE*)formatter->target);
 }
 
@@ -38050,7 +41965,7 @@ void _ctx_string_addstr (CtxFormatter *formatter, const char *str, int len)
   {
     return;
   }
-  if (len < 0) len = strlen (str);
+  if (len < 0) len = ctx_strlen (str);
   ctx_string_append_data ((CtxString*)(formatter->target), str, len);
 }
 
@@ -38087,6 +42002,7 @@ const char *_ctx_code_to_name (int code)
           case CTX_SET_KEY:              return "setParam"; break;
           case CTX_COLOR:                return "setColor"; break;
           case CTX_DEFINE_GLYPH:         return "defineGlyph"; break;
+          case CTX_DEFINE_FONT:          return "defineFont"; break;
           case CTX_KERNING_PAIR:         return "kerningPair"; break;
           case CTX_SET_PIXEL:            return "setPixel"; break;
           case CTX_GLOBAL_ALPHA:         return "globalAlpha"; break;
@@ -38121,8 +42037,8 @@ const char *_ctx_code_to_name (int code)
           case CTX_IDENTITY:             return "identity"; break;
           case CTX_CLOSE_PATH:           return "closePath"; break;
           case CTX_PRESERVE:             return "preserve"; break;
-          case CTX_FLUSH:                return "flush"; break;
-          case CTX_RESET:                return "reset"; break;
+          case CTX_START_FRAME:          return "start_frame"; break;
+          case CTX_END_FRAME:            return "end_frame"; break;
           case CTX_FONT:                 return "font"; break;
           case CTX_STROKE:               return "stroke"; break;
           case CTX_CLIP:                 return "clip"; break;
@@ -38155,6 +42071,9 @@ const char *_ctx_code_to_name (int code)
           case CTX_LINE_CAP:             return "lineCap"; break;
           case CTX_LINE_WIDTH:           return "lineWidth"; break;
           case CTX_LINE_DASH_OFFSET:     return "lineDashOffset"; break;
+          case CTX_LINE_HEIGHT:          return "lineHeight";break;
+          case CTX_WRAP_LEFT:            return "wrapLeft"; break;
+          case CTX_WRAP_RIGHT:           return "wrapRight"; break;
           case CTX_IMAGE_SMOOTHING:      return "imageSmoothing"; break;
           case CTX_SHADOW_BLUR:          return "shadowBlur";  break;
           case CTX_FILL_RULE:            return "fillRule"; break;
@@ -38203,6 +42122,9 @@ static void _ctx_print_name (CtxFormatter *formatter, int code)
         case CTX_LINE_CAP:          name[1]='c'; break;
         case CTX_LINE_WIDTH:        name[1]='w'; break;
         case CTX_LINE_DASH_OFFSET:  name[1]='D'; break;
+        case CTX_LINE_HEIGHT:       name[1]='H'; break;
+        case CTX_WRAP_LEFT:         name[1]='L'; break;
+        case CTX_WRAP_RIGHT:        name[1]='R'; break;
         case CTX_IMAGE_SMOOTHING:   name[1]='S'; break;
         case CTX_SHADOW_BLUR:       name[1]='s'; break;
         case CTX_SHADOW_COLOR:      name[1]='C'; break;
@@ -38352,28 +42274,29 @@ ctx_print_entry_enum (CtxFormatter *formatter, CtxEntry *entry, int args)
   _ctx_print_endcmd (formatter);
 }
 
-
+#if 0
 static void
 ctx_print_a85 (CtxFormatter *formatter, uint8_t *data, int length)
 {
-  char *tmp = (char*)malloc (ctx_a85enc_len (length));
+  char *tmp = (char*)ctx_malloc (ctx_a85enc_len (length));
   ctx_a85enc (data, tmp, length);
   ctx_formatter_addstr (formatter, " ~", 2);
   ctx_formatter_addstr (formatter, tmp, -1);
   ctx_formatter_addstr (formatter, "~ ", 2);
-  free (tmp);
+  ctx_free (tmp);
 }
+#endif
 
 static void
 ctx_print_yenc (CtxFormatter *formatter, uint8_t *data, int length)
 {
-  char *tmp = (char*)malloc (length * 2 + 2);// worst case scenario
+  char *tmp = (char*)ctx_malloc (length * 2 + 2);// worst case scenario
   int enclength = ctx_yenc ((char*)data, tmp, length);
   data[enclength]=0;
   ctx_formatter_addstr (formatter, " =", 2);
   ctx_formatter_addstr (formatter, tmp, enclength);
   ctx_formatter_addstr (formatter, "=y ", 2);
-  free (tmp);
+  ctx_free (tmp);
 }
 
 static void
@@ -38407,7 +42330,7 @@ ctx_print_entry (CtxFormatter *formatter, CtxEntry *entry, int args)
   for (int i = 0; i <  args; i ++)
     {
       float val = ctx_arg_float (i);
-      if (i>0 && val >= 0.0f)
+      if (i>0 /* && val >= 0.0f */)
         {
           if (formatter->longform)
             {
@@ -38415,8 +42338,7 @@ ctx_print_entry (CtxFormatter *formatter, CtxEntry *entry, int args)
             }
           else
             {
-              if (val >= 0.0f)
-                ctx_formatter_addstr (formatter, " ", 1);
+              ctx_formatter_addstr (formatter, " ", 1);
             }
         }
       ctx_print_float (formatter, val);
@@ -38536,6 +42458,9 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
       case CTX_ROTATE:
       case CTX_LINE_WIDTH:
       case CTX_LINE_DASH_OFFSET:
+      case CTX_LINE_HEIGHT:
+      case CTX_WRAP_LEFT:
+      case CTX_WRAP_RIGHT:
       case CTX_GLOBAL_ALPHA:
       case CTX_SHADOW_BLUR:
       case CTX_SHADOW_OFFSET_X:
@@ -38594,7 +42519,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
                   ctx_print_float (formatter, c->graya.a);
                   break;
                 case CTX_RGBA:
-                  if (c->rgba.a != 1.0)
+                  if (c->rgba.a != 1.0f)
                   {
                     ctx_formatter_addstr (formatter, "rgba", 4);
                     ctx_formatter_addstr (formatter, suffix, -1);
@@ -38749,7 +42674,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
         break;
       case CTX_FILL:
       case CTX_PAINT:
-      case CTX_RESET:
+      case CTX_START_FRAME:
       case CTX_STROKE:
       case CTX_IDENTITY:
       case CTX_CLIP:
@@ -38778,10 +42703,10 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
         break;
       case CTX_GRADIENT_STOP:
         _ctx_print_name (formatter, entry->code);
+        ctx_print_float (formatter, ctx_arg_float (0));
         for (int c = 0; c < 4; c++)
           {
-            if (c)
-              ctx_formatter_addstr (formatter, " ", 1);
+            ctx_formatter_addstr (formatter, " ", 1);
             ctx_print_float (formatter, ctx_u8_to_float (ctx_arg_u8 (4+c) ) );
           }
         _ctx_print_endcmd (formatter);
@@ -38799,8 +42724,18 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
       case CTX_EDGE:
       case CTX_DATA:
       case CTX_DATA_REV:
-      case CTX_FLUSH:
+      case CTX_END_FRAME:
+        break;
+
+      case CTX_DEFINE_FONT:
+        _ctx_print_name (formatter, entry->code);
+        ctx_formatter_addstr (formatter, "\"", 1);
+        ctx_print_escaped_string (formatter, ctx_arg_string());
+        ctx_formatter_addstr (formatter, "\"", 1);
+        _ctx_print_endcmd (formatter);
+        // XXX: todo, also print license if present
         break;
+
       case CTX_KERNING_PAIR:
         _ctx_print_name (formatter, entry->code);
         ctx_formatter_addstr (formatter, "\"", 1);
@@ -38812,7 +42747,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
            utf8[ctx_unichar_to_utf8 (c->kern.glyph_after, utf8)]=0;
            ctx_print_escaped_string (formatter, (char*)utf8);
            ctx_formatter_addstr (formatter, "\", ", 3);
-           ctx_print_float (formatter, c->kern.amount/256.0);
+           ctx_print_float (formatter, c->kern.amount/256.0f);
            ctx_print_escaped_string (formatter, (char*)utf8);
         }
         _ctx_print_endcmd (formatter);
@@ -38826,8 +42761,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
            utf8[ctx_unichar_to_utf8 (entry->data.u32[0], utf8)]=0;
            ctx_print_escaped_string (formatter, (char*)utf8);
            ctx_formatter_addstr (formatter, "\", ", 3);
-           ctx_print_float (formatter, entry->data.u32[1]/256.0);
-           ctx_print_escaped_string (formatter, (char*)utf8);
+           ctx_print_float (formatter, entry->data.u32[1]/256.0f);
         }
         _ctx_print_endcmd (formatter);
         break;
@@ -38916,14 +42850,27 @@ void ctx_dirty_rect (Ctx *ctx, int *x, int *y, int *width, int *height)
 }
 
 #if CTX_CURRENT_PATH
-CtxIterator *
-ctx_current_path (Ctx *ctx)
+static CtxIterator *
+ctx_current_path_iterator (Ctx *ctx)
 {
   CtxIterator *iterator = &ctx->current_path_iterator;
   ctx_iterator_init (iterator, &ctx->current_path, 0, CTX_ITERATOR_EXPAND_BITPACK);
   return iterator;
 }
 
+CtxDrawlist *
+ctx_current_path (Ctx *ctx)
+{
+  CtxDrawlist *drawlist = ctx_calloc (sizeof (CtxDrawlist) + 
+                              ctx->current_path.count * 9, 1);
+  drawlist->entries = (CtxEntry*)(&drawlist[1]);
+  drawlist->size = drawlist->count = ctx->current_path.count;
+  drawlist->flags = CTX_DRAWLIST_DOESNT_OWN_ENTRIES;
+  memcpy (drawlist->entries, ctx->current_path.entries,
+          drawlist->count * 9);
+  return drawlist;
+}
+
 void
 ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
 {
@@ -38934,7 +42881,7 @@ ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
   float x = 0;
   float y = 0;
 
-  CtxIterator *iterator = ctx_current_path (ctx);
+  CtxIterator *iterator = ctx_current_path_iterator (ctx);
   CtxCommand *command;
 
   while ((command = ctx_iterator_next (iterator)))
@@ -38942,7 +42889,7 @@ ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
      int got_coord = 0;
      switch (command->code)
      {
-        // XXX missing many curve types
+        // XXX missing some segment types
         case CTX_LINE_TO:
         case CTX_MOVE_TO:
           x = command->move_to.x;
@@ -38951,8 +42898,8 @@ ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
           break;
         case CTX_REL_LINE_TO:
         case CTX_REL_MOVE_TO:
-          x += command->move_to.x;
-          y += command->move_to.y;
+          x += command->line_to.x;
+          y += command->line_to.y;
           got_coord++;
           break;
         case CTX_CURVE_TO:
@@ -38961,8 +42908,8 @@ ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
           got_coord++;
           break;
         case CTX_REL_CURVE_TO:
-          x += command->curve_to.x;
-          y += command->curve_to.y;
+          x += command->rel_curve_to.x;
+          y += command->rel_curve_to.y;
           got_coord++;
           break;
         case CTX_ARC:
@@ -38985,7 +42932,9 @@ ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
           y += command->rectangle.height;
           got_coord++;
           break;
+        default:
      }
+          //fprintf(stderr, "[%c]", command->code);
     if (got_coord)
     {
       minx = ctx_minf (minx, x);
@@ -39016,7 +42965,7 @@ ctx_gstate_push (CtxState *state)
     { return; }
   state->gstate_stack[state->gstate_no] = state->gstate;
   state->gstate_no++;
-  ctx_state_set (state, CTX_new_state, 0.0);
+  ctx_state_set (state, CTX_newState, 0.0f);
   state->has_clipped=0;
 }
 
@@ -39066,7 +43015,9 @@ ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh,
      }
    }
 #endif
-   else if (format == CTX_FORMAT_RGBA8 && ctx_backend_is_tiled (ctx))
+   else if ((format == CTX_FORMAT_RGBA8 ||
+             format == CTX_FORMAT_BGRA8)
+                   && ctx_backend_is_tiled (ctx))
    {
      /* synchronize */
      CtxTiled *tiled = (CtxTiled*)ctx->backend;
@@ -39074,6 +43025,7 @@ ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh,
        if (dst_stride <= 0) dst_stride = ctx_pixel_format_get_stride (format, sw);
        int bytes_per_pix = 4;
        int y = 0;
+       int count = 0;
        for (int v = sy; v < sy + sh; v++, y++)
        {
          int x = 0;
@@ -39081,6 +43033,17 @@ ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh,
          {
             uint8_t* src_buf = (uint8_t*)tiled->pixels;
             memcpy (&dst_data[y * dst_stride + x * bytes_per_pix], &src_buf[v * tiled->width * bytes_per_pix 
+ u * bytes_per_pix], bytes_per_pix);
+            count++;
+         }
+       }
+       if (format == CTX_FORMAT_RGBA8) // XXX does this vary between tiled
+                                       // backends?
+       {
+         for (int i = 0; i < count; i++)
+         {
+           uint32_t tmp = dst_data[i*4+0];
+           dst_data[i*4+0] = dst_data[i*4+2];
+           dst_data[i*4+2] = tmp;
          }
        }
        return;
@@ -39092,11 +43055,25 @@ ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh,
      Ctx *rasterizer = ctx_new_for_framebuffer (dst_data, sw, sh, dst_stride, format);
      ctx_translate (rasterizer, sx, sy);
      ctx_render_ctx (ctx, rasterizer);
-     ctx_free (rasterizer);
+     ctx_destroy (rasterizer);
    }
 #endif
 }
 
+void ctx_screenshot (Ctx *ctx, const char *output_path)
+{
+#ifdef INCLUDE_STB_IMAGE_WRITE_H
+  uint32_t width = ctx_width (ctx);
+  uint32_t height = ctx_height (ctx);
+  uint8_t *buf = ctx_malloc (width * height * 4);
+  ctx_get_image_data (ctx, 0, 0, width, height,
+                      CTX_FORMAT_RGBA8, width *4,
+                      buf);
+  stbi_write_png (output_path, width, height, 4, buf, width * 4);
+  ctx_free (buf);
+#endif
+}
+
 void
 ctx_put_image_data (Ctx *ctx, int w, int h, int stride, int format,
                     uint8_t *data,
@@ -39124,7 +43101,6 @@ static int ctx_eid_valid (Ctx *ctx, const char *eid, int *w, int *h)
   ctx = ctx->texture_cache;
   CtxList *to_remove = NULL;
   int ret = 0;
-  //fprintf (stderr, "{%i}\n", ctx->frame);
   for (CtxList *l = ctx->eid_db; l; l = l->next)
   {
     CtxEidInfo *eid_info = (CtxEidInfo*)l->data;
@@ -39136,7 +43112,7 @@ static int ctx_eid_valid (Ctx *ctx, const char *eid, int *w, int *h)
     {
       ctx_list_prepend (&to_remove, eid_info);
     }
-    else if (!strcmp (eid_info->eid, eid) &&
+    else if (!ctx_strcmp (eid_info->eid, eid) &&
              ctx->frame - eid_info->frame < 2)
     {
     //fclose (f);
@@ -39152,17 +43128,50 @@ static int ctx_eid_valid (Ctx *ctx, const char *eid, int *w, int *h)
     //FILE  *f  = fopen ("/tmp/l", "a");
     //fprintf (f, "%i client removing %s\n", getpid(), eid_info->eid);
     //fclose (f);
-    free (eid_info->eid);
-    free (eid_info);
+    ctx_free (eid_info->eid);
+    ctx_free (eid_info);
     ctx_list_remove (&ctx->eid_db, eid_info);
     ctx_list_remove (&to_remove, eid_info);
   }
   return ret;
 }
 
+void ctx_drop_eid (Ctx *ctx, const char *eid)
+{
+  ctx = ctx->texture_cache;
+  CtxList *to_remove = NULL;
+  for (CtxList *l = ctx->eid_db; l; l = l->next)
+  {
+    CtxEidInfo *eid_info = (CtxEidInfo*)l->data;
+    if (!ctx_strcmp (eid_info->eid, eid))
+    {
+      ctx_list_prepend (&to_remove, eid_info);
+    }
+  }
+  while (to_remove)
+  {
+    CtxEidInfo *eid_info = (CtxEidInfo*)to_remove->data;
+    ctx_free (eid_info->eid);
+    ctx_free (eid_info);
+    ctx_list_remove (&ctx->eid_db, eid_info);
+    ctx_list_remove (&to_remove, eid_info);
+  }
+
+  for (int i = 0; i <  CTX_MAX_TEXTURES; i++)
+  {
+    if (ctx->texture[i].data &&
+        ctx->texture[i].eid  &&
+        !ctx_strcmp (ctx->texture[i].eid, eid))
+    {
+      ctx->texture[i].eid[0]++;
+    }
+  }
+}
+
+
 void ctx_texture (Ctx *ctx, const char *eid, float x, float y)
 {
-  int eid_len = strlen (eid);
+  int eid_len = ctx_strlen (eid);
   char ascii[41]="";
   //fprintf (stderr, "tx %s\n", eid);
   if (eid_len > 50)
@@ -39247,7 +43256,7 @@ void ctx_define_texture (Ctx *ctx,
     eid = ascii;
   }
 
-  int eid_len = strlen (eid);
+  int eid_len = ctx_strlen (eid);
 
   if (eid_len > 50)
   {
@@ -39271,7 +43280,7 @@ void ctx_define_texture (Ctx *ctx,
 
   if (ctx_eid_valid (ctx, eid, 0, 0))
   {
-    ctx_texture (ctx, eid, 0.0, 0.0);
+    ctx_texture (ctx, eid, 0.0f, 0.0f);
   }
   else
 
@@ -39280,7 +43289,7 @@ void ctx_define_texture (Ctx *ctx,
     int command_size = 1 + (data_len+1+1)/9 + 1 + (eid_len+1+1)/9 + 1 +   8;
     if (ctx->backend && (void*)ctx->backend->process != (void*)ctx_drawlist_process)
     {
-       commands = (CtxEntry*)calloc (sizeof (CtxEntry), command_size);
+       commands = (CtxEntry*)ctx_calloc (sizeof (CtxEntry), command_size);
     }
     else
     {
@@ -39327,19 +43336,19 @@ void ctx_define_texture (Ctx *ctx,
     if (ctx->backend && (void*)ctx->backend->process != (void*)ctx_drawlist_process)
     {
       ctx_process (ctx, commands);
-      free (commands);
+      ctx_free (commands);
     }
     else
     {
        ctx->drawlist.count += ctx_conts_for_entry (commands) + 1;
     }
 
-    CtxEidInfo *eid_info = (CtxEidInfo*)calloc (sizeof (CtxEidInfo), 1);
+    CtxEidInfo *eid_info = (CtxEidInfo*)ctx_calloc (sizeof (CtxEidInfo), 1);
     eid_info->width      = width;
     eid_info->height     = height;
     eid_info->frame      = ctx->texture_cache->frame;
     //fprintf (stderr, "%i\n", eid_info->frame);
-    eid_info->eid        = strdup (eid);
+    eid_info->eid        = ctx_strdup (eid);
     ctx_list_prepend (&ctx->texture_cache->eid_db, eid_info);
   }
 
@@ -39354,8 +43363,9 @@ void
 ctx_texture_load (Ctx *ctx, const char *path, int *tw, int *th, char *reid)
 {
   const char *eid = path;
+  if (strstr (path, "svg"))return;
   char ascii[41]="";
-  int eid_len = strlen (eid);
+  int eid_len = ctx_strlen (eid);
   if (eid_len > 50)
   {
     CtxSHA1 *sha1 = ctx_sha1_new ();
@@ -39373,7 +43383,7 @@ ctx_texture_load (Ctx *ctx, const char *path, int *tw, int *th, char *reid)
     eid = ascii;
   }
 
-  if (ctx_eid_valid (ctx, eid , tw, th))
+  if (ctx_eid_valid (ctx, eid, tw, th))
   {
      if (reid)
      {
@@ -39399,10 +43409,11 @@ ctx_texture_load (Ctx *ctx, const char *path, int *tw, int *th, char *reid)
     if (data)
     {
        pixels = stbi_load_from_memory (data, length, &w, &h, &components, 0);
-       free (data);
+       ctx_free (data);
     }
   }
 
+
   if (pixels)
   {
     switch (components)
@@ -39410,12 +43421,17 @@ ctx_texture_load (Ctx *ctx, const char *path, int *tw, int *th, char *reid)
       case 1: pixel_format = CTX_FORMAT_GRAY8;  break;
       case 2: pixel_format = CTX_FORMAT_GRAYA8; break;
       case 3: pixel_format = CTX_FORMAT_RGB8;   break;
-      case 4: pixel_format = CTX_FORMAT_RGBA8;  break;
+      case 4: pixel_format = CTX_FORMAT_RGBA8;
+      for (int i = 0; i < w * h; i++)
+      {
+        ctx_RGBA8_associate_alpha (&pixels[i * 4]);
+      }
+        break;
     }
     if (tw) *tw = w;
     if (th) *th = h;
     ctx_define_texture (ctx, eid, w, h, w * components, pixel_format, pixels, reid);
-    free (pixels);
+    ctx_free (pixels);
   }
   else
   {
@@ -39435,7 +43451,7 @@ ctx_draw_texture_clipped  (Ctx *ctx, const char *eid,
   int tex_height = 0;
   if (ctx_eid_valid (ctx, eid , &tex_width, &tex_height))
   {
-    if (width > 0.0 && height > 0.0)
+    if (width > 0.0f && height > 0.0f)
     {
 #if 0
       if (clip_width > 0.0f)
@@ -39547,6 +43563,7 @@ void ctx_stroke (Ctx *ctx)
 }
 
 
+#if 0
 static void ctx_empty (Ctx *ctx)
 {
 #if CTX_RASTERIZER
@@ -39554,6 +43571,7 @@ static void ctx_empty (Ctx *ctx)
 #endif
     ctx_drawlist_clear (ctx);
 }
+#endif
 
 void _ctx_set_store_clear (Ctx *ctx)
 {
@@ -39564,7 +43582,7 @@ void _ctx_set_store_clear (Ctx *ctx)
 static void
 ctx_event_free (void *event, void *user_data)
 {
-  free (event);
+  ctx_free (event);
 }
 
 static void
@@ -39572,12 +43590,12 @@ ctx_collect_events (CtxEvent *event, void *data, void *data2)
 {
   Ctx *ctx = (Ctx*)data;
   CtxEvent *copy;
-  if (event->type == CTX_KEY_PRESS && !strcmp (event->string, "idle"))
+  if (event->type == CTX_KEY_PRESS && !ctx_strcmp (event->string, "idle"))
     return;
-  copy = (CtxEvent*)malloc (sizeof (CtxEvent));
+  copy = (CtxEvent*)ctx_malloc (sizeof (CtxEvent));
   *copy = *event;
   if (copy->string)
-    copy->string = strdup (event->string);
+    copy->string = ctx_strdup (event->string);
   ctx_list_append_full (&ctx->events.events, copy, ctx_event_free, NULL);
 }
 #endif
@@ -39587,7 +43605,7 @@ static void _ctx_bindings_key_press (CtxEvent *event, void *data1, void *data2);
 #endif
 
 CTX_EXPORT void
-ctx_reset (Ctx *ctx)
+ctx_start_frame (Ctx *ctx)
 {
   ctx_drawlist_clear (ctx);
         /* we do the callback reset first - maybe we need two cbs,
@@ -39595,10 +43613,10 @@ ctx_reset (Ctx *ctx)
          *
          * tiled fb and sdl needs to sync
          */
-  if (ctx->backend && ctx->backend->reset)
-    ctx->backend->reset (ctx);
+  if (ctx->backend && ctx->backend->start_frame)
+    ctx->backend->start_frame (ctx);
 
-  //CTX_PROCESS_VOID (CTX_RESET);
+  //CTX_PROCESS_VOID (CTX_START_FRAME);
   //if (ctx->transformation & CTX_TRANSFORMATION_STORE_CLEAR)
   //  { return; }
   ctx_state_init (&ctx->state);
@@ -39650,6 +43668,10 @@ void ctx_restore (Ctx *ctx)
 {
   CTX_PROCESS_VOID (CTX_RESTORE);
 }
+void ctx_new_page (Ctx *ctx)
+{
+  CTX_PROCESS_VOID (CTX_NEW_PAGE);
+}
 
 void ctx_start_group (Ctx *ctx)
 {
@@ -39683,6 +43705,21 @@ void ctx_line_dash_offset (Ctx *ctx, float x)
     CTX_PROCESS_F1 (CTX_LINE_DASH_OFFSET, x);
 }
 
+void ctx_line_height (Ctx *ctx, float x)
+{
+  CTX_PROCESS_F1 (CTX_LINE_HEIGHT, x);
+}
+
+void ctx_wrap_left (Ctx *ctx, float x)
+{
+  CTX_PROCESS_F1 (CTX_WRAP_LEFT , x);
+}
+
+void ctx_wrap_right (Ctx *ctx, float x)
+{
+  CTX_PROCESS_F1 (CTX_WRAP_RIGHT, x);
+}
+
 int ctx_get_image_smoothing (Ctx *ctx)
 {
   return ctx->state.gstate.image_smoothing;
@@ -39780,7 +43817,7 @@ _ctx_font (Ctx *ctx, const char *name)
 void
 ctx_set (Ctx *ctx, uint32_t key_hash, const char *string, int len)
 {
-  if (len <= 0) len = strlen (string);
+  if (len <= 0) len = ctx_strlen (string);
   ctx_process_cmd_str (ctx, CTX_SET, string, key_hash, len);
 }
 
@@ -39821,7 +43858,7 @@ ctx_font (Ctx *ctx, const char *family_name)
 const char *
 ctx_get_font (Ctx *ctx)
 {
-  return ctx_fonts[ctx->state.gstate.font].name;
+  return ctx_get_font_name (ctx, ctx->state.gstate.font);
 }
 
 void ctx_line_to (Ctx *ctx, float x, float y)
@@ -39927,12 +43964,26 @@ CtxExtend ctx_get_extend (Ctx *ctx)
 
 CtxTextAlign ctx_get_text_align  (Ctx *ctx)
 {
-  return (CtxTextAlign)ctx_state_get (&ctx->state, CTX_text_align);
+  return (CtxTextAlign)ctx_state_get (&ctx->state, CTX_textAlign);
+}
+
+float ctx_get_wrap_left        (Ctx *ctx)
+{
+  return ctx_state_get (&ctx->state, CTX_wrapLeft);
+}
+float ctx_get_wrap_right       (Ctx *ctx)
+{
+  return ctx_state_get (&ctx->state, CTX_wrapRight);
+}
+
+float ctx_get_line_height      (Ctx *ctx)
+{
+  return ctx_state_get (&ctx->state, CTX_lineHeight);
 }
 
 CtxTextBaseline ctx_get_text_baseline (Ctx *ctx)
 {
-  return (CtxTextBaseline)ctx_state_get (&ctx->state, CTX_text_baseline);
+  return (CtxTextBaseline)ctx_state_get (&ctx->state, CTX_textBaseline);
 }
 
 CtxLineCap ctx_get_line_cap (Ctx *ctx)
@@ -40070,7 +44121,7 @@ ctx_point_seg_dist_sq (float x, float y,
                        float vx, float vy, float wx, float wy)
 {
   float l2 = ctx_pow2 (vx-wx) + ctx_pow2 (vy-wy);
-  if (l2 < 0.0001)
+  if (l2 < 0.0001f)
     { return ctx_pow2 (x-vx) + ctx_pow2 (y-vy); }
   float t = ( (x - vx) * (wx - vx) + (y - vy) * (wy - vy) ) / l2;
   t = ctx_maxf (0, ctx_minf (1, t) );
@@ -40111,8 +44162,8 @@ ctx_arc_to (Ctx *ctx, float x1, float y1, float x2, float y2, float radius)
       // Handle degenerate cases.
       if (ctx_coords_equal (x0,y0, x1,y1, 0.5f) ||
           ctx_coords_equal (x1,y1, x2,y2, 0.5f) ||
-          ctx_point_seg_dist_sq (x1,y1, x0,y0, x2,y2) < 0.5 ||
-          radius < 0.5)
+          ctx_point_seg_dist_sq (x1,y1, x0,y0, x2,y2) < 0.5f ||
+          radius < 0.5f)
         {
           ctx_line_to (ctx, x1,y1);
           return;
@@ -40170,10 +44221,10 @@ ctx_exit (Ctx *ctx)
 }
 
 CTX_EXPORT void
-ctx_flush (Ctx *ctx)
+ctx_end_frame (Ctx *ctx)
 {
-  if (ctx->backend && ctx->backend->flush)
-    ctx->backend->flush (ctx);
+  if (ctx->backend && ctx->backend->end_frame)
+    ctx->backend->end_frame (ctx);
   ctx->frame++;
   if (ctx->texture_cache != ctx)
     ctx->texture_cache->frame++;
@@ -40189,6 +44240,15 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
   CtxCommand *c = (CtxCommand *) entry;
   switch (entry->code)
     {
+      case CTX_LINE_HEIGHT:
+        ctx_state_set (state, CTX_lineHeight, ctx_arg_float (0) );
+        break;
+      case CTX_WRAP_LEFT:
+        ctx_state_set (state, CTX_wrapLeft, ctx_arg_float (0) );
+        break;
+      case CTX_WRAP_RIGHT:
+        ctx_state_set (state, CTX_wrapRight, ctx_arg_float (0) );
+        break;
       case CTX_LINE_DASH_OFFSET:
         state->gstate.line_dash_offset = ctx_arg_float (0);
         break;
@@ -40225,13 +44285,13 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
         state->gstate.extend = (CtxExtend) ctx_arg_u32 (0);
         break;
       case CTX_TEXT_ALIGN:
-        ctx_state_set (state, CTX_text_align, ctx_arg_u8 (0) );
+        ctx_state_set (state, CTX_textAlign, ctx_arg_u8 (0) );
         break;
       case CTX_TEXT_BASELINE:
-        ctx_state_set (state, CTX_text_baseline, ctx_arg_u8 (0) );
+        ctx_state_set (state, CTX_textBaseline, ctx_arg_u8 (0) );
         break;
       case CTX_TEXT_DIRECTION:
-        ctx_state_set (state, CTX_text_direction, ctx_arg_u8 (0) );
+        ctx_state_set (state, CTX_textDirection, ctx_arg_u8 (0) );
         break;
       case CTX_GLOBAL_ALPHA:
         state->gstate.global_alpha_u8 = ctx_float_to_u8 (ctx_arg_float (0) );
@@ -40256,6 +44316,10 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
         state->source = 1;
         break;
 
+      case CTX_FONT:
+        state->gstate.font = ctx_resolve_font (ctx_arg_string());
+        break;
+
       case CTX_COLOR:
         {
           int is_stroke = (state->source != 0);
@@ -40349,7 +44413,7 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
           source->linear_gradient.dy = dy;
           source->linear_gradient.start = start;
           source->linear_gradient.end = end;
-          source->linear_gradient.rdelta = (end-start)!=0.0?1.0f/(end - start):1.0;
+          source->linear_gradient.rdelta = (end-start)!=0.0f?1.0f/(end - start):1.0f;
           source->type = CTX_SOURCE_LINEAR_GRADIENT;
           source->transform = state->gstate.transform;
           ctx_matrix_invert (&source->transform);
@@ -40375,7 +44439,7 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
           source->radial_gradient.x1 = x1;
           source->radial_gradient.y1 = y1;
           source->radial_gradient.r1 = r1;
-          source->radial_gradient.rdelta = (r1 - r0) != 0.0 ? 1.0f/(r1-r0):0.0;
+          source->radial_gradient.rdelta = (r1 - r0) != 0.0f ? 1.0f/(r1-r0):0.0f;
           source->type      = CTX_SOURCE_RADIAL_GRADIENT;
           source->transform = state->gstate.transform;
           ctx_matrix_invert (&source->transform);
@@ -40397,17 +44461,25 @@ ctx_interpret_transforms (CtxState *state, CtxEntry *entry, void *data)
         break;
       case CTX_IDENTITY:
         _ctx_matrix_identity (&state->gstate.transform);
+        //state->gstate.transform_type = 0;
+        _ctx_transform_prime (state);
         break;
       case CTX_TRANSLATE:
         ctx_matrix_translate (&state->gstate.transform,
                               ctx_arg_float (0), ctx_arg_float (1) );
+        //state->gstate.transform_type = 0;
+        _ctx_transform_prime (state);
         break;
       case CTX_SCALE:
         ctx_matrix_scale (&state->gstate.transform,
                           ctx_arg_float (0), ctx_arg_float (1) );
+        //state->gstate.transform_type = 0;
+        _ctx_transform_prime (state);
         break;
       case CTX_ROTATE:
         ctx_matrix_rotate (&state->gstate.transform, ctx_arg_float (0) );
+        //state->gstate.transform_type = 0;
+        _ctx_transform_prime (state);
         break;
       case CTX_APPLY_TRANSFORM:
         {
@@ -40420,6 +44492,8 @@ ctx_interpret_transforms (CtxState *state, CtxEntry *entry, void *data)
                           ctx_arg_float (8));
           _ctx_matrix_multiply (&state->gstate.transform,
                                 &state->gstate.transform, &m); // XXX verify order
+          // state->gstate.transform_type = 0;
+          _ctx_transform_prime (state);
         }
 #if 0
         ctx_matrix_set (&state->gstate.transform,
@@ -40616,7 +44690,7 @@ ctx_interpret_pos_bare (CtxState *state, CtxEntry *entry, void *data)
 {
   switch (entry->code)
     {
-      case CTX_RESET:
+      case CTX_START_FRAME:
         ctx_state_init (state);
         state->has_moved = 0;
         break;
@@ -40681,6 +44755,10 @@ void ctx_colorspace_babl (CtxState   *state,
                           const Babl *space);
 #endif
 
+#ifndef CTX_TEXT_WRAP
+#define CTX_TEXT_WRAP 1
+#endif
+
 static void
 ctx_state_init (CtxState *state)
 {
@@ -40692,7 +44770,12 @@ ctx_state_init (CtxState *state)
   state->gstate.image_smoothing = 1;
   state->gstate.source_stroke.type = CTX_SOURCE_INHERIT_FILL;
   ctx_color_set_graya (state, &state->gstate.source_fill.color, 1.0f, 1.0f);
-  ctx_state_set (state, CTX_line_spacing, 1.0f);
+  ctx_state_set (state, CTX_lineHeight, 1.0f);
+#if CTX_TEXT_WRAP
+  ctx_state_set (state, CTX_wrapLeft, 0.0f);
+  ctx_state_set (state, CTX_wrapRight, 0.0f);
+#endif
+
   state->ink_min_x              = 8192;
   state->ink_min_y              = 8192;
   state->ink_max_x              = -8192;
@@ -40710,6 +44793,7 @@ void _ctx_set_transformation (Ctx *ctx, int transformation)
 {
   ctx->transformation = transformation;
 }
+static void ctx_setup (Ctx *ctx);
 
 #if CTX_SIMD
 void ctx_simd_setup (void);
@@ -40718,9 +44802,13 @@ static void
 _ctx_init (Ctx *ctx)
 {
   static int done_first_run = 0;
+  ctx_setup (ctx);
 
   if (!done_first_run)
   {
+#if CTX_BABL
+    babl_init ();
+#endif
     done_first_run = 1;
 #if CTX_SIMD
     ctx_simd_setup ();
@@ -40733,8 +44821,8 @@ _ctx_init (Ctx *ctx)
     if (getenv ("CTX_SHAPE_CACHE"))
     {
       const char * val = getenv ("CTX_SHAPE_CACHE");
-      if (!strcmp (val, "0") ||
-          !strcmp (val, "off"))
+      if (!ctx_strcmp (val, "0") ||
+          !ctx_strcmp (val, "off"))
         _ctx_shape_cache_enabled = 0;
       else
         _ctx_shape_cache_enabled = 1;
@@ -40753,19 +44841,42 @@ _ctx_init (Ctx *ctx)
   ctx->drawlist.flags |= CTX_TRANSFORMATION_BITPACK;
 #endif
   ctx->texture_cache = ctx;
+
+  ctx->fonts = ctx_fonts;
 }
 
-static void ctx_setup (void);
 
 #if CTX_DRAWLIST_STATIC
 static Ctx ctx_state;
 #endif
 
+void ctx_push_backend (Ctx *ctx,
+                       void *backend)
+{
+  if (ctx->backend_pushed)
+    fprintf (stderr, "double push\n");
+  ctx->backend_pushed = ctx->backend;
+  ctx->backend = (CtxBackend*)backend;
+  if (ctx->backend->process == NULL)
+    ctx->backend->process = (void(*)(Ctx*,CtxCommand*))ctx_drawlist_process;
+}
+
+
+void ctx_pop_backend (Ctx *ctx)
+{
+  if (!ctx->backend_pushed)
+    fprintf (stderr, "backend pop without push\n");
+  if (ctx->backend && ctx->backend->destroy)
+    ctx->backend->destroy (ctx->backend);
+  ctx->backend = ctx->backend_pushed;
+  ctx->backend_pushed = NULL;
+}
+
 void ctx_set_backend (Ctx  *ctx,
                        void *backend)
 {
-  if (ctx->backend && ctx->backend->free)
-    ctx->backend->free (ctx->backend);
+  if (ctx->backend && ctx->backend->destroy)
+    ctx->backend->destroy (ctx->backend);
   ctx->backend = (CtxBackend*)backend;
   if (ctx->backend->process == NULL)
     ctx->backend->process = (void(*)(Ctx*,CtxCommand*))ctx_drawlist_process;
@@ -40780,11 +44891,10 @@ void *ctx_get_backend (Ctx *ctx)
 static Ctx *
 _ctx_new_drawlist (int width, int height)
 {
-  ctx_setup ();
 #if CTX_DRAWLIST_STATIC
   Ctx *ctx = &ctx_state;
 #else
-  Ctx *ctx = (Ctx *) malloc (sizeof (Ctx) );
+  Ctx *ctx = (Ctx *) ctx_malloc (sizeof (Ctx) );
 #endif
   ctx_memset (ctx, 0, sizeof (Ctx) );
   _ctx_init (ctx);
@@ -40800,11 +44910,15 @@ ctx_new_drawlist (int width, int height)
   return _ctx_new_drawlist (width, height);
 }
 
+#if CTX_EVENTS
+static Ctx *ctx_new_ui (int width, int height, const char *backend);
+#endif
+
 CTX_EXPORT Ctx *
 ctx_new (int width, int height, const char *backend)
 {
 #if CTX_EVENTS
-  if (backend && !strcmp (backend, "drawlist"))
+  if (backend && !ctx_strcmp (backend, "drawlist"))
 #endif
   {
     return _ctx_new_drawlist (width, height);
@@ -40821,7 +44935,7 @@ ctx_drawlist_deinit (CtxDrawlist *drawlist)
 #if !CTX_DRAWLIST_STATIC
   if (drawlist->entries && ! (drawlist->flags & CTX_DRAWLIST_DOESNT_OWN_ENTRIES) )
     {
-      free (drawlist->entries); 
+      ctx_free (drawlist->entries); 
     }
 #endif
   drawlist->entries = NULL;
@@ -40835,11 +44949,10 @@ static void ctx_deinit (Ctx *ctx)
   ctx_events_deinit (ctx);
 #endif
 
-
   if (ctx->backend)
     {
-      if (ctx->backend->free)
-        ctx->backend->free (ctx->backend);
+      if (ctx->backend->destroy)
+        ctx->backend->destroy (ctx->backend);
       ctx->backend    = NULL;
     }
   ctx_drawlist_deinit (&ctx->drawlist);
@@ -40852,7 +44965,7 @@ static void ctx_deinit (Ctx *ctx)
 }
 
 CTX_EXPORT void
-ctx_free (Ctx *ctx)
+ctx_destroy (Ctx *ctx)
 {
   if (!ctx)
     { return; }
@@ -40867,7 +44980,7 @@ ctx_free (Ctx *ctx)
 #endif
   ctx_deinit (ctx);
 #if !CTX_DRAWLIST_STATIC
-  free (ctx);
+  ctx_free (ctx);
 #endif
 }
 
@@ -40883,9 +44996,9 @@ ctx_new_for_drawlist (int width, int height, void *data, size_t length)
 }
 
 
-static void ctx_setup (void)
+static void ctx_setup (Ctx *ctx)
 {
-  ctx_font_setup ();
+  ctx_font_setup (ctx);
 }
 
 void
@@ -40893,6 +45006,7 @@ ctx_render_ctx (Ctx *ctx, Ctx *d_ctx)
 {
   CtxIterator iterator;
   CtxCommand *command;
+  ctx->bail = 0;
   ctx_iterator_init (&iterator, &ctx->drawlist, 0,
                      CTX_ITERATOR_EXPAND_BITPACK);
   while ( (command = ctx_iterator_next (&iterator) ) )
@@ -40903,16 +45017,13 @@ ctx_render_ctx (Ctx *ctx, Ctx *d_ctx)
 
 
 void
-ctx_render_ctx_masked (Ctx *ctx, Ctx *d_ctx, CtxCommandState *active_list, int count, uint32_t mask)
+ctx_render_ctx_masked (Ctx *ctx, Ctx *d_ctx, uint32_t mask)
 {
   CtxIterator iterator;
   CtxCommand *command;
   ctx_iterator_init (&iterator, &ctx->drawlist, 0,
                      CTX_ITERATOR_EXPAND_BITPACK);
 
-  unsigned int pos = 0;
-
-  int l = 0;
   uint32_t active_mask = 0xffffffff;
 
   while ( (command = ctx_iterator_next (&iterator) ) )
@@ -40920,17 +45031,15 @@ ctx_render_ctx_masked (Ctx *ctx, Ctx *d_ctx, CtxCommandState *active_list, int c
        d_ctx->bail = ((active_mask & mask) == 0);
        ctx_process (d_ctx, &command->entry);
 
-       if (l < count)
-       do {
-         active_mask = active_list[l].active;
-         if (active_list[l].pos <= pos )
-         {
-           l++;
-         }
-         else break;
-       } while (l < count);
-
-       pos += ctx_conts_for_entry ((CtxEntry*)command)+1;
+       switch (command->code)
+       {
+         case CTX_FILL:
+         case CTX_STROKE:
+         case CTX_CLIP:
+         case CTX_TEXT:
+         case CTX_GLYPH:
+           active_mask = command->entry.data.u32[1];
+       }
     }
 }
 
@@ -41064,7 +45173,7 @@ char *ctx_get_clipboard (Ctx *ctx)
   {
     return ctx->backend->get_clipboard (ctx);
   }
-  return strdup ("");
+  return ctx_strdup ("");
 }
 
 void ctx_set_texture_source (Ctx *ctx, Ctx *texture_source)
@@ -41110,7 +45219,7 @@ ctx_get_contents2 (const char     *uri,
 
   if (uri[0] == '/')
   {
-    temp_uri = (char*) malloc (strlen (uri) + 8);
+    temp_uri = (char*) ctx_malloc (ctx_strlen (uri) + 8);
     sprintf (temp_uri, "file://%s", uri);
     uri = temp_uri;
   }
@@ -41121,12 +45230,12 @@ ctx_get_contents2 (const char     *uri,
   for (CtxList *l = registered_contents; l; l = l->next)
   {
     CtxFileContent *c = (CtxFileContent*)l->data;
-    if (!strcmp (c->path, uri))
+    if (!ctx_strcmp (c->path, uri))
     {
-      contents = malloc (c->length+1);
+      contents = ctx_malloc (c->length+1);
       contents[c->length]=0;
       if (length) *length = c->length;
-      free (temp_uri);
+      ctx_free (temp_uri);
       return 0;
     }
   }
@@ -41174,7 +45283,7 @@ ctx_get_contents2 (const char     *uri,
     success = ___ctx_file_get_contents (uri, contents, length, max_len);
 #endif
   }
-  free (temp_uri);
+  ctx_free (temp_uri);
   return success;
 }
 
@@ -41190,6 +45299,7 @@ ctx_get_contents (const char     *uri,
 
 
 typedef struct CtxMagicEntry {
+  int is_text;
   const char *mime_type;
   const char *ext1;
   int len;
@@ -41197,74 +45307,74 @@ typedef struct CtxMagicEntry {
 } CtxMagicEntry;
 
 static CtxMagicEntry ctx_magics[]={
-  {"image/bmp",  ".bmp", 0, {0}},
-  {"image/png",  ".png", 8, {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a}},
-  {"image/jpeg", ".jpg", 8,  {0xff, 0xd8, 0xff, 0xdb, 0xff, 0xd8, 0xff, 0xe0}},
-  {"image/jpeg", ".jpg", 4,  {0xff, 0xd8, 0xff, 0xe0}},
-  {"image/jpeg", ".jpg", 4,  {0xff, 0xd8, 0xff, 0xee}},
-  {"image/jpeg", ".jpg", 4,  {0xff, 0xd8, 0xff, 0xe1}},
-  {"image/jpeg", ".jpeg", 8, {0xff, 0xd8, 0xff, 0xdb, 0xff, 0xd8, 0xff, 0xe0}},
-
-  {"image/psd", ".psd", 4,  {0x38, 0x42, 0x50, 0x53}},
-  {"image/tinyvg", ".tvg", 3, {0x72, 0x56, 1}}, 
-  {"image/gif",  ".gif", 6, {0x47, 0x49, 0x46, 0x38, 0x37, 0x61}},
-  {"image/gif",  ".gif", 6, {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}},
-  {"image/exr",  ".exr", 4, {0x76, 0x2f, 0x31, 0x01}},
-  {"video/mpeg", ".mpg", 4, {0x00, 0x00, 0x01, 0xba}},
-  {"application/blender", ".blend", 8, {0x42, 0x4c,0x45,0x4e,0x44,0x45,0x52}},
-  {"image/xcf",  ".xcf", 8, {0x67, 0x69,0x6d,0x70,0x20,0x78,0x63,0x66}},
-  {"application/bzip2", ".bz2", 3, {0x42, 0x5a, 0x68}},
-  {"application/gzip", ".gz", 2, {0x1f, 0x8b}},
-  {"application/zip", ".zip", 4, {0x50, 0x4b, 0x03, 0x04}},
-  {"application/zip", ".zip", 4, {0x50, 0x4b, 0x05, 0x06}},
-  {"application/rar", ".rar", 6, {0x52, 0x61, 0x72, 0x1a, 0x07, 0x00}},
-  {"application/rar", ".rar", 7, {0x52, 0x61, 0x72, 0x1a, 0x07, 0x01, 0x00}},
-  {"text/x-csrc", ".c", 0, {0,}},
-  {"text/x-chdr", ".h", 0, {0,}},
-  {"text/css", ".css", 0, {0x0}},
-
-  {"application/gzip", ".z", 2, {0x1f, 0x9d}},
-
-  {"application/dos-mz", ".exe", 2, {0x4d, 0x5a}},
-
-  {"text/csv", ".csv", 0, {0x0}},
-  {"text/html", ".htm", 0, {0x0}},
-  {"text/html", ".html", 0, {0x0}},
-  {"text/x-makefile", "makefile", 0, {0x0}},
-  {"application/atom+xml", ".atom", 0, {0x0}},
-  {"application/rdf+xml", ".rdf", 0, {0x0}},
-  {"application/javascript", ".js", 0, {0x0}},
-  {"application/json", ".json", 0, {0x0}},
-  {"application/octet-stream", ".bin", 0, {0x0}},
-  {"application/x-object", ".o", 0, {0x0}},
-  {"text/utf-8", ".txt", 0, {0xef, 0xbb, 0xbf}}, // utf8 bom
-  {"text/x-sh", ".sh", 0, {0x0}},
-  {"text/x-python", ".py", 0, {0x0}},
-  {"text/x-perl", ".pl", 0, {0x0}},
-  {"text/x-perl", ".pm", 0, {0x0}},
-  {"application/x-shellscript", ".sh", 2, {0x23, 0x21}}, // #!
-  {"application/pdf", ".pdf", 0, {0x0}},
-  {"application/ctx", ".ctx", 0, {0x0}},
-  {"application/wasm", ".wasm", 0, {0x00, 0x61, 0x73, 0x6d}},
-  {"text/xml", ".xml",     0, {0x0}},
-  {"video/mp4", ".mp4",    7, {0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f}},
-  {"video/matroska", ".mkv", 4, {0x1a, 0x45, 0xdf, 0xa3}},
-  {"video/ogg", ".ogv",    0, {0x0}},
-  {"audio/flac", ".flac",  0, {0x66, 0x4c, 0x61, 0x43}},
-  {"audio/sp-midi", ".mid",  4, {0x4d, 0x54, 0x68, 0x64}},
-  {"audio/x-wav", ".wav",  4, {0x52, 0x49, 0x46, 0x46}},
-  {"audio/ogg", ".ogg",    4, {0x4f, 0x67, 0x67, 0x53}},
-  {"audio/ogg", ".opus",   0, {0x0}},
-  {"audio/ogg", ".oga",    0, {0x0}},
-  {"audio/mpeg", ".mp1",   0, {0x0}},
-  {"audio/m3u", ".m3u",    0, {0x0}},
-  {"audio/mpeg", ".mp2",   0, {0x0}},
-  {"audio/mpeg", ".mp3",   0, {0x0}},
-  {"audio/mpeg", ".m4a",   0, {0x0}},
-  {"audio/mpeg", ".mpga",  0, {0x0}},
-  {"audio/mpeg", ".mpega", 0, {0x0}},
-  {"font/otf", ".otf", 0,{0x0}},
-  {"font/ttf", ".ttf", 5,{0x0, 0x01, 0x00, 0x00, 0x00}},
+  {0, "image/bmp",  ".bmp", 0, {0}},
+  {0, "image/png",  ".png", 8, {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a}},
+  {0, "image/jpeg", ".jpg", 8,  {0xff, 0xd8, 0xff, 0xdb, 0xff, 0xd8, 0xff, 0xe0}},
+  {0, "image/jpeg", ".jpg", 4,  {0xff, 0xd8, 0xff, 0xe0}},
+  {0, "image/jpeg", ".jpg", 4,  {0xff, 0xd8, 0xff, 0xee}},
+  {0, "image/jpeg", ".jpg", 4,  {0xff, 0xd8, 0xff, 0xe1}},
+  {0, "image/jpeg", ".jpeg", 8, {0xff, 0xd8, 0xff, 0xdb, 0xff, 0xd8, 0xff, 0xe0}},
+
+  {0, "image/psd", ".psd", 4,  {0x38, 0x42, 0x50, 0x53}},
+  {0, "image/tinyvg", ".tvg", 3, {0x72, 0x56, 1}}, 
+  {0, "image/gif",  ".gif", 6, {0x47, 0x49, 0x46, 0x38, 0x37, 0x61}},
+  {0, "image/gif",  ".gif", 6, {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}},
+  {0, "image/exr",  ".exr", 4, {0x76, 0x2f, 0x31, 0x01}},
+  {0, "video/mpeg", ".mpg", 4, {0x00, 0x00, 0x01, 0xba}},
+  {0, "application/blender", ".blend", 8, {0x42, 0x4c,0x45,0x4e,0x44,0x45,0x52}},
+  {0, "image/xcf",  ".xcf", 8, {0x67, 0x69,0x6d,0x70,0x20,0x78,0x63,0x66}},
+  {0, "application/bzip2", ".bz2", 3, {0x42, 0x5a, 0x68}},
+  {0, "application/gzip", ".gz", 2, {0x1f, 0x8b}},
+  {0, "application/zip", ".zip", 4, {0x50, 0x4b, 0x03, 0x04}},
+  {0, "application/zip", ".zip", 4, {0x50, 0x4b, 0x05, 0x06}},
+  {0, "application/rar", ".rar", 6, {0x52, 0x61, 0x72, 0x1a, 0x07, 0x00}},
+  {0, "application/rar", ".rar", 7, {0x52, 0x61, 0x72, 0x1a, 0x07, 0x01, 0x00}},
+  {1, "text/x-csrc", ".c", 0, {0,}},
+  {1, "text/x-chdr", ".h", 0, {0,}},
+  {1, "text/css", ".css", 0, {0x0}},
+
+  {0, "application/gzip", ".z", 2, {0x1f, 0x9d}},
+
+  {0, "application/dos-mz", ".exe", 2, {0x4d, 0x5a}},
+
+  {1, "text/csv", ".csv", 0, {0x0}},
+  {1, "text/html", ".htm", 0, {0x0}},
+  {1, "text/html", ".html", 0, {0x0}},
+  {1, "text/x-makefile", "makefile", 0, {0x0}},
+  {1, "application/atom+xml", ".atom", 0, {0x0}},
+  {1, "application/rdf+xml", ".rdf", 0, {0x0}},
+  {1, "application/javascript", ".js", 0, {0x0}},
+  {1, "application/json", ".json", 0, {0x0}},
+  {0, "application/octet-stream", ".bin", 0, {0x0}},
+  {0, "application/x-object", ".o", 0, {0x0}},
+  {1, "text/utf-8", ".txt", 0, {0xef, 0xbb, 0xbf}}, // utf8 bom
+  {1, "text/x-sh", ".sh", 0, {0x0}},
+  {1, "text/x-python", ".py", 0, {0x0}},
+  {1, "text/x-perl", ".pl", 0, {0x0}},
+  {1, "text/x-perl", ".pm", 0, {0x0}},
+  {1, "application/x-shellscript", ".sh", 2, {0x23, 0x21}}, // #!
+  {0, "application/pdf", ".pdf", 0, {0x0}},
+  {0, "application/ctx", ".ctx", 0, {0x0}},
+  {0, "application/wasm", ".wasm", 0, {0x00, 0x61, 0x73, 0x6d}},
+  {1, "text/xml", ".xml",     0, {0x0}},
+  {0, "video/mp4", ".mp4",    7, {0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f}},
+  {0, "video/matroska", ".mkv", 4, {0x1a, 0x45, 0xdf, 0xa3}},
+  {0, "video/ogg", ".ogv",    0, {0x0}},
+  {0, "audio/flac", ".flac",  0, {0x66, 0x4c, 0x61, 0x43}},
+  {0, "audio/sp-midi", ".mid",  4, {0x4d, 0x54, 0x68, 0x64}},
+  {0, "audio/x-wav", ".wav",  4, {0x52, 0x49, 0x46, 0x46}},
+  {0, "audio/ogg", ".ogg",    4, {0x4f, 0x67, 0x67, 0x53}},
+  {0, "audio/ogg", ".opus",   0, {0x0}},
+  {0, "audio/ogg", ".oga",    0, {0x0}},
+  {0, "audio/mpeg", ".mp1",   0, {0x0}},
+  {0, "audio/m3u", ".m3u",    0, {0x0}},
+  {0, "audio/mpeg", ".mp2",   0, {0x0}},
+  {0, "audio/mpeg", ".mp3",   0, {0x0}},
+  {0, "audio/mpeg", ".m4a",   0, {0x0}},
+  {0, "audio/mpeg", ".mpga",  0, {0x0}},
+  {0, "audio/mpeg", ".mpega", 0, {0x0}},
+  {0, "font/otf", ".otf", 0,{0x0}},
+  {0, "font/ttf", ".ttf", 5,{0x0, 0x01, 0x00, 0x00, 0x00}},
   // inode-directory
 };
 
@@ -41291,16 +45401,16 @@ const char *ctx_guess_media_type (const char *path, const char *content, int len
   ctx_media_matched_content = 0;
   if (path && strrchr (path, '.'))
   {
-    char *pathdup = strdup (strrchr(path, '.'));
+    char *pathdup = ctx_strdup (strrchr(path, '.'));
     for (int i = 0; pathdup[i]; i++) pathdup[i]=tolower(pathdup[i]);
     for (unsigned int i = 0; i < sizeof (ctx_magics)/sizeof(ctx_magics[0]);i++)
     {
-      if (ctx_magics[i].ext1 && !strcmp (ctx_magics[i].ext1, pathdup))
+      if (ctx_magics[i].ext1 && !ctx_strcmp (ctx_magics[i].ext1, pathdup))
       {
         extension_match = ctx_magics[i].mime_type;
       }
     }
-    free (pathdup);
+    ctx_free (pathdup);
   }
 
   if (len > 16)
@@ -41316,9 +45426,8 @@ const char *ctx_guess_media_type (const char *path, const char *content, int len
     }
   }
 
-  if (extension_match && !strcmp (extension_match, "application/ctx"))
+  if (extension_match && !ctx_strcmp (extension_match, "application/ctx"))
   {
-          fprintf (stderr, "!!\n");
     //if (!ctx_path_is_exec (path))
     //  extension_match = NULL;
   }
@@ -41356,17 +45465,17 @@ const char *ctx_path_get_media_type (const char *path)
   /* XXX : code duplication, factor out in separate fun */
   if (path && strrchr (path, '.'))
   {
-    char *pathdup = strdup (strrchr(path, '.'));
+    char *pathdup = ctx_strdup (strrchr(path, '.'));
     for (int i = 0; pathdup[i]; i++) pathdup[i]=tolower(pathdup[i]);
     for (unsigned int i = 0; i < sizeof (ctx_magics)/sizeof(ctx_magics[0]);i++)
     {
-      if (ctx_magics[i].ext1 && !strcmp (ctx_magics[i].ext1, pathdup))
+      if (ctx_magics[i].ext1 && !ctx_strcmp (ctx_magics[i].ext1, pathdup))
       {
-        free (pathdup);
+        ctx_free (pathdup);
         return ctx_magics[i].mime_type;
       }
     }
-    free (pathdup);
+    ctx_free (pathdup);
   }
 #endif
   if (ctx_path_is_dir (path))
@@ -41376,12 +45485,25 @@ const char *ctx_path_get_media_type (const char *path)
   if (content)
   {
   const char *guess = ctx_guess_media_type (path, content, length);
-  free (content);
+  ctx_free (content);
   return guess;
   }
   return "application/none";
 }
 
+int ctx_media_type_is_text (const char *media_type)
+{
+  for (unsigned int i = 0; i < sizeof (ctx_magics)/sizeof(ctx_magics[0]);i++)
+    if (media_type == ctx_magics[i].mime_type)
+       return ctx_magics[i].is_text;
+  for (unsigned int i = 0; i < sizeof (ctx_magics)/sizeof(ctx_magics[0]);i++)
+    if (!strcmp (media_type,  ctx_magics[i].mime_type))
+       return ctx_magics[i].is_text;
+  if (!strcmp (media_type, "text/plain"))
+    return 1;
+  return 0;
+}
+
 CtxMediaTypeClass ctx_media_type_class (const char *media_type)
 {
   CtxMediaTypeClass ret = CTX_MEDIA_TYPE_NONE;
@@ -41492,35 +45614,35 @@ CtxBackendType ctx_backend_type (Ctx *ctx)
   CtxBackend *backend = ctx->backend;
   if (backend == NULL)
     return CTX_BACKEND_NONE;
-#if CTX_EVENTS
-  else if (backend->free == (void*) ctx_ctx_free) return CTX_BACKEND_CTX;
+#if CTX_TERMINAL_EVENTS
+  else if (backend->destroy == (void*) ctx_ctx_destroy) return CTX_BACKEND_CTX;
+#if CTX_HEADLESS
+  else if (backend->destroy == (void*) ctx_headless_destroy) return CTX_BACKEND_HEADLESS;
 #endif
-#if CTX_TERM
-  else if (backend->free == (void*) ctx_term_free) return CTX_BACKEND_TERM;
 #endif
-#if CTX_HEADLESS
-  else if (backend->free == (void*) ctx_headless_free) return CTX_BACKEND_HEADLESS;
+#if CTX_TERMINAL_EVENTS
+  else if (backend->destroy == (void*) ctx_term_destroy) return CTX_BACKEND_TERM;
 #endif
 #if CTX_RASTERIZER
   else if (backend->process == (void*) ctx_hasher_process) return CTX_BACKEND_HASHER;
 #endif
 #if CTX_RASTERIZER
-  else if (backend->free == (void*) ctx_rasterizer_deinit) return CTX_BACKEND_RASTERIZER;
+  else if (backend->destroy == (void*) ctx_rasterizer_destroy) return CTX_BACKEND_RASTERIZER;
 #endif
 #if CTX_KMS
-  else if (backend->free == (void*) ctx_kms_free) return CTX_BACKEND_KMS;
+  else if (backend->destroy == (void*) ctx_kms_destroy) return CTX_BACKEND_KMS;
 #endif
 #if CTX_FB
-  else if (backend->free == (void*) ctx_fb_free) return CTX_BACKEND_FB;
+  else if (backend->destroy == (void*) ctx_fb_destroy) return CTX_BACKEND_FB;
 #endif
 #if CTX_SDL
-  else if (backend->free == (void*) ctx_sdl_free) return CTX_BACKEND_SDL;
+  else if (backend->destroy == (void*) ctx_sdl_destroy) return CTX_BACKEND_SDL;
 #endif
 #if CTX_CAIRO
-  else if (backend->free == (void*) ctx_cairo_free) return CTX_BACKEND_CAIRO;
+  else if (backend->destroy == (void*) ctx_cairo_destroy) return CTX_BACKEND_CAIRO;
 #endif
-#if CTX_TERMIMG
-  else if (backend->free == (void*) ctx_termimg_free) return CTX_BACKEND_TERMIMG;
+#if CTX_TERMINAL_EVENTS
+  else if (backend->destroy == (void*) ctx_termimg_destroy) return CTX_BACKEND_TERMIMG;
 #endif
   return CTX_BACKEND_NONE;
 }
@@ -41603,7 +45725,7 @@ void (*ctx_composite_fill_rect) (CtxRasterizer *rasterizer,
 #endif
 
 
-CTX_EXPORT void
+CTX_EXPORT  void
 ctx_logo (Ctx *ctx, float x, float y, float dim)
 {
      //float width = ctx_width (ctx);
@@ -41615,59 +45737,64 @@ ctx_logo (Ctx *ctx, float x, float y, float dim)
      //if (width < height) height = width;
      
      ctx_scale (ctx, dim, dim);
-     ctx_translate (ctx, -0.5, -0.5);
+     ctx_translate (ctx, -0.5f, -0.5f);
      ctx_begin_path (ctx);
-     ctx_rgba(ctx,1,1,1,0.4);
-     ctx_move_to(ctx,0.43956786,0.90788066);
-     ctx_rel_curve_to(ctx,0.0195929,0.0102943,0.0716181,0.0218038,0.10361884,-0.0167646);
-     ctx_line_to (ctx,0.93768705,0.37887837);
-     ctx_rel_curve_to (ctx,  0.019925 ,-0.0342044,-0.00963,-0.0544608,-0.0308834,-0.0508084);
-     ctx_rel_curve_to (ctx,-0.17965502,0.0285588,-0.35466092,-0.055125,-0.45096394,-0.21253089);
-     ctx_rel_curve_to (ctx, -0.0176003 ,-0.02988716, -0.0594422,-0.01560777,-0.0594422,0.0139473);
-     ctx_rel_curve_to (ctx, 0, 0.0591101,0.003321,0.49845135,0.001991, 0.70699722);
-     ctx_rel_curve_to (ctx, 0.00039042, 0.0283487,0.0157362 ,0.0529866,0.0408456,0.070733);
+     ctx_rgba(ctx,1,1,1,0.4f);
+     ctx_move_to(ctx,0.43956786f,0.90788066f);
+     ctx_rel_curve_to(ctx,0.0195929f,0.0102943f,0.0716181f,0.0218038f,0.10361884f,-0.0167646f);
+     ctx_line_to (ctx,0.93768705f,0.37887837f);
+     ctx_rel_curve_to (ctx,  0.019925f,-0.0342044f,-0.00963f,-0.0544608f,-0.0308834f,-0.0508084f);
+     ctx_rel_curve_to (ctx,-0.17965502f,0.0285588f,-0.35466092f,-0.055125f,-0.45096394f,-0.21253089f);
+     ctx_rel_curve_to (ctx, -0.0176003f,-0.02988716f, -0.0594422f,-0.01560777f,-0.0594422f,0.0139473f);
+     ctx_rel_curve_to (ctx, 0, 0.0591101f,0.003321f,0.49845135f,0.001991f, 0.70699722f);
+     ctx_rel_curve_to (ctx, 0.00039042f, 0.0283487f,0.0157362f,0.0529866f,0.0408456f,0.070733f);
      ctx_fill (ctx);
 
-     ctx_move_to (ctx, 0.39772584,0.91850721);
-     ctx_rel_line_to (ctx, -0.0664159, 0);
-     ctx_rel_curve_to (ctx, -0.15408489,0, -0.27894675,-0.12486192, -0.27894675,-0.2789468);
-     ctx_rel_curve_to (ctx, 0,-0.15408489, 0.12486186,-0.27861466, 0.27894675,-0.27894675);
-     ctx_rel_line_to (ctx, 0.18585599,0.0000662);
-     ctx_rel_curve_to (ctx, 0.0111839,0.00017138, 0.0158287,0.001542, 0.0263337,0.0134822);
-     ctx_rel_curve_to (ctx, 0.11733258,0.14373102, 0.3018009,0.36870115, 0.3942639,0.49195316);
-     ctx_rel_curve_to (ctx, 0.0185394,0.0332794, -0.0106225,0.0505515, -0.0228143,0.0505207);
-
-     ctx_linear_gradient (ctx, 0.0525, 0, 0.9905, 0);
-     ctx_gradient_add_stop (ctx, 0.0, 1.0, 1.0, 0.66, 1.0);
-     ctx_gradient_add_stop (ctx, 0.2, 1.0, 0.66, 0.0, 1.0);
-     ctx_gradient_add_stop (ctx, 0.5, 1.0, 0.0, 0.0, 1.0);
-     ctx_gradient_add_stop (ctx, 1.0, 0.4, 0.0, 0.53, 1.0);
+     ctx_move_to (ctx, 0.39772584f,0.91850721f);
+     ctx_rel_line_to (ctx, -0.0664159f, 0);
+     ctx_rel_curve_to (ctx, -0.15408489f,0, -0.27894675f,-0.12486192f, -0.27894675f,-0.2789468f);
+     ctx_rel_curve_to (ctx, 0,-0.15408489f, 0.12486186f,-0.27861466f, 0.27894675f,-0.27894675f);
+     ctx_rel_line_to (ctx, 0.18585599f,0.0000662f);
+     ctx_rel_curve_to (ctx, 0.0111839f,0.00017138f, 0.0158287f,0.001542f, 0.0263337f,0.0134822f);
+     ctx_rel_curve_to (ctx, 0.11733258f,0.14373102f, 0.3018009f,0.36870115f, 0.3942639f,0.49195316f);
+     ctx_rel_curve_to (ctx, 0.0185394f,0.0332794f, -0.0106225f,0.0505515f, -0.0228143f,0.0505207f);
+
+     ctx_linear_gradient (ctx, 0.0525f, 0, 0.9905f, 0);
+     ctx_gradient_add_stop (ctx, 0.0f, 1.0f, 1.0f, 0.66f, 1.0f);
+     ctx_gradient_add_stop (ctx, 0.2f, 1.0f, 0.66f, 0.0f, 1.0f);
+     ctx_gradient_add_stop (ctx, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f);
+     ctx_gradient_add_stop (ctx, 1.0f, 0.4f, 0.0f, 0.53f, 1.0f);
      ctx_fill (ctx);
      
 
 
-     ctx_linear_gradient(ctx, 0.697, 0.17, 0.4318, 0.884);
-     ctx_gradient_add_stop (ctx, 0, 0.26, 0.26, 1, 1.0);
-     ctx_gradient_add_stop (ctx, 0.3, 0, 1, 1, 0.4);
-     ctx_gradient_add_stop (ctx, 1.0, 0, 1, 0.26,1.0);
+     ctx_linear_gradient(ctx, 0.697f, 0.17f, 0.4318f, 0.884f);
+     ctx_gradient_add_stop (ctx, 0, 0.26f, 0.26f, 1, 1.0f);
+     ctx_gradient_add_stop (ctx, 0.3f, 0, 1, 1, 0.4f);
+     ctx_gradient_add_stop (ctx, 1.0f, 0, 1, 0.26f,1.0f);
      
-     ctx_move_to(ctx,0.43956786,0.90788066);
-     ctx_rel_curve_to(ctx,0.0195929,0.0102943,0.0716181,0.0218038,0.10361884,-0.0167646);
-     ctx_line_to (ctx,0.93768705,0.37887837);
-     ctx_rel_curve_to (ctx,  0.019925 ,-0.0342044,-0.00963,-0.0544608,-0.0308834,-0.0508084);
-     ctx_rel_curve_to (ctx,-0.17965502,0.0285588,-0.35466092,-0.055125,-0.45096394,-0.21253089);
-     ctx_rel_curve_to (ctx, -0.0176003 ,-0.02988716, -0.0594422,-0.01560777,-0.0594422,0.0139473);
-     ctx_rel_curve_to (ctx, 0, 0.0591101,0.003321,0.49845135,0.001991, 0.70699722);
-     ctx_rel_curve_to (ctx, 0.00039042, 0.0283487,0.0157362 ,0.0529866,0.0408456,0.070733);
+     ctx_move_to(ctx,0.43956786f,0.90788066f);
+     ctx_rel_curve_to(ctx,0.0195929f,0.0102943f,0.0716181f,0.0218038f,0.10361884f,-0.0167646f);
+     ctx_line_to (ctx,0.93768705f,0.37887837f);
+     ctx_rel_curve_to (ctx,  0.019925f,-0.0342044f,-0.00963f,-0.0544608f,-0.0308834f,-0.0508084f);
+     ctx_rel_curve_to (ctx,-0.17965502f,0.0285588f,-0.35466092f,-0.055125f,-0.45096394f,-0.21253089f);
+     ctx_rel_curve_to (ctx, -0.0176003f,-0.02988716f, -0.0594422f,-0.01560777f,-0.0594422f,0.0139473f);
+     ctx_rel_curve_to (ctx, 0, 0.0591101f,0.003321f,0.49845135f,0.001991f, 0.70699722f);
+     ctx_rel_curve_to (ctx, 0.00039042f, 0.0283487f,0.0157362f,0.0529866f,0.0408456f,0.070733f);
      ctx_fill (ctx);
      
      ctx_restore (ctx);
-
-  //ctx_parse (ctx, "rgb 1 0 0 rectangle 0 0 1000 1000 fill rgb 0 1 0 rectangle 40 40 40 40 fill ");
-//  ctx_free (ctx);
 }
 
-
+void
+ctx_CBRLE_decompress (const uint8_t *cbrle, uint8_t *rgba8, int width, int size);
+void
+ctx_CBRLE_decompress (const uint8_t *cbrle, uint8_t *rgba8, int width, int size)
+{
+#if CTX_ENABLE_CBRLE
+  _ctx_CBRLE_decompress (cbrle, rgba8, width, size, 0, width);
+#endif
+}
 /*
  * tinf - tiny inflate library (inflate, gzip, zlib)
  *
@@ -43040,7 +47167,7 @@ static inline void vt_line_set_style (VtLine *string, int pos, uint64_t style)
   if (pos >= string->style_size)
     {
       int new_size = pos + 16;
-      string->style = realloc (string->style, new_size * sizeof (uint64_t) );
+      string->style = ctx_realloc (string->style, string->style_size, new_size * sizeof (uint64_t) );
       memset (&string->style[string->style_size], 0, (new_size - string->style_size) * sizeof (uint64_t) );
       string->style_size = new_size;
     }
@@ -43061,11 +47188,11 @@ static inline void        vt_line_free           (VtLine *line, int freealloc)
     if (line->frame)
       ctx_string_free (line->frame, 1);
     if (line->style)
-      { free (line->style); }
+      { ctx_free (line->style); }
     if (line->ctx)
-      { ctx_free (line->ctx); }
+      { ctx_destroy (line->ctx); }
     if (line->ctx_copy)
-      { ctx_free (line->ctx_copy); }
+      { ctx_destroy (line->ctx_copy); }
   }
 #endif
 
@@ -43116,7 +47243,7 @@ static inline void _ctx_string_append_byte (CtxString *string, char  val)
     {
       char *old = string->str;
       string->allocated_length = CTX_MAX (string->allocated_length * 2, string->length + 2);
-      string->str = (char*)realloc (old, string->allocated_length);
+      string->str = (char*)ctx_realloc (old, string->allocated_length);
     }
   string->str[string->length++] = val;
   string->str[string->length] = '\0';
@@ -43233,12 +47360,12 @@ void ctx_string_init (CtxString *string, int initial_size);
 
 VtLine *vt_line_new_with_size (const char *initial, int initial_size)
 {
-  VtLine *line = calloc (sizeof (VtLine), 1);
+  VtLine *line = ctx_calloc (sizeof (VtLine), 1);
   CtxString *string = (CtxString*)line;
   ctx_string_init (string, initial_size);
   if (initial)
     { ctx_string_append_str (string, initial); }
-  line->style = calloc (sizeof (uint64_t), initial_size);
+  line->style = ctx_calloc (sizeof (uint64_t), initial_size);
   line->style_size = initial_size;
   string->is_line = 1;
   return line;
@@ -43500,6 +47627,7 @@ struct _VT
 };
 
 
+// add vt_new_cb - suitable for hooking up to generic stdout/stdin callbacks
 VT *vt_new (const char *command, int width, int height, float font_size, float line_spacing, int id, int 
can_launch);
 VT *vt_new_argv (char **argv, int width, int height, float font_size, float line_spacing, int id, int 
can_launch);
 VT *vt_new_thread (void (*start_routine)(void *userdata), void *userdata,
@@ -43755,7 +47883,7 @@ void vt_feed_audio (VT *vt, void *samples, int bytes)
   if (audio->compression == 'z')
   {
     unsigned long len = bytes * 1.2;//compressBound(bytes);
-    data = malloc (len);
+    data = ctx_malloc (len);
     int z_result = compress (data, &len, samples, len);
     if (z_result != Z_OK)
     {
@@ -43769,7 +47897,7 @@ void vt_feed_audio (VT *vt, void *samples, int bytes)
     }
   }
 
-  char *encoded = malloc (bytes * 2);
+  char *encoded = ctx_malloc (bytes * 2);
   encoded[0]=0;
   if (audio->encoding == 'a')
   {
@@ -43783,10 +47911,10 @@ void vt_feed_audio (VT *vt, void *samples, int bytes)
   sprintf (buf, "\033[_Af=%i;", frames);
   vt_write (vt, buf, strlen (buf));
   vt_write (vt, encoded, strlen(encoded));
-  free (encoded);
+  ctx_free (encoded);
 
   if (data != samples)
-    free (data);
+    ctx_free (data);
 
   //vt_write (vt, samples, bytes);
   buf[0]='\033';
@@ -44951,12 +49079,12 @@ void vt_audio (VT *vt, const char *command)
      if (audio->data == NULL)
      {
        audio->data_size = chunk_size;
-       audio->data = malloc (audio->data_size + 1);
+       audio->data = ctx_malloc (audio->data_size + 1);
      }
      else
      {
        audio->data_size += chunk_size;
-       audio->data = realloc (audio->data, audio->data_size + 1);
+       audio->data = ctx_realloc (audio->data, audio->data_size+1 - chunk_size, audio->data_size + 1);
      }
      memcpy (audio->data + old_size, payload, chunk_size);
      audio->data[audio->data_size]=0;
@@ -44973,7 +49101,7 @@ void vt_audio (VT *vt, const char *command)
         int bin_length = audio->data_size;
         if (bin_length)
         {
-        uint8_t *data2 = malloc ((unsigned int)ctx_a85len ((char*)audio->data, audio->data_size) + 1);
+        uint8_t *data2 = ctx_malloc ((unsigned int)ctx_a85len ((char*)audio->data, audio->data_size) + 1);
         // a85len is inaccurate but gives an upper bound,
         // should be fixed.
         bin_length = ctx_a85dec ((char*)audio->data,
@@ -44989,13 +49117,13 @@ void vt_audio (VT *vt, const char *command)
       case 'b':
       {
         int bin_length = audio->data_size;
-        uint8_t *data2 = malloc (audio->data_size);
+        uint8_t *data2 = ctx_malloc (audio->data_size);
         bin_length = ctx_base642bin ((char*)audio->data,
                                      &bin_length,
                                      data2);
         memcpy (audio->data, data2, bin_length + 1);
         audio->data_size = bin_length;
-        free (data2);
+        ctx_free (data2);
       }
       break;
     }
@@ -45011,7 +49139,7 @@ void vt_audio (VT *vt, const char *command)
       unsigned int
 #endif
               actual_uncompressed_size = audio->frames * audio->bits/8 * audio->channels + 512;
-      unsigned char *data2 = malloc (actual_uncompressed_size);
+      unsigned char *data2 = ctx_malloc (actual_uncompressed_size);
       /* if a buf size is set (rather compression, but
        * this works first..) then */
       int z_result = uncompress (data2, &actual_uncompressed_size,
@@ -45035,7 +49163,7 @@ void vt_audio (VT *vt, const char *command)
         //goto cleanup;
       }
 #endif
-      free (audio->data);
+      ctx_free (audio->data);
       audio->data = data2;
       audio->data_size = actual_uncompressed_size;
     }
@@ -45069,7 +49197,7 @@ void vt_audio (VT *vt, const char *command)
         goto cleanup;
       }
       audio->format = 32;
-      free (audio->data);
+      ctx_free (audio->data);
       audio->data = new_data;
       audio->data_size = audio->buf_width * audio->buf_height * 4;
     }
@@ -45141,7 +49269,7 @@ void vt_audio (VT *vt, const char *command)
            }
          }
        }
-       free (audio->data);
+       ctx_free (audio->data);
        audio->data = NULL;
        audio->data_size=0;
        break;
@@ -45163,7 +49291,7 @@ void vt_audio (VT *vt, const char *command)
 
 //cleanup:
     if (audio->data)
-      free (audio->data);
+      ctx_free (audio->data);
     audio->data = NULL;
     audio->data_size=0;
 }
@@ -45199,6 +49327,8 @@ void vt_audio (VT *vt, const char *command)
  *
  */
 
+#if CTX_TERMINAL_EVENTS
+
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -45301,7 +49431,7 @@ static inline int ctx_list_length (CtxList *list)
 
 static inline void ctx_list_prepend (CtxList **list, void *data)
 {
-  CtxList *new_=calloc (sizeof (CtxList), 1);
+  CtxList *new_=ctx_calloc (sizeof (CtxList), 1);
   new_->next = *list;
   new_->data = data;
   *list = new_;
@@ -45320,7 +49450,7 @@ static inline void *ctx_list_last (CtxList *list)
 
 static inline void ctx_list_append (CtxList **list, void *data)
 {
-  CtxList *new_= calloc (sizeof (CtxList), 1);
+  CtxList *new_= ctx_calloc (sizeof (CtxList), 1);
   new_->data=data;
   if (*list)
     {
@@ -45339,7 +49469,7 @@ static inline void ctx_list_remove (CtxList **list, void *data)
   if ( (*list)->data == data)
     {
       prev = (void *) (*list)->next;
-      free (*list);
+      ctx_free (*list);
       *list = prev;
       return;
     }
@@ -45347,7 +49477,7 @@ static inline void ctx_list_remove (CtxList **list, void *data)
     if (iter->data == data)
       {
         prev->next = iter->next;
-        free (iter);
+        ctx_free (iter);
         break;
       }
     else
@@ -45373,7 +49503,7 @@ ctx_list_insert_before (CtxList **list, CtxList *sibling,
         }
       if (prev)
         {
-          CtxList *new_=calloc (sizeof (CtxList), 1);
+          CtxList *new_=ctx_calloc (sizeof (CtxList), 1);
           new_->next = sibling;
           new_->data = data;
           prev->next=new_;
@@ -45454,7 +49584,7 @@ static Image *image_add (int width,
       image = &image_db[random() %MAX_IMAGES];
     }
   if (image->data)
-    { free (image->data); }
+    { ctx_free (image->data); }
   image->kitty_format = format;
   image->width  = width;
   image->height = height;
@@ -45519,7 +49649,7 @@ static int vt_col_to_pos (VT *vt, int col)
   if (vt->current_line->contains_proportional)
     {
       Ctx *ctx = _ctx_new_drawlist (vt->width, vt->height);
-      ctx_font (ctx, "regular");
+      ctx_font (ctx, "Regular");
       ctx_font_size (ctx, vt->font_size);
       int x = 0;
       pos = 0;
@@ -45549,7 +49679,7 @@ static int vt_col_to_pos (VT *vt, int col)
           pos ++;
         }
       pos --;
-      ctx_free (ctx);
+      ctx_destroy (ctx);
     }
   return pos;
 }
@@ -45578,8 +49708,8 @@ static void vt_set_title (VT *vt, const char *new_title)
 {
   if (vt->inert) return;
   if (vt->title)
-    { free (vt->title); }
-  vt->title = strdup (new_title);
+    { ctx_free (vt->title); }
+  vt->title = ctx_strdup (new_title);
   vt_set_prop (vt, ctx_strhash ("title"), (char*)new_title);
 }
 
@@ -45817,7 +49947,7 @@ static void vt_init (VT *vt, int width, int height, float font_size, float line_
   vt->scrollback_limit   = DEFAULT_SCROLLBACK;
   vt->argument_buf_len   = 0;
   vt->argument_buf_cap   = 64;
-  vt->argument_buf       = malloc (vt->argument_buf_cap);
+  vt->argument_buf       = ctx_malloc (vt->argument_buf_cap);
   vt->argument_buf[0]    = 0;
   vt->vtpty.done         = 0;
   vt->result             = -1;
@@ -46041,7 +50171,7 @@ static void vt_run_argv (VT *vt, char **argv, const char *term)
 
 VT *vt_new_argv (char **argv, int width, int height, float font_size, float line_spacing, int id, int 
can_launch)
 {
-  VT *vt                 = calloc (sizeof (VT), 1);
+  VT *vt                 = ctx_calloc (sizeof (VT), 1);
   vt_init (vt, width, height, font_size, line_spacing, id, can_launch);
   vt_set_font_size (vt, font_size);
   vt_set_line_spacing (vt, line_spacing);
@@ -46121,7 +50251,7 @@ VT *vt_new (const char *command, int width, int height, float font_size, float l
   char *cargv[32];
   int   cargc;
   char *rest, *copy;
-  copy = calloc (strlen (command)+2, 1);
+  copy = ctx_calloc (strlen (command)+2, 1);
   strcpy (copy, command);
   rest = copy;
   cargc = 0;
@@ -46341,7 +50471,7 @@ void vt_set_term_size (VT *vt, int icols, int irows)
   ctx_client_rev_inc (vt->client);
   VT_info ("resize %i %i", irows, icols);
   if (vt->ctxp)
-    ctx_parser_free (vt->ctxp);
+    ctx_parser_destroy (vt->ctxp);
   vt->ctxp = NULL;
 }
 
@@ -46374,7 +50504,7 @@ static inline void vt_argument_buf_add (VT *vt, int ch)
       vt->argument_buf_cap)
     {
       vt->argument_buf_cap = vt->argument_buf_cap * 2;
-      vt->argument_buf = realloc (vt->argument_buf, vt->argument_buf_cap);
+      vt->argument_buf = ctx_realloc (vt->argument_buf, vt->argument_buf_cap/2, vt->argument_buf_cap);
     }
   vt->argument_buf[vt->argument_buf_len] = ch;
   vt->argument_buf[++vt->argument_buf_len] = 0;
@@ -46957,9 +51087,9 @@ static void vtcmd_screen_alignment_display (VT *vt, const char *sequence)
 #if 0
 static int find_idx (int r, int g, int b)
 {
-  r = r / 255.0 * 5;
-  g = g / 255.0 * 5;
-  b = b / 255.0 * 5;
+  r = r / 255.0f * 5;
+  g = g / 255.0f * 5;
+  b = b / 255.0f * 5;
   return 16 + r * 6 * 6 + g * 6 + b;
 }
 #endif
@@ -47501,7 +51631,7 @@ static void vt_ctx_exit (void *data)
     ((void**)vt->ctxp)[0]= vt->current_line->ctx;
 #endif
 
-  //ctx_parser_free (vt->ctxp);
+  //ctx_parser_destroy (vt->ctxp);
   //vt->ctxp = NULL;
 }
 #if 0
@@ -47726,7 +51856,7 @@ qagain:
 #endif
                   }
                 if (vt->ctxp)
-                  ctx_parser_free (vt->ctxp);
+                  ctx_parser_destroy (vt->ctxp);
 
                 vt->ctxp = ctx_parser_new (vt->current_line->ctx,
                                            vt->cols * vt->cw, vt->rows * vt->ch,
@@ -48199,10 +52329,10 @@ static void ctx_wait_frame (Ctx *ctx, VT *vt)
            max_wait-- > 0)
     {
 #if CTX_AUDIO
-      usleep (5);
+      usleep (10);
       vt_audio_task (vt, 0);
 #else
-      usleep (5);
+      usleep (10);
 #endif
       ctx_show_frame (ctx, 0);
     }
@@ -48710,7 +52840,7 @@ static int _vt_handle_control (VT *vt, int byte)
           const char *reply = getenv ("TERM_ENQ_REPLY");
           if (reply)
             {
-              char *copy = strdup (reply);
+              char *copy = ctx_strdup (reply);
               for (uint8_t *c = (uint8_t *) copy; *c; c++)
                 {
                   if (*c < ' ' || * c > 127) { *c = 0; }
@@ -48911,12 +53041,12 @@ void vt_gfx (VT *vt, const char *command)
     if (vt->gfx.data == NULL)
       {
         vt->gfx.data_size = chunk_size;
-        vt->gfx.data = malloc (vt->gfx.data_size + 1);
+        vt->gfx.data = ctx_malloc (vt->gfx.data_size + 1);
       }
     else
       {
         vt->gfx.data_size += chunk_size;
-        vt->gfx.data = realloc (vt->gfx.data, vt->gfx.data_size + 1);
+        vt->gfx.data = ctx_realloc (vt->gfx.data, vt->gfx.data_size-chunk_size,vt->gfx.data_size + 1);
       }
     memcpy (vt->gfx.data + old_size, payload, chunk_size);
     vt->gfx.data[vt->gfx.data_size]=0;
@@ -48933,7 +53063,7 @@ void vt_gfx (VT *vt, const char *command)
         }
       {
         int bin_length = vt->gfx.data_size;
-        uint8_t *data2 = malloc (vt->gfx.data_size);
+        uint8_t *data2 = ctx_malloc (vt->gfx.data_size);
         bin_length = ctx_base642bin ( (char *) vt->gfx.data,
                                      &bin_length,
                                      data2);
@@ -48950,7 +53080,7 @@ void vt_gfx (VT *vt, const char *command)
       if (vt->gfx.compression == 'z')
         {
           //vt->gfx.buf_size)
-          unsigned char *data2 = malloc (vt->gfx.buf_size + 1);
+          unsigned char *data2 = ctx_malloc (vt->gfx.buf_size + 1);
           /* if a buf size is set (rather compression, but
            * this works first..) then */
 #ifndef EMSCRIPTEN
@@ -49301,7 +53431,7 @@ static void vt_sixels (VT *vt, const char *sixels)
     }
   x = 0;
   y = 0;
-  pixels = calloc (width * (height + 6), 4);
+  pixels = ctx_calloc (width * (height + 6), 4);
   image = image_add (width, height, 0,
                      32, width*height*4, pixels);
   uint8_t *dst = pixels;
@@ -49849,7 +53979,7 @@ static void vt_state_osc (VT *vt, int byte)
                             {
                               if (!strcmp (key, "name") )
                                 {
-                                  name = strdup (value);
+                                  name = ctx_strdup (value);
                                 }
                               else if (!strcmp (key, "width") )
                                 {
@@ -49904,7 +54034,7 @@ static void vt_state_osc (VT *vt, int byte)
                       // code-dup
                       if (!strcmp (key, "name") )
                         {
-                          name = strdup (value);
+                          name = ctx_strdup (value);
                         }
                       else if (!strcmp (key, "width") )
                         {
@@ -49952,7 +54082,7 @@ static void vt_state_osc (VT *vt, int byte)
                   Image *image = NULL;
                   {
                     int bin_length = vt->argument_buf_len;
-                    uint8_t *data2 = malloc (bin_length);
+                    uint8_t *data2 = ctx_malloc (bin_length);
                     bin_length = ctx_base642bin ( (char *) p,
                                                  &bin_length,
                                                  data2);
@@ -50299,7 +54429,7 @@ int vt_poll (VT *vt, int timeout)
   // read_size*2   56.99s
   int remaining_chars = read_size * 3;// * 100;
   int len = 0;
-  vt_audio_task (vt, 0);
+  //vt_audio_task (vt, 0);
 #if 1
   if (vt->cursor_visible && vt->smooth_scroll)
     {
@@ -50309,10 +54439,13 @@ int vt_poll (VT *vt, int timeout)
   read_size = MIN (read_size, remaining_chars);
   long start_ticks = ctx_ticks ();
   long ticks = start_ticks;
+  int first = 1;
   while (remaining_chars > 0 &&
-         vt_waitdata (vt, 0) &&
+         vt_waitdata (vt, first?0:1000*5) &&
          ( ticks - start_ticks < timeout ||  vt->state == vt_state_ctx))
     {
+      first = 0;
+      vt_audio_task (vt, 0);
   if (vt->in_smooth_scroll)
     {
       remaining_chars = 1;
@@ -50336,7 +54469,6 @@ int vt_poll (VT *vt, int timeout)
            remaining_chars = read_size * 2;
          }
       }
-      vt_audio_task (vt, 0);
       ticks = ctx_ticks ();
     }
   if (got_data < 0)
@@ -50558,7 +54690,7 @@ void vt_feed_keystring (VT *vt, CtxEvent *event, const char *str)
   if (!strcmp (str, "capslock")) return;
 
 #if 0
-  if (!strstr (str, "-page"))
+  if (!ctx_strstr (str, "-page"))
     vt_set_scroll (vt, 0);
 #endif
 
@@ -50910,9 +55042,9 @@ void vt_destroy (VT *vt)
       ctx_list_remove (&vt->scrollback, vt->scrollback->data);
     }
   if (vt->ctxp)
-    ctx_parser_free (vt->ctxp);
+    ctx_parser_destroy (vt->ctxp);
   //if (vt->ctx)
-  //  { ctx_free (vt->ctx); }
+  //  { ctx_destroy (vt->ctx); }
   free (vt->argument_buf);
   ctx_list_remove (&ctx_vts, vt);
   kill (vt->vtpty.pid, 9);
@@ -52638,14 +56770,17 @@ void vt_ctx_glyph (Ctx *ctx, VT *vt, float x, float y, int unichar, int bold, fl
     ctx_translate (ctx, 0, vt->font_size * offset_y);
   }
   y -= vt->font_size * 0.22;
-  if (bold
-      && backend_type != CTX_BACKEND_TERM)
+  ctx_move_to (ctx, x, y);
+  if (bold)
+  {
+    if (!did_save)
     {
-      ctx_move_to (ctx, x - vt->font_size/30.0, y);
-      //ctx_line_width (ctx, vt->font_size/30.0);
-      ctx_glyph (ctx, unichar, 0);
+      ctx_save (ctx);
+      did_save = 1;
     }
-  ctx_move_to (ctx, x, y);
+    // TODO : check if proportional and use other font for that
+    ctx_font (ctx, "Mono Bold");
+  }
   ctx_glyph (ctx, unichar, 0);
   if (did_save)
     ctx_restore (ctx);
@@ -52786,7 +56921,7 @@ float vt_draw_cell (VT      *vt, Ctx *ctx,
     {
       if (vt->font_is_mono)
         {
-          ctx_font (ctx, "regular");
+          ctx_font (ctx, "Regular");
           vt->font_is_mono = 0;
         }
       cw = ctx_glyph_width (ctx, unichar);
@@ -52795,7 +56930,7 @@ float vt_draw_cell (VT      *vt, Ctx *ctx,
     {
       if (vt->font_is_mono == 0)
         {
-          ctx_font (ctx, "mono");
+          ctx_font (ctx, "Mono");
           vt->font_is_mono = 1;
           if (col > 1)
             {
@@ -53074,10 +57209,11 @@ float vt_draw_cell (VT      *vt, Ctx *ctx,
       if (italic)
         {
           ctx_save (ctx);
-          ctx_translate (ctx, (x0 + cw/3), (y0 + vt->ch/2) );
-          ctx_scale (ctx, 0.9, 0.9);
-          ctx_rotate (ctx, 0.15);
-          ctx_translate (ctx, - (x0 + cw/3), - (y0 + vt->ch/2) );
+          //ctx_translate (ctx, (x0 + cw/3), (y0 + vt->ch/2) );
+          //ctx_scale (ctx, 0.9, 0.9);
+          //ctx_rotate (ctx, 0.15);
+          //ctx_translate (ctx, - (x0 + cw/3), - (y0 + vt->ch/2) );
+          ctx_font (ctx, "Mono Italic");
         }
       vt_ctx_glyph (ctx, vt, x0, y0, unichar, bold, scale_x, scale_y, offset_y);
       if (italic)
@@ -53467,7 +57603,7 @@ void vt_draw (VT *vt, Ctx *ctx, double x0, double y0)
                             0.00, -0.0007, 1.0);
   x0 = 0;
   y0 = 0;
-  ctx_font (ctx, "mono");
+  ctx_font (ctx, "Mono");
   vt->font_is_mono = 0;
   ctx_font_size (ctx, vt->font_size * vt->font_to_cell_scale);
   vt->has_blink = 0;
@@ -53497,6 +57633,7 @@ void vt_draw (VT *vt, Ctx *ctx, double x0, double y0)
       else
         {
           itk_style_color (ctx, "terminal-bg");
+          //ctx_rgba (ctx,0,0,0,1.0f);
           ctx_fill  (ctx);
         }
 #endif
@@ -53873,9 +58010,9 @@ static int short_count = 0;
 
 void terminal_set_primary (const char *text)
 {
-  if (primary) free (primary);
+  if (primary) ctx_free (primary);
   primary = NULL;
-  if (text) primary = strdup (text);
+  if (text) primary = ctx_strdup (text);
 }
 
 void terminal_long_tap (Ctx *ctx, VT *vt);
@@ -53937,7 +58074,7 @@ void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, in
                  char *sel = vt_get_selection (vt);
                  if (sel[0] == ' ' || sel[0] == '\0')
                    hit_space = 1;
-                 free (sel);
+                 ctx_free (sel);
                }
                if (hit_space)
                  vt->select_start_col++;
@@ -53951,7 +58088,7 @@ void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, in
                  int len = strlen(sel);
                  if (sel[len-1]==' ')
                    hit_space = 1;
-                 free (sel);
+                 ctx_free (sel);
                }
                if (hit_space)
                  vt->select_end_col--;
@@ -53962,7 +58099,7 @@ void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, in
                  if (sel)
                  {
                     terminal_set_primary (sel);
-                    free (sel);
+                    ctx_free (sel);
                  }
                }
                }
@@ -53975,7 +58112,7 @@ void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, in
                  char *sel = vt_get_selection (vt);
                  if (sel){
                     terminal_set_primary (sel);
-                    free (sel);
+                    ctx_free (sel);
                  }
                }
                break;
@@ -54041,7 +58178,7 @@ void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, in
            if (selection)
            {
              terminal_set_primary (selection);
-             free (selection);
+             ctx_free (selection);
            }
          }
 
@@ -54119,6 +58256,8 @@ void vt_set_ctx (VT *vt, Ctx *ctx)
 {
   vt->root_ctx = ctx;
 }
+
+#endif
 #endif
 
 float ctx_target_fps = 100.0; /* this might end up being the resolution of our
@@ -54154,18 +58293,6 @@ extern Ctx *ctx;
 #define flag_set(a, f)    ((a) |= (f));
 #define flag_unset(a, f)  ((a) &= ~(f));
 
-//#define CTX_x            CTX_STRH('x',0,0,0,0,0,0,0,0,0,0,0,0,0)
-//#define CTX_y            CTX_STRH('y',0,0,0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_lower_bottom CTX_STRH('l','o','w','e','r','-','b','o','t','t','o','m',0,0)
-#define CTX_lower        CTX_STRH('l','o','w','e','r',0,0,0,0,0,0,0,0,0)
-#define CTX_raise        CTX_STRH('r','a','i','s','e',0,0,0,0,0,0,0,0,0)
-#define CTX_raise_top    CTX_STRH('r','a','i','s','e','-','t','o','p',0,0,0,0,0)
-#define CTX_terminate    CTX_STRH('t','e','r','m','i','n','a','t','e',0,0,0,0,0)
-#define CTX_maximize     CTX_STRH('m','a','x','i','m','i','z','e',0,0,0,0,0,0)
-#define CTX_unmaximize   CTX_STRH('u','n','m','a','x','i','m','i','z','e',0,0,0,0)
-//#define CTX_width        CTX_STRH('w','i','d','t','h',0,0,0,0,0,0,0,0,0)
-#define CTX_action       CTX_STRH('a','c','t','i','o','n',0,0,0,0,0,0,0,0)
-//#define CTX_height       CTX_STRH('h','e','i','g','h','t',0,0,0,0,0,0,0,0)
 
 void terminal_update_title    (const char *title);
 void ctx_sdl_set_fullscreen   (Ctx *ctx, int val);
@@ -54180,10 +58307,10 @@ void ctx_client_set_title        (Ctx *ctx, int id, const char *title)
    if (!client)
      return;
    if (client->title)
-     free (client->title);
+     ctx_free (client->title);
    client->title = NULL;
    if (title)
-     client->title = strdup (title);
+     client->title = ctx_strdup (title);
 }
 const char *ctx_client_get_title (Ctx *ctx, int id)
 {
@@ -54204,8 +58331,8 @@ int vt_set_prop (VT *vt, uint32_t key_hash, const char *val)
        if (client)
        {
          ctx_client_set_title (vt->root_ctx, client->id, val);
-         //if (client->title) free (client->title);
-         //client->title = strdup (val);
+         //if (client->title) ctx_free (client->title);
+         //client->title = ctx_strdup (val);
        }
      }
      break;
@@ -54248,9 +58375,9 @@ int vt_set_prop (VT *vt, uint32_t key_hash, const char *val)
         case CTX_maximize:     ctx_client_maximize (client); break;
         case CTX_unmaximize:   ctx_client_unmaximize (client); break;
         case CTX_lower:        ctx_client_lower (client); break;
-        case CTX_lower_bottom: ctx_client_lower_bottom (client);  break;
+        case CTX_lowerBottom:  ctx_client_lower_bottom (client);  break;
         case CTX_raise:        ctx_client_raise (client); break;
-        case CTX_raise_top:    ctx_client_raise_top (client); break;
+        case CTX_raiseTop:     ctx_client_raise_top (client); break;
       }
       break;
   }
@@ -54312,7 +58439,7 @@ CtxClient *ctx_client_new (Ctx *ctx,
                            void *user_data,
                            CtxClientFinalize finalize)
 {
-  CtxClient *client = calloc (sizeof (CtxClient), 1);
+  CtxClient *client = ctx_calloc (sizeof (CtxClient), 1);
   ctx_list_append (&ctx->events.clients, client);
   ctx_client_init (ctx, client, x, y, width, height, font_size, flags, user_data, finalize);
   float line_spacing = 2.0f;
@@ -54325,7 +58452,7 @@ CtxClient *ctx_client_new (Ctx *ctx,
 CtxClient *ctx_client_new_argv (Ctx *ctx, char **argv, int x, int y, int width, int height, float font_size, 
CtxClientFlags flags, void *user_data, CtxClientFinalize finalize)
 {
 
-  CtxClient *client = calloc (sizeof (CtxClient), 1);
+  CtxClient *client = ctx_calloc (sizeof (CtxClient), 1);
   ctx_client_init (ctx, client, x, y, width, height, font_size, flags, user_data, finalize);
   ctx_list_append (&ctx->events.clients, client);
 
@@ -54347,14 +58474,14 @@ static void *launch_client_thread (void *data)
   client->start_routine (client->sub_ctx, client->user_data);
 
   fprintf (stderr, "%s: cleanup\n", __FUNCTION__);
-  ctx_free (client->sub_ctx);
+  ctx_destroy (client->sub_ctx);
   return NULL;
 }
 
 CtxClient *ctx_client_new_thread (Ctx *ctx, void (*start_routine)(Ctx *ctx, void *user_data),
                                   int x, int y, int width, int height, float font_size, CtxClientFlags 
flags, void *user_data, CtxClientFinalize finalize)
 {
-  CtxClient *client = calloc (sizeof (CtxClient), 1);
+  CtxClient *client = ctx_calloc (sizeof (CtxClient), 1);
   ctx_client_init (ctx, client, x, y, width, height, font_size, flags, user_data, finalize);
 
   ctx_list_append (&ctx->events.clients, client);
@@ -54371,8 +58498,12 @@ CtxClient *ctx_client_new_thread (Ctx *ctx, void (*start_routine)(Ctx *ctx, void
 }
 #endif
 
+#if CTX_SHAPE_CACHE
 extern float ctx_shape_cache_rate;
+#endif
+#if CTX_THREADS
 extern int _ctx_max_threads;
+#endif
 
 static int focus_follows_mouse = 0;
 
@@ -54479,11 +58610,11 @@ void ctx_client_remove (Ctx *ctx, CtxClient *client)
   }
 
   if (client->title)
-    free (client->title);
+    ctx_free (client->title);
 
 #if VT_RECORD
   if (client->recording)
-    ctx_free (client->recording);
+    ctx_destroy (client->recording);
 #endif
   if (client->finalize)
      client->finalize (client, client->user_data);
@@ -54507,7 +58638,7 @@ void ctx_client_remove (Ctx *ctx, CtxClient *client)
   }
 
   ctx_client_unlock (client);
-  free (client);
+  ctx_free (client);
 }
 
 void ctx_client_remove_by_id (Ctx *ctx, int id)
@@ -54686,7 +58817,7 @@ char  *ctx_client_get_selection (Ctx *ctx, int id)
    CtxClient *client = ctx_client_by_id (ctx, id);
    if (client && client->vt)
      return vt_get_selection (client->vt);
-   return strdup ("");
+   return ctx_strdup ("");
 }
 
 void ctx_client_move (Ctx *ctx, int id, int x, int y)
@@ -54965,7 +59096,7 @@ static void ctx_client_draw (Ctx *ctx, CtxClient *client, float x, float y)
         if (!client->recording)
           client->recording = _ctx_new_drawlist (client->width, client->height);
         else
-          ctx_reset (client->recording);
+          ctx_start_frame (client->recording);
         vt_draw (client->vt, client->recording, 0.0, 0.0);
       }
 
@@ -55011,7 +59142,7 @@ static void ctx_client_use_images (Ctx *ctx, CtxClient *client)
         if (!client->recording)
           client->recording = _ctx_new_drawlist (client->width, client->height);
         else
-          ctx_reset (client->recording);
+          ctx_start_frame (client->recording);
         vt_draw (client->vt, client->recording, 0.0, 0.0);
       }
 
@@ -55049,10 +59180,10 @@ void ctx_client_unlock (CtxClient *client)
 
 CtxEvent *ctx_event_copy (CtxEvent *event)
 {
-  CtxEvent *copy = calloc (1, sizeof (CtxEvent));
+  CtxEvent *copy = ctx_calloc (1, sizeof (CtxEvent));
   *copy = *event;
   if (copy->string) {
-    copy->string = strdup (copy->string);
+    copy->string = ctx_strdup (copy->string);
     copy->owns_string = 1;
   }
   return copy;
@@ -55090,7 +59221,7 @@ void ctx_client_handle_event (Ctx *ctx, CtxEvent *ctx_event, const char *event)
         {
           if (vt)
             vt_paste (vt, text);
-          free (text);
+          ctx_free (text);
         }
     }
   else if (!strcmp (event, "shift-control-c") && vt)
@@ -55099,7 +59230,7 @@ void ctx_client_handle_event (Ctx *ctx, CtxEvent *ctx_event, const char *event)
       if (text)
         {
           ctx_set_clipboard (ctx, text);
-          free (text);
+          ctx_free (text);
         }
     }
   else if (!strcmp (event, "shift-control-t") ||
@@ -55147,7 +59278,7 @@ void ctx_client_handle_event (Ctx *ctx, CtxEvent *ctx_event, const char *event)
         if (sel)
         {
           vt_feed_keystring (vt, ctx_event, sel);
-          free (sel);
+          ctx_free (sel);
         }
       }
     }
@@ -55637,6 +59768,57 @@ ctx_client_feed_keystring (CtxClient *client, CtxEvent *event, const char *str)
 #endif
 }
 
+#if CTX_CLIENTS
+int ctx_client_id (CtxClient *client)
+{
+  return client?client->id:-1;
+}
+
+VT *ctx_client_vt (CtxClient *client)
+{
+  return client?client->vt:NULL;
+}
+
+void ctx_client_add_event (CtxClient *client, CtxEvent *event)
+{
+  ctx_list_append (&client->ctx_events, ctx_event_copy (event));
+}
+
+void ctx_client_quit (CtxClient *client)
+{
+   if (!client) return;
+  client->do_quit = 1;
+}
+
+int ctx_client_flags (CtxClient *client)
+{
+  return client?client->flags:0;
+}
+
+void *ctx_client_userdata (CtxClient *client)
+{
+  return client?client->user_data:NULL;
+}
+
+const char *ctx_client_title (CtxClient *client)
+{
+  return client?client->title:NULL;
+}
+
+CtxClient *ctx_client_find (Ctx *ctx, const char *label)
+{
+  for (CtxList *l = ctx_clients (ctx); l; l = l->next)
+  {
+    CtxClient *client = l->data;
+    if (client->user_data && !strcmp (client->user_data, label))
+    {
+      return client;
+    }
+  }
+  return NULL;
+}
+
+#endif
 /* a C tinyvg parser with minimal RAM requirement and geometry culling
  * ability, (c) 2022 Øyvind Kolås, pippin gimp org
  */
@@ -55644,7 +59826,9 @@ ctx_client_feed_keystring (CtxClient *client, CtxEvent *event, const char *str)
 
 #if CTX_TINYVG
 
+#ifndef CTX_TVG_STDIO
 #define CTX_TVG_STDIO     1
+#endif
 
 #if CTX_TVG_STDIO
 #include <sys/types.h>
@@ -55752,6 +59936,7 @@ static inline void ctx_tvg_seek (CtxTinyVG *tvg, uint32_t pos)
   }
 }
 
+#if CTX_TVG_STDIO
 static void ctx_tvg_init_fd (CtxTinyVG *tvg, Ctx *ctx, int fd, int flags)
 {
   memset (tvg, 0, sizeof (CtxTinyVG));
@@ -55764,6 +59949,7 @@ static void ctx_tvg_init_fd (CtxTinyVG *tvg, Ctx *ctx, int fd, int flags)
   tvg->cache = &tvg->_cache[0];
   tvg->cache_length = CTX_TVG_CACHE_SIZE;
 }
+#endif
 
 static void ctx_tvg_init_data (CtxTinyVG *tvg, Ctx *ctx, void *data, int len, int flags)
 {
@@ -55776,15 +59962,17 @@ static void ctx_tvg_init_data (CtxTinyVG *tvg, Ctx *ctx, void *data, int len, in
   tvg->flags = flags;
 }
 
-#if CTX_TVG_STDIO
 static inline int ctx_tvg_prime_cache (CtxTinyVG *tvg, uint32_t pos, int len)
 {
+#if CTX_TVG_STDIO
   if (!tvg->fd)
+#endif
   {
     if (pos + len < tvg->length)
       return 1;
     return 0;
   }
+#if CTX_TVG_STDIO
   if (tvg->cache_offset < pos && tvg->cache_offset + CTX_TVG_CACHE_SIZE - 1 > pos+len)
   {
     return 1;
@@ -55798,9 +59986,9 @@ static inline int ctx_tvg_prime_cache (CtxTinyVG *tvg, uint32_t pos, int len)
   }
   read (tvg->fd, tvg->cache, CTX_TVG_CACHE_SIZE);
   tvg->fd_pos += CTX_TVG_CACHE_SIZE;
+#endif
   return 1;
 }
-#endif
 
 static inline void ctx_tvg_memcpy (CtxTinyVG *tvg, void *dst, int pos, int len)
 {
@@ -55832,7 +60020,9 @@ static inline uint8_t ctx_tvg_u6_u2 (CtxTinyVG *tvg, uint8_t *u2_ret)
   return (ret & 63);
 }
 
-static inline int32_t ctx_tvg_val (CtxTinyVG *tvg)
+// XXX if this is inline the ESP32 fails with a compiler error
+//
+static int32_t ctx_tvg_val (CtxTinyVG *tvg)
 {
   switch (tvg->val_type)
   {
@@ -55870,10 +60060,10 @@ ctx_tvg_segment (CtxTinyVG *tvg, int n_commands)
 
   if (tvg->flags & CTX_TVG_FLAG_BBOX_CHECK)
   {
-      float minx = 1000000.0;
-      float miny = 1000000.0;
-      float maxx = -1000000.0;
-      float maxy = -1000000.0;
+      float minx = 1000000.0f;
+      float miny = 1000000.0f;
+      float maxx = -1000000.0f;
+      float maxy = -1000000.0f;
       int start_pos = tvg->pos;
   
       float x = ctx_tvg_unit(tvg);
@@ -55922,7 +60112,7 @@ ctx_tvg_segment (CtxTinyVG *tvg, int n_commands)
              float cy1 = ctx_tvg_unit(tvg);
                    x   = ctx_tvg_unit(tvg);
                    y   = ctx_tvg_unit(tvg);
-             if (cx0 + cy0 + cx1 + cy1){}
+             if (cx0 + cy0 + cx1 + cy1 != 0.f){}
              ADD_COORD(x,y);
            }
            break;
@@ -55932,7 +60122,7 @@ ctx_tvg_segment (CtxTinyVG *tvg, int n_commands)
              float   radius = ctx_tvg_unit (tvg);
                      x = ctx_tvg_unit (tvg);
                      y = ctx_tvg_unit (tvg);
-             if (radius && large_and_sweep){};
+             if (radius != 0.0f && large_and_sweep != 0){};
              ADD_COORD(x,y);
            }
            break;
@@ -55944,7 +60134,7 @@ ctx_tvg_segment (CtxTinyVG *tvg, int n_commands)
              float rotation = ctx_tvg_unit (tvg);
                    x        = ctx_tvg_unit (tvg);
                    y        = ctx_tvg_unit (tvg);
-             if (rotation && rx && ry && large_and_sweep) {};
+             if (rotation !=0.0f && rx != 0.0f && ry !=0.0f && large_and_sweep) {};
              ADD_COORD(x,y);
            }
            break;
@@ -55955,7 +60145,7 @@ ctx_tvg_segment (CtxTinyVG *tvg, int n_commands)
            {
              float cx0 = ctx_tvg_unit(tvg);
              float cy0 = ctx_tvg_unit(tvg);
-             if (cx0 + cy0){}
+             if (cx0 + cy0 != 0.0f){}
              x = ctx_tvg_unit(tvg);
              y = ctx_tvg_unit(tvg);
              ADD_COORD(x,y);
@@ -56025,7 +60215,7 @@ ctx_tvg_segment (CtxTinyVG *tvg, int n_commands)
            float   radius = ctx_tvg_unit (tvg);
                    x = ctx_tvg_unit (tvg);
                    y = ctx_tvg_unit (tvg);
-           ctx_svg_arc_to (ctx, radius, radius, 0.0, large, !sweep, x, y);
+           ctx_svg_arc_to (ctx, radius, radius, 0.0f, large, !sweep, x, y);
          }
          break;
        case CTX_TVG_ARC_ELLIPSE:
@@ -56174,19 +60364,19 @@ static void ctx_tvg_set_style (CtxTinyVG *tvg, CtxTinyVGStyle *style)
     case CTX_TVG_LGRAD:
       ctx_linear_gradient (ctx, x0, y0, x1, y1);
       ctx_tvg_get_color (tvg, idx0, &red, &green, &blue, &alpha);
-      ctx_gradient_add_stop (ctx, 0.0, red, green, blue, alpha);
+      ctx_gradient_add_stop (ctx, 0.0f, red, green, blue, alpha);
       ctx_tvg_get_color (tvg, idx1, &red, &green, &blue, &alpha);
-      ctx_gradient_add_stop (ctx, 1.0, red, green, blue, alpha);
+      ctx_gradient_add_stop (ctx, 1.0f, red, green, blue, alpha);
       break;
     case CTX_TVG_RGRAD:
       {
         float radius = ctx_sqrtf ((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0));
-        ctx_radial_gradient (ctx, x0, y0, 0.0, x1, y1, radius);
+        ctx_radial_gradient (ctx, x0, y0, 0.0f, x1, y1, radius);
       }
       ctx_tvg_get_color (tvg, idx0, &red, &green, &blue, &alpha);
-      ctx_gradient_add_stop (ctx, 0.0, red, green, blue, alpha);
+      ctx_gradient_add_stop (ctx, 0.0f, red, green, blue, alpha);
       ctx_tvg_get_color (tvg, idx1, &red, &green, &blue, &alpha);
-      ctx_gradient_add_stop (ctx, 1.0, red, green, blue, alpha);
+      ctx_gradient_add_stop (ctx, 1.0f, red, green, blue, alpha);
       break;
   }
 }
@@ -56263,7 +60453,7 @@ static int ctx_tvg_command (CtxTinyVG *tvg)
   float factor = ctx_matrix_get_scale (&ctx->state.gstate.transform);
   int command = ctx_tvg_u6_u2(tvg, &primary_style_type);
   int item_count;
-  float line_width = 0.0;
+  float line_width = 0.0f;
 
   int save_offset = 0;
 
@@ -56300,7 +60490,7 @@ static int ctx_tvg_command (CtxTinyVG *tvg)
       ctx_tvg_style (tvg, primary_style_type, &tvg->stroke);
       line_width = ctx_tvg_unit (tvg);
 
-      if (line_width * factor < 1.0) line_width = 1.0 / factor;
+      if (line_width * factor < 1.0f) line_width = 1.0f / factor;
 
       if (command == CTX_TVG_DRAW_LINE_PATH)
         ctx_tvg_path (tvg, item_count);
@@ -56323,7 +60513,7 @@ static int ctx_tvg_command (CtxTinyVG *tvg)
       ctx_tvg_style (tvg, tvg->stroke.type, &tvg->stroke);
       line_width = ctx_tvg_unit (tvg);
 
-      if (line_width * factor < 1.0) line_width = 1.0 / factor;
+      if (line_width * factor < 1.0f) line_width = 1.0f / factor;
 
       ctx_line_width (ctx, line_width);
       ctx_tvg_rectangles (tvg, item_count, 1, 1);
@@ -56336,7 +60526,7 @@ static int ctx_tvg_command (CtxTinyVG *tvg)
       ctx_tvg_style (tvg, tvg->stroke.type, &tvg->stroke);
       line_width = ctx_tvg_unit (tvg);
 
-      if (line_width * factor < 1.0) line_width = 1.0 / factor;
+      if (line_width * factor < 1.0f) line_width = 1.0f / factor;
 
       save_offset = tvg->pos;
       if (command == CTX_TVG_OUTLINE_FILL_POLYGON)
@@ -56404,11 +60594,14 @@ ctx_tvg_draw (CtxTinyVG *tvg)
    if (tvg->flags & CTX_TVG_FLAG_LOAD_PAL)
    {
      int count = tvg->color_bytes * tvg->color_count;
-     tvg->pal = malloc (count);
+     tvg->pal = ctx_malloc (count);
      for (int i = 0; i < count; i++)
        tvg->pal[i] = ctx_tvg_u8 (tvg);
    }
-   else if (!tvg->fd)
+   else 
+#if CTX_TVG_STDIO
+           if (!tvg->fd)
+#endif
    {
      tvg->pal = &tvg->cache[tvg->pos];
      ctx_tvg_seek (tvg, tvg->pos + tvg->color_bytes * tvg->color_count);
@@ -56420,10 +60613,10 @@ ctx_tvg_draw (CtxTinyVG *tvg)
 
    if (tvg->flags & CTX_TVG_FLAG_BBOX_CHECK)
    {
-      float minx = 1000000.0;
-      float miny = 1000000.0;
-      float maxx = -1000000.0;
-      float maxy = -1000000.0;
+      float minx = 1000000.0f;
+      float miny = 1000000.0f;
+      float maxx = -1000000.0f;
+      float maxy = -1000000.0f;
       float x, y;
       x = 0; y =0;
       ctx_device_to_user (ctx, &x, &y);
@@ -56449,7 +60642,7 @@ ctx_tvg_draw (CtxTinyVG *tvg)
 
    ctx_restore (ctx);
    if (tvg->flags & CTX_TVG_FLAG_LOAD_PAL)
-     free (tvg->pal);
+     ctx_free (tvg->pal);
    return tvg->error;
 }
 
@@ -56461,8 +60654,8 @@ ctx_tvg_draw2 (CtxTinyVG *tvg,
                float target_height)
 {
    Ctx*ctx = tvg->ctx;
-   float scale_x = 1.0;
-   float scale_y = 1.0;
+   float scale_x = 1.0f;
+   float scale_y = 1.0f;
    { /* handle aspect ratio, add translate ? */
    if (target_width<=0 && target_height <= 0)
    {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]