[gegl/wip/pippin/ctx: 115/115] gegl/ctx: update ctx
- From: Øyvind "pippin" Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/wip/pippin/ctx: 115/115] gegl/ctx: update ctx
- Date: Fri, 30 Apr 2021 15:05:47 +0000 (UTC)
commit 98c0689bba7d3b39cb3e185805890aeb48a5f466
Author: Øyvind Kolås <pippin gimp org>
Date: Fri Apr 30 17:05:03 2021 +0200
gegl/ctx: update ctx
gegl/ctx/ctx.h | 30389 +++++++++++++++++++++++++++----------------------
gegl/ctx/meson.build | 3 +
2 files changed, 17016 insertions(+), 13376 deletions(-)
---
diff --git a/gegl/ctx/ctx.h b/gegl/ctx/ctx.h
index 0aa4a12ca..3bdf02b7c 100644
--- a/gegl/ctx/ctx.h
+++ b/gegl/ctx/ctx.h
@@ -21,13 +21,14 @@
* #define CTX_IMPLEMENTATION
* #include "ctx.h"
*
- * Ctx does not - yet - contain a minimal default fallback font, so
+ * Ctx contains a minimal default fallback font with only ascii, so
* you probably want to also include a font, and perhaps enable
* the cairo or SDL2 optional renderers, a more complete example
* could be:
*
* #include <cairo.h>
* #include <SDL.h>
+ * #include "ctx-font-regular.h"
* #define CTX_IMPLEMENTATION
* #include "ctx.h"
*
@@ -54,39 +55,23 @@ typedef struct _Ctx Ctx;
enum _CtxPixelFormat
{
CTX_FORMAT_NONE=0,
- CTX_FORMAT_GRAY8,
- CTX_FORMAT_GRAYA8,
- CTX_FORMAT_RGB8,
- CTX_FORMAT_RGBA8,
- CTX_FORMAT_BGRA8,
- CTX_FORMAT_RGB565,
- CTX_FORMAT_RGB565_BYTESWAPPED,
- CTX_FORMAT_RGB332,
- CTX_FORMAT_RGBAF,
- CTX_FORMAT_GRAYF,
- CTX_FORMAT_GRAYAF,
- CTX_FORMAT_GRAY1,
- CTX_FORMAT_GRAY2,
- CTX_FORMAT_GRAY4,
- CTX_FORMAT_CMYK8,
- CTX_FORMAT_CMYKA8,
- CTX_FORMAT_CMYKAF,
- CTX_FORMAT_DEVICEN1,
- CTX_FORMAT_DEVICEN2,
- CTX_FORMAT_DEVICEN3,
- CTX_FORMAT_DEVICEN4,
- CTX_FORMAT_DEVICEN5,
- CTX_FORMAT_DEVICEN6,
- CTX_FORMAT_DEVICEN7,
- CTX_FORMAT_DEVICEN8,
- CTX_FORMAT_DEVICEN9,
- CTX_FORMAT_DEVICEN10,
- CTX_FORMAT_DEVICEN11,
- CTX_FORMAT_DEVICEN12,
- CTX_FORMAT_DEVICEN13,
- CTX_FORMAT_DEVICEN14,
- CTX_FORMAT_DEVICEN15,
- CTX_FORMAT_DEVICEN16
+ CTX_FORMAT_GRAY8, // 1 - these enum values are not coincidence
+ CTX_FORMAT_GRAYA8, // 2 -
+ CTX_FORMAT_RGB8, // 3 -
+ CTX_FORMAT_RGBA8, // 4 -
+ CTX_FORMAT_BGRA8, // 5
+ CTX_FORMAT_RGB565, // 6
+ CTX_FORMAT_RGB565_BYTESWAPPED, // 7
+ CTX_FORMAT_RGB332, // 8
+ 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
};
typedef enum _CtxPixelFormat CtxPixelFormat;
@@ -141,7 +126,6 @@ void ctx_dirty_rect (Ctx *ctx, int *x, int *y, int *width, int *height);
*/
void ctx_free (Ctx *ctx);
-
/* clears and resets a context */
void ctx_reset (Ctx *ctx);
void ctx_begin_path (Ctx *ctx);
@@ -153,17 +137,25 @@ void ctx_clip (Ctx *ctx);
void ctx_identity (Ctx *ctx);
void ctx_rotate (Ctx *ctx, float x);
+void ctx_image_smoothing (Ctx *ctx, int enabled);
+int ctx_get_image_smoothing (Ctx *ctx);
+
#define CTX_LINE_WIDTH_HAIRLINE -1000.0
#define CTX_LINE_WIDTH_ALIASED -1.0
#define CTX_LINE_WIDTH_FAST -1.0 /* aliased 1px wide line */
void ctx_miter_limit (Ctx *ctx, float limit);
+float ctx_get_miter_limit (Ctx *ctx);
void ctx_line_width (Ctx *ctx, float x);
+void ctx_line_dash_offset (Ctx *ctx, float line_dash);
+float ctx_get_line_dash_offset (Ctx *ctx);
void ctx_apply_transform (Ctx *ctx, float a, float b, // hscale, hskew
- float c, float d, // vskew, vscale
- float e, float f); // htran, vtran
+ float c, float d, // vskew, vscale
+ float e, float f); // htran, vtran
+void ctx_set_transform (Ctx *ctx, float a, float b, float c, float d, float e, float f);
void ctx_line_dash (Ctx *ctx, float *dashes, int count);
void ctx_font_size (Ctx *ctx, float x);
void ctx_font (Ctx *ctx, const char *font);
+void ctx_font_family (Ctx *ctx, const char *font_family);
void ctx_scale (Ctx *ctx, float x, float y);
void ctx_translate (Ctx *ctx, float x, float y);
void ctx_line_to (Ctx *ctx, float x, float y);
@@ -202,6 +194,7 @@ void ctx_rel_quad_to (Ctx *ctx,
float x, float y);
void ctx_close_path (Ctx *ctx);
float ctx_get_font_size (Ctx *ctx);
+const char *ctx_get_font (Ctx *ctx);
float ctx_get_line_width (Ctx *ctx);
int ctx_width (Ctx *ctx);
int ctx_height (Ctx *ctx);
@@ -219,15 +212,6 @@ void gtx_glyph_free (CtxGlyph *glyphs);
int ctx_glyph (Ctx *ctx, uint32_t unichar, int stroke);
-void ctx_arc (Ctx *ctx,
- float x, float y,
- float radius,
- float angle1, float angle2,
- int direction);
-
-void ctx_arc_to (Ctx *ctx, float x1, float y1,
- float x2, float y2, float radius);
-
void ctx_quad_to (Ctx *ctx, float cx, float cy,
float x, float y);
@@ -243,6 +227,7 @@ void ctx_arc_to (Ctx *ctx, float x1, float y1,
void ctx_preserve (Ctx *ctx);
void ctx_fill (Ctx *ctx);
void ctx_stroke (Ctx *ctx);
+
void ctx_parse (Ctx *ctx, const char *string);
void ctx_shadow_rgba (Ctx *ctx, float r, float g, float b, float a);
@@ -261,10 +246,24 @@ float ctx_get_global_alpha (Ctx *ctx);
void ctx_named_source (Ctx *ctx, const char *name);
// followed by a color, gradient or pattern definition
+void ctx_rgba_stroke (Ctx *ctx, float r, float g, float b, float a);
+void ctx_rgb_stroke (Ctx *ctx, float r, float g, float b);
+void ctx_rgba8_stroke (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
+
+void ctx_gray_stroke (Ctx *ctx, float gray);
+void ctx_drgba_stroke (Ctx *ctx, float r, float g, float b, float a);
+void ctx_cmyka_stroke (Ctx *ctx, float c, float m, float y, float k, float a);
+void ctx_cmyk_stroke (Ctx *ctx, float c, float m, float y, float k);
+void ctx_dcmyka_stroke (Ctx *ctx, float c, float m, float y, float k, float a);
+void ctx_dcmyk_stroke (Ctx *ctx, float c, float m, float y, float k);
+
+
+
void ctx_rgba (Ctx *ctx, float r, float g, float b, float a);
void ctx_rgb (Ctx *ctx, float r, float g, float b);
-void ctx_gray (Ctx *ctx, float gray);
void ctx_rgba8 (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
+
+void ctx_gray (Ctx *ctx, float gray);
void ctx_drgba (Ctx *ctx, float r, float g, float b, float a);
void ctx_cmyka (Ctx *ctx, float c, float m, float y, float k, float a);
void ctx_cmyk (Ctx *ctx, float c, float m, float y, float k);
@@ -292,39 +291,67 @@ void ctx_gradient_add_stop (Ctx *ctx, float pos, float r, float g, float b, floa
void ctx_gradient_add_stop_u8 (Ctx *ctx, float pos, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
-
-/*ctx_texture_init:
+/*
*
- * return value: the actual id assigned, if id is out of range - or later
- * when -1 as id will mean auto-assign.
*/
-int ctx_texture_init (Ctx *ctx,
- int id,
- int width,
- int height,
- int stride,
- CtxPixelFormat format,
- uint8_t *pixels,
- void (*freefunc) (void *pixels, void *user_data),
- void *user_data);
+void ctx_define_texture (Ctx *ctx,
+ const char *eid,
+ int width,
+ int height,
+ int stride,
+ int format,
+ void *data,
+ char *ret_eid);
-int ctx_texture_load (Ctx *ctx, int id, const char *path, int *width, int *height);
-void ctx_texture_release (Ctx *ctx, int id);
+void
+ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh,
+ CtxPixelFormat format, int dst_stride,
+ uint8_t *dst_data);
-/* sets the paint source to be a texture from the texture bank*/
-void ctx_texture (Ctx *ctx, int id, float x, float y);
+void
+ctx_put_image_data (Ctx *ctx, int w, int h, int stride, int format,
+ uint8_t *data,
+ int ox, int oy,
+ int dirtyX, int dirtyY,
+ int dirtyWidth, int dirtyHeight);
+
+
+/* loads an image file from disk into texture, returning pixel width, height
+ * and eid, the eid is based on the path; not the contents - avoiding doing
+ * sha1 checksum of contents. The width and height of the image is returned
+ * along with the used eid, width height or eid can be NULL if we
+ * do not care about their values.
+ */
+void ctx_texture_load (Ctx *ctx,
+ const char *path,
+ int *width,
+ int *height,
+ char *eid);
-/* global used to use the textures from a different context, used
- * by the render threads of fb and sdl backends.
+/* sets the paint source to be a texture by eid
*/
-void ctx_set_texture_source (Ctx *ctx, Ctx *texture_source);
+void ctx_texture (Ctx *ctx, const char *eid, float x, float y);
+
+void ctx_draw_texture (Ctx *ctx, const char *eid, float x, float y, float w, float h);
+
+void ctx_draw_texture_clipped (Ctx *ctx, const char *eid, float x, float y, float w, float h, float sx,
float sy, float swidth, float sheight);
+
+void ctx_draw_image (Ctx *ctx, const char *path, float x, float y, float w, float h);
-void ctx_image_path (Ctx *ctx, const char *path, float x, float y);
+void ctx_draw_image_clipped (Ctx *ctx, const char *path, float x, float y, float w, float h, float sx,
float sy, float swidth, float sheight);
+
+/* used by the render threads of fb and sdl backends.
+ */
+void ctx_set_texture_source (Ctx *ctx, Ctx *texture_source);
+/* used when sharing cache state of eids between clients
+ */
+void ctx_set_texture_cache (Ctx *ctx, Ctx *texture_cache);
typedef struct _CtxDrawlist CtxDrawlist;
typedef void (*CtxFullCb) (CtxDrawlist *drawlist, void *data);
-int ctx_pixel_format_bpp (CtxPixelFormat format);
+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);
void _ctx_set_store_clear (Ctx *ctx);
@@ -500,6 +527,17 @@ _CtxGlyph
float y;
};
+CtxTextAlign ctx_get_text_align (Ctx *ctx);
+CtxTextBaseline ctx_get_text_baseline (Ctx *ctx);
+CtxTextDirection ctx_get_text_direction (Ctx *ctx);
+CtxFillRule ctx_get_fill_rule (Ctx *ctx);
+CtxLineCap ctx_get_line_cap (Ctx *ctx);
+CtxLineJoin ctx_get_line_join (Ctx *ctx);
+CtxCompositingMode ctx_get_compositing_mode (Ctx *ctx);
+CtxBlend ctx_get_blend_mode (Ctx *ctx);
+
+void ctx_gradient_add_stop_string (Ctx *ctx, float pos, const char *color);
+
void ctx_text_align (Ctx *ctx, CtxTextAlign align);
void ctx_text_baseline (Ctx *ctx, CtxTextBaseline baseline);
void ctx_text_direction (Ctx *ctx, CtxTextDirection direction);
@@ -510,7 +548,7 @@ void ctx_compositing_mode (Ctx *ctx, CtxCompositingMode mode);
int ctx_set_drawlist (Ctx *ctx, void *data, int length);
typedef struct _CtxEntry CtxEntry;
/* we only care about the tight packing for this specific
- * structx as we do indexing across members in arrays of it,
+ * struct as we do indexing across members in arrays of it,
* to make sure its size becomes 9bytes -
* the pack pragma is also sufficient on recent gcc versions
*/
@@ -551,10 +589,19 @@ void ctx_glyphs_stroke (Ctx *ctx,
void ctx_text (Ctx *ctx,
const char *string);
-
void ctx_text_stroke (Ctx *ctx,
const char *string);
+void ctx_fill_text (Ctx *ctx,
+ const char *string,
+ float x,
+ float y);
+
+void ctx_stroke_text (Ctx *ctx,
+ const char *string,
+ float x,
+ float y);
+
/* returns the total horizontal advance if string had been rendered */
float ctx_text_width (Ctx *ctx,
const char *string);
@@ -592,6 +639,11 @@ void ctx_set_renderer (Ctx *ctx,
void *renderer);
void *ctx_get_renderer (Ctx *ctx);
+int ctx_renderer_is_sdl (Ctx *ctx);
+int ctx_renderer_is_fb (Ctx *ctx);
+int ctx_renderer_is_ctx (Ctx *ctx);
+int ctx_renderer_is_term (Ctx *ctx);
+
/* the following API is only available when CTX_EVENTS is defined to 1
*
* it provides the ability to register callbacks with the current path
@@ -600,8 +652,8 @@ void *ctx_get_renderer (Ctx *ctx);
unsigned long ctx_ticks (void);
int ctx_is_dirty (Ctx *ctx);
void ctx_set_dirty (Ctx *ctx, int dirty);
-float ctx_get_float (Ctx *ctx, uint32_t hash);
-void ctx_set_float (Ctx *ctx, uint32_t hash, float value);
+float ctx_get_float (Ctx *ctx, uint64_t hash);
+void ctx_set_float (Ctx *ctx, uint64_t hash, float value);
unsigned long ctx_ticks (void);
void ctx_flush (Ctx *ctx);
@@ -610,8 +662,8 @@ void ctx_set_clipboard (Ctx *ctx, const char *text);
char *ctx_get_clipboard (Ctx *ctx);
void _ctx_events_init (Ctx *ctx);
-typedef struct _CtxRectangle CtxRectangle;
-struct _CtxRectangle {
+typedef struct _CtxIntRectangle CtxIntRectangle;
+struct _CtxIntRectangle {
int x;
int y;
int width;
@@ -627,26 +679,27 @@ typedef void (*CtxCb) (CtxEvent *event,
typedef void (*CtxDestroyNotify) (void *data);
enum _CtxEventType {
- CTX_PRESS = 1 << 0,
- CTX_MOTION = 1 << 1,
- CTX_RELEASE = 1 << 2,
- CTX_ENTER = 1 << 3,
- CTX_LEAVE = 1 << 4,
- CTX_TAP = 1 << 5,
- CTX_TAP_AND_HOLD = 1 << 6,
+ CTX_PRESS = 1 << 0,
+ CTX_MOTION = 1 << 1,
+ CTX_RELEASE = 1 << 2,
+ CTX_ENTER = 1 << 3,
+ CTX_LEAVE = 1 << 4,
+ CTX_TAP = 1 << 5,
+ CTX_TAP_AND_HOLD = 1 << 6,
/* NYI: SWIPE, ZOOM ROT_ZOOM, */
- CTX_DRAG_PRESS = 1 << 7,
- CTX_DRAG_MOTION = 1 << 8,
- CTX_DRAG_RELEASE = 1 << 9,
- CTX_KEY_DOWN = 1 << 10,
- CTX_KEY_UP = 1 << 11,
- CTX_SCROLL = 1 << 12,
- CTX_MESSAGE = 1 << 13,
- CTX_DROP = 1 << 14,
+ CTX_DRAG_PRESS = 1 << 7,
+ CTX_DRAG_MOTION = 1 << 8,
+ CTX_DRAG_RELEASE = 1 << 9,
+ CTX_KEY_PRESS = 1 << 10,
+ CTX_KEY_DOWN = 1 << 11,
+ CTX_KEY_UP = 1 << 12,
+ CTX_SCROLL = 1 << 13,
+ CTX_MESSAGE = 1 << 14,
+ CTX_DROP = 1 << 15,
- CTX_SET_CURSOR= 1 << 15, // used internally
+ CTX_SET_CURSOR = 1 << 16, // used internally
/* client should store state - preparing
* for restart
@@ -655,7 +708,7 @@ enum _CtxEventType {
CTX_TAPS = (CTX_TAP | CTX_TAP_AND_HOLD),
CTX_CROSSING = (CTX_ENTER | CTX_LEAVE),
CTX_DRAG = (CTX_DRAG_PRESS | CTX_DRAG_MOTION | CTX_DRAG_RELEASE),
- CTX_KEY = (CTX_KEY_DOWN | CTX_KEY_UP),
+ CTX_KEY = (CTX_KEY_DOWN | CTX_KEY_UP | CTX_KEY_PRESS),
CTX_MISC = (CTX_MESSAGE),
CTX_ANY = (CTX_POINTER | CTX_DRAG | CTX_CROSSING | CTX_KEY | CTX_MISC | CTX_TAPS),
};
@@ -671,10 +724,10 @@ struct _CtxEvent {
CtxModifierState state;
- int device_no; /* 0 = left mouse button / virtual focus */
- /* 1 = middle mouse button */
- /* 2 = right mouse button */
- /* 3 = first multi-touch .. (NYI) */
+ int device_no; /* 0 = left mouse button / virtual focus */
+ /* 1 = middle mouse button */
+ /* 2 = right mouse button */
+ /* 3 = first multi-touch .. (NYI) */
float device_x; /* untransformed (device) coordinates */
float device_y;
@@ -690,7 +743,7 @@ struct _CtxEvent {
float delta_y; /* y - prev_y, redundant - .. */
- unsigned int unicode; /* only valid for key-events */
+ unsigned int unicode; /* only valid for key-events, re-use as keycode? */
const char *string; /* as key can be "up" "down" "space" "backspace" "a" "b" "ø" etc .. */
/* this is also where the message is delivered for
* MESSAGE events
@@ -742,6 +795,8 @@ int ctx_add_idle (Ctx *ctx, int (*idle_cb)(Ctx *ctx, void *idle_data
void ctx_add_hit_region (Ctx *ctx, const char *id);
+void ctx_set_title (Ctx *ctx, const char *title);
+
void ctx_listen_full (Ctx *ctx,
float x,
float y,
@@ -787,8 +842,14 @@ int ctx_events_height (Ctx *ctx);
* are called in response to these being called.
*/
+int ctx_key_down (Ctx *ctx, unsigned int keyval,
+ const char *string, uint32_t time);
+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);
@@ -797,7 +858,6 @@ 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);
-
typedef enum
{
CTX_CONT = '\0', // - contains args from preceding entry
@@ -836,7 +896,7 @@ typedef enum
CTX_FILL = 'F', //
CTX_RESTORE = 'G', //
CTX_HOR_LINE_TO = 'H', // x
- CTX_BITPIX = 'I', // x, y, width, height, scale // NYI
+ CTX_DEFINE_TEXTURE = 'I', // "eid" width height format "data"
CTX_ROTATE = 'J', // radians
CTX_COLOR = 'K', // model, c1 c2 c3 ca - has a variable set of
// arguments.
@@ -883,7 +943,7 @@ typedef enum
CTX_RECTANGLE = 'r', // x y width height
CTX_REL_SMOOTH_TO = 's', // cx cy x y
CTX_REL_SMOOTHQ_TO = 't', // x y
- CTX_TEXT_STROKE = 'u', // string - utf8 string
+ CTX_STROKE_TEXT = 'u', // string - utf8 string
CTX_REL_VER_LINE_TO = 'v', // y
CTX_GLYPH = 'w', // unichar fontsize
CTX_TEXT = 'x', // string | kern - utf8 data to shape or horizontal kerning amount
@@ -920,9 +980,14 @@ typedef enum
CTX_SHADOW_COLOR = 141, // kC
CTX_SHADOW_OFFSET_X = 142, // kx
CTX_SHADOW_OFFSET_Y = 143, // ky
+ CTX_IMAGE_SMOOTHING = 144, // kS
+ CTX_LINE_DASH_OFFSET = 145, // kD lineDashOffset
// items marked with % are currently only for the parser
// for instance for svg compatibility or simulated/converted color spaces
// not the serialization/internal render stream
+ //
+ CTX_STROKE_RECT = 200, // strokeRect - only exist in long form
+ CTX_FILL_RECT = 201, // fillRect - only exist in long form
} CtxCode;
@@ -1027,6 +1092,33 @@ struct
uint8_t data[8]; /* .. and continues */
} colorspace;
struct
+ {
+ uint8_t code;
+ float x;
+ float y;
+ uint8_t code_data;
+ uint32_t stringlen;
+ uint32_t blocklen;
+ uint8_t code_cont;
+ char eid[8]; /* .. and continues */
+ } texture;
+ struct
+ {
+ uint8_t code;
+ uint32_t width;
+ uint32_t height;
+ uint8_t code_cont0;
+ uint16_t format;
+ uint16_t pad0;
+ uint32_t pad1;
+ uint8_t code_data;
+ uint32_t stringlen;
+ uint32_t blocklen;
+ uint8_t code_cont1;
+ char eid[8]; /* .. and continues */
+ // followed by - in variable offset code_Data, data_len, datablock_len, cont, pixeldata
+ } define_texture;
+ struct
{
uint8_t code;
float pad;
@@ -1180,6 +1272,14 @@ struct
uint8_t pad1;
float radius;
} rectangle;
+ struct {
+ uint8_t code;
+ float x;
+ float y;
+ uint8_t pad0;
+ float width;
+ float height;
+ } view_box;
struct
{
@@ -1570,7 +1670,7 @@ typedef struct _CtxParser CtxParser;
float cell_height,
int cursor_x,
int cursor_y,
- int (*set_prop)(void *prop_data, uint32_t key, const char *data, int len),
+ int (*set_prop)(void *prop_data, uint64_t key, const char *data, int len),
int (*get_prop)(void *prop_Data, const char *key, char **data, int *len),
void *prop_data,
void (*exit) (void *exit_data),
@@ -1583,13 +1683,23 @@ enum _CtxColorSpace
CTX_COLOR_SPACE_DEVICE_CMYK,
CTX_COLOR_SPACE_USER_RGB,
CTX_COLOR_SPACE_USER_CMYK,
+ CTX_COLOR_SPACE_TEXTURE
};
typedef enum _CtxColorSpace CtxColorSpace;
-void ctx_colorspace (Ctx *ctx,
- CtxColorSpace space_slot,
- unsigned char *data,
- int data_length);
+/* sets the color space for a slot, the space is either a string of
+ * "sRGB" "rec2020" .. etc or an icc profile.
+ *
+ * The slots device_rgb and device_cmyk is mostly to be handled outside drawing
+ * code, and user_rgb and user_cmyk is to be used. With no user_cmyk set
+ * user_cmyk == device_cmyk.
+ *
+ * The set profiles follows the graphics state.
+ */
+void ctx_color_space (Ctx *ctx,
+ CtxColorSpace space_slot,
+ unsigned char *data,
+ int data_length);
void
ctx_parser_set_size (CtxParser *parser,
@@ -1600,12 +1710,29 @@ ctx_parser_set_size (CtxParser *parser,
void ctx_parser_feed_byte (CtxParser *parser, int byte);
+int
+ctx_get_contents (const char *path,
+ unsigned char **contents,
+ long *length);
+
void ctx_parser_free (CtxParser *parser);
+typedef struct _CtxSHA1 CtxSHA1;
+
+void
+ctx_bin2base64 (const void *bin,
+ int bin_length,
+ char *ascii);
+int
+ctx_base642bin (const char *ascii,
+ int *length,
+ unsigned char *bin);
+float ctx_term_get_cell_width (Ctx *ctx);
+float ctx_term_get_cell_height (Ctx *ctx);
#ifndef CTX_CODEC_CHAR
//#define CTX_CODEC_CHAR '\035'
//#define CTX_CODEC_CHAR 'a'
-#define CTX_CODEC_CHAR '\077'
+#define CTX_CODEC_CHAR '\020' // datalink escape
//#define CTX_CODEC_CHAR '^'
#endif
@@ -1619,23 +1746,6 @@ void ctx_parser_free (CtxParser *parser);
#endif
#ifndef __CTX_H__
#define __CTX_H__
-/* mrg - MicroRaptor Gui
- * Copyright (c) 2014 Øyvind Kolås <pippin hodefoting com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
#ifndef CTX_STRING_H
#define CTX_STRING_H
@@ -1678,155 +1788,6 @@ char *ctx_strdup_printf (const char *format, ...);
#define FALSE 0
#endif
-#endif
- /* Copyright (C) 2020 Øyvind Kolås <pippin gimp org>
- */
-
-#if CTX_FORMATTER
-
-/* returns the maximum string length including terminating \0 */
-static int ctx_a85enc_len (int input_length)
-{
- return (input_length / 4 + 1) * 5;
-}
-
-static int ctx_a85enc (const void *srcp, char *dst, int count)
-{
- const uint8_t *src = (uint8_t*)srcp;
- int out_len = 0;
-
- int padding = 4-(count % 4);
- if (padding == 4) padding = 0;
-
- for (int i = 0; i < (count+3)/4; i ++)
- {
- uint32_t input = 0;
- for (int j = 0; j < 4; j++)
- {
- input = (input << 8);
- if (i*4+j<=count)
- input += src[i*4+j];
- }
-
- int divisor = 85 * 85 * 85 * 85;
- if (input == 0)
- {
- dst[out_len++] = 'z';
- }
- /* todo: encode 4 spaces as 'y' */
- else
- {
- for (int j = 0; j < 5; j++)
- {
- dst[out_len++] = ((input / divisor) % 85) + '!';
- divisor /= 85;
- }
- }
- }
- out_len -= padding;
- dst[out_len]=0;
- return out_len;
-}
-#endif
-
-#if CTX_PARSER
-
-static int ctx_a85dec (const char *src, char *dst, int count)
-{
- int out_len = 0;
- uint32_t val = 0;
- int k = 0;
- int i = 0;
- for (i = 0; i < count; i ++)
- {
- val *= 85;
- if (src[i] == '~')
- {
- break;
- }
- else if (src[i] == 'z')
- {
- for (int j = 0; j < 4; j++)
- dst[out_len++] = 0;
- k = 0;
- }
- else if (src[i] == 'y') /* lets support this extension */
- {
- for (int j = 0; j < 4; j++)
- dst[out_len++] = 32;
- k = 0;
- }
- else if (src[i] >= '!' && src[i] <= 'u')
- {
- val += src[i]-'!';
- if (k % 5 == 4)
- {
- for (int j = 0; j < 4; j++)
- {
- dst[out_len++] = (val & (0xff << 24)) >> 24;
- val <<= 8;
- }
- val = 0;
- }
- k++;
- }
- // we treat all other chars as whitespace
- }
- if (src[i] != '~')
- {
- val *= 85;
- }
- k = k % 5;
- if (k)
- {
- val += 84;
- for (int j = k; j < 4; j++)
- {
- val *= 85;
- val += 84;
- }
-
- for (int j = 0; j < k-1; j++)
- {
- dst[out_len++] = (val & (0xff << 24)) >> 24;
- val <<= 8;
- }
- val = 0;
- }
- dst[out_len] = 0;
- return out_len;
-}
-
-#if 0
-static int ctx_a85len (const char *src, int count)
-{
- int out_len = 0;
- int k = 0;
- for (int i = 0; i < count; i ++)
- {
- if (src[i] == '~')
- break;
- else if (src[i] == 'z')
- {
- for (int j = 0; j < 4; j++)
- out_len++;
- k = 0;
- }
- else if (src[i] >= '!' && src[i] <= 'u')
- {
- if (k % 5 == 4)
- out_len += 4;
- k++;
- }
- // we treat all other chars as whitespace
- }
- k = k % 5;
- if (k)
- out_len += k-1;
- return out_len;
-}
-#endif
-
#endif
#ifndef _CTX_INTERNAL_FONT_
#define _CTX_INTERNAL_FONT_
@@ -3618,8 +3579,19 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
#endif
+#ifndef CTX_PARSER_FIXED_TEMP
+#define CTX_PARSER_FIXED_TEMP 0
+ // when 1 CTX_PARSER_MAXLEN is the fixed max stringlen
+#endif // and no allocations happens beyond creating the parser,
+ // when 0 the scratchbuf for parsing is a separate dynamically
+ // growing buffer, that maxes out at CTX_PARSER_MAXLEN
+ //
#ifndef CTX_PARSER_MAXLEN
-#define CTX_PARSER_MAXLEN 1024 // this is the largest text string we support
+#if CTX_PARSER_FIXED_TEMP
+#define CTX_PARSER_MAXLEN 1024*128 // This is the maximum texture/string size supported
+#else
+#define CTX_PARSER_MAXLEN 1024*1024*16 // 16mb
+#endif
#endif
#ifndef CTX_COMPOSITING_GROUPS
@@ -3699,14 +3671,15 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
* edgelist and drawlist.
*/
#ifndef CTX_MIN_JOURNAL_SIZE
-#define CTX_MIN_JOURNAL_SIZE 1024*64
+#define CTX_MIN_JOURNAL_SIZE 512
#endif
/* The maximum size we permit the drawlist to grow to,
* the memory used is this number * 9, where 9 is sizeof(CtxEntry)
*/
#ifndef CTX_MAX_JOURNAL_SIZE
-#define CTX_MAX_JOURNAL_SIZE CTX_MIN_JOURNAL_SIZE
+//#define CTX_MAX_JOURNAL_SIZE CTX_MIN_JOURNAL_SIZE
+#define CTX_MAX_JOURNAL_SIZE 1024*1024*16
#endif
#ifndef CTX_DRAWLIST_STATIC
@@ -3733,7 +3706,7 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
// properties still make use of it)
//
// for desktop-use this should be fully dynamic, possibly
- // with chained pools
+ // with chained pools, gradients are stored here.
#define CTX_STRINGPOOL_SIZE 1000 //
#endif
@@ -3977,7 +3950,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 100
+#define CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS 120
#endif
#ifndef CTX_MAX_FONTS
@@ -4034,7 +4007,6 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
#ifdef CTX_RASTERIZER
#if CTX_RASTERIZER==0
-#elif CTX_RASTERIZER==1
#else
#undef CTX_RASTERIZER
#define CTX_RASTERIZER 1
@@ -4068,15 +4040,178 @@ static inline CtxList *ctx_list_find_custom (CtxList *list,
#ifndef CTX_SCREENSHOT
#define CTX_SCREENSHOT 0
#endif
-#ifndef __CTX_EXTRA_H
-#define __CTX_EXTRA_H
-
-
-#define CTX_CLAMP(val,min,max) ((val)<(min)?(min):(val)>(max)?(max):(val))
-static inline int ctx_mini (int a, int b) { if (a < b) return a; return b; }
-static inline float ctx_minf (float a, float b) { if (a < b) return a; return b; }
-static inline int ctx_maxi (int a, int b) { if (a > b) return a; return b; }
-static inline float ctx_maxf (float a, float b) { if (a > b) return a; return b; }
+
+
+#ifndef CTX_TILED
+#if CTX_SDL || CTX_FB
+#define CTX_TILED 1
+#else
+#define CTX_TILED 0
+#endif
+#endif
+
+ /* Copyright (C) 2020 Øyvind Kolås <pippin gimp org>
+ */
+
+#if CTX_FORMATTER
+
+/* returns the maximum string length including terminating \0 */
+static int ctx_a85enc_len (int input_length)
+{
+ return (input_length / 4 + 1) * 5;
+}
+
+static int ctx_a85enc (const void *srcp, char *dst, int count)
+{
+ const uint8_t *src = (uint8_t*)srcp;
+ int out_len = 0;
+
+ int padding = 4-(count % 4);
+ if (padding == 4) padding = 0;
+
+ for (int i = 0; i < (count+3)/4; i ++)
+ {
+ uint32_t input = 0;
+ for (int j = 0; j < 4; j++)
+ {
+ input = (input << 8);
+ if (i*4+j<=count)
+ input += src[i*4+j];
+ }
+
+ int divisor = 85 * 85 * 85 * 85;
+#if 0
+ if (input == 0)
+ {
+ dst[out_len++] = 'z';
+ }
+ /* todo: encode 4 spaces as 'y' */
+ else
+#endif
+ {
+ for (int j = 0; j < 5; j++)
+ {
+ dst[out_len++] = ((input / divisor) % 85) + '!';
+ divisor /= 85;
+ }
+ }
+ }
+ out_len -= padding;
+ dst[out_len]=0;
+ return out_len;
+}
+#endif
+
+#if CTX_PARSER
+
+static int ctx_a85dec (const char *src, char *dst, int count)
+{
+ int out_len = 0;
+ uint32_t val = 0;
+ int k = 0;
+ int i = 0;
+ for (i = 0; i < count; i ++)
+ {
+ val *= 85;
+ if (src[i] == '~')
+ {
+ break;
+ }
+#if 0
+ else if (src[i] == 'z')
+ {
+ for (int j = 0; j < 4; j++)
+ dst[out_len++] = 0;
+ k = 0;
+ }
+ else if (src[i] == 'y') /* lets support this extension */
+ {
+ for (int j = 0; j < 4; j++)
+ dst[out_len++] = 32;
+ k = 0;
+ }
+#endif
+ else if (src[i] >= '!' && src[i] <= 'u')
+ {
+ val += src[i]-'!';
+ if (k % 5 == 4)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ dst[out_len++] = (val & (0xff << 24)) >> 24;
+ val <<= 8;
+ }
+ val = 0;
+ }
+ k++;
+ }
+ // we treat all other chars as whitespace
+ }
+ if (src[i] != '~')
+ {
+ val *= 85;
+ }
+ k = k % 5;
+ if (k)
+ {
+ val += 84;
+ for (int j = k; j < 4; j++)
+ {
+ val *= 85;
+ val += 84;
+ }
+
+ for (int j = 0; j < k-1; j++)
+ {
+ dst[out_len++] = (val & (0xff << 24)) >> 24;
+ val <<= 8;
+ }
+ val = 0;
+ }
+ dst[out_len] = 0;
+ return out_len;
+}
+
+#if 0
+static int ctx_a85len (const char *src, int count)
+{
+ int out_len = 0;
+ int k = 0;
+ for (int i = 0; i < count; i ++)
+ {
+ if (src[i] == '~')
+ break;
+ else if (src[i] == 'z')
+ {
+ for (int j = 0; j < 4; j++)
+ out_len++;
+ k = 0;
+ }
+ else if (src[i] >= '!' && src[i] <= 'u')
+ {
+ if (k % 5 == 4)
+ out_len += 4;
+ k++;
+ }
+ // we treat all other chars as whitespace
+ }
+ k = k % 5;
+ if (k)
+ out_len += k-1;
+ return out_len;
+}
+#endif
+
+#endif
+#ifndef __CTX_EXTRA_H
+#define __CTX_EXTRA_H
+
+
+#define CTX_CLAMP(val,min,max) ((val)<(min)?(min):(val)>(max)?(max):(val))
+static inline int ctx_mini (int a, int b) { if (a < b) return a; return b; }
+static inline float ctx_minf (float a, float b) { if (a < b) return a; return b; }
+static inline int ctx_maxi (int a, int b) { if (a > b) return a; return b; }
+static inline float ctx_maxf (float a, float b) { if (a > b) return a; return b; }
typedef enum CtxOutputmode
@@ -4090,84 +4225,9 @@ typedef enum CtxOutputmode
CTX_OUTPUT_MODE_UI
} CtxOutputmode;
-#define CTX_NORMALIZE(a) (((a)=='-')?'_':(a))
-#define CTX_NORMALIZE_CASEFOLDED(a) (((a)=='-')?'_':((((a)>='A')&&((a)<='Z'))?(a)+32:(a)))
-/* We use the preprocessor to compute case invariant hashes
- * of strings directly, if there is collisions in our vocabulary
- * the compiler tells us.
- */
-#define CTX_STRHash(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a27,a12,a13) (\
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a0))+ \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a1))*27)+ \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a2))*27*27)+ \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a3))*27*27*27)+ \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a4))*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a5))*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a6))*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a7))*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a8))*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a9))*27*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a10))*27*27*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a27))*27*27*27*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a12))*27*27*27*27*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE_CASEFOLDED(a13))*27*27*27*27*27*27*27*27*27*27*27*27*27)))
-
-#define CTX_STRH(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a27,a12,a13) (\
- (((uint32_t)CTX_NORMALIZE(a0))+ \
- (((uint32_t)CTX_NORMALIZE(a1))*27)+ \
- (((uint32_t)CTX_NORMALIZE(a2))*27*27)+ \
- (((uint32_t)CTX_NORMALIZE(a3))*27*27*27)+ \
- (((uint32_t)CTX_NORMALIZE(a4))*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a5))*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a6))*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a7))*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a8))*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a9))*27*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a10))*27*27*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a27))*27*27*27*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a12))*27*27*27*27*27*27*27*27*27*27*27*27) + \
- (((uint32_t)CTX_NORMALIZE(a13))*27*27*27*27*27*27*27*27*27*27*27*27*27)))
-
-static inline uint32_t ctx_strhash (const char *str, int case_insensitive)
-{
- uint32_t ret;
- if (!str) return 0;
- int len = strlen (str);
- if (case_insensitive)
- ret =CTX_STRHash(len>=0?str[0]:0,
- len>=1?str[1]:0,
- len>=2?str[2]:0,
- len>=3?str[3]:0,
- len>=4?str[4]:0,
- len>=5?str[5]:0,
- len>=6?str[6]:0,
- len>=7?str[7]:0,
- len>=8?str[8]:0,
- len>=9?str[9]:0,
- len>=10?str[10]:0,
- len>=11?str[11]:0,
- len>=12?str[12]:0,
- len>=13?str[13]:0);
- else
- ret =CTX_STRH(len>=0?str[0]:0,
- len>=1?str[1]:0,
- len>=2?str[2]:0,
- len>=3?str[3]:0,
- len>=4?str[4]:0,
- len>=5?str[5]:0,
- len>=6?str[6]:0,
- len>=7?str[7]:0,
- len>=8?str[8]:0,
- len>=9?str[9]:0,
- len>=10?str[10]:0,
- len>=11?str[11]:0,
- len>=12?str[12]:0,
- len>=13?str[13]:0);
- return ret;
-}
#if CTX_FORCE_INLINES
#define CTX_INLINE inline __attribute__((always_inline))
@@ -4353,8 +4413,8 @@ static inline float _ctx_parse_float (const char *str, char **endptr)
return strtod (str, endptr); /* XXX: , vs . problem in some locales */
}
-const char *ctx_get_string (Ctx *ctx, uint32_t hash);
-void ctx_set_string (Ctx *ctx, uint32_t hash, const char *value);
+const char *ctx_get_string (Ctx *ctx, uint64_t hash);
+void ctx_set_string (Ctx *ctx, uint64_t hash, const char *value);
typedef struct _CtxColor CtxColor;
typedef struct _CtxBuffer CtxBuffer;
@@ -4366,15 +4426,16 @@ struct
};
void ctx_get_matrix (Ctx *ctx, CtxMatrix *matrix);
-int ctx_color (Ctx *ctx, const char *string);
+int ctx_color_fill (Ctx *ctx, const char *string);
+int ctx_color_stroke (Ctx *ctx, const char *string);
typedef struct _CtxState CtxState;
CtxColor *ctx_color_new ();
CtxState *ctx_get_state (Ctx *ctx);
void ctx_color_get_rgba (CtxState *state, CtxColor *color, float *out);
void ctx_color_set_rgba (CtxState *state, CtxColor *color, float r, float g, float b, float a);
void ctx_color_free (CtxColor *color);
-void ctx_set_color (Ctx *ctx, uint32_t hash, CtxColor *color);
-int ctx_get_color (Ctx *ctx, uint32_t hash, CtxColor *color);
+void ctx_set_color (Ctx *ctx, uint64_t hash, CtxColor *color);
+int ctx_get_color (Ctx *ctx, uint64_t hash, CtxColor *color);
int ctx_color_set_from_string (Ctx *ctx, CtxColor *color, const char *string);
int ctx_color_is_transparent (CtxColor *color);
@@ -4394,9 +4455,17 @@ void ctx_matrix_multiply (CtxMatrix *result,
const CtxMatrix *s);
void
ctx_matrix_translate (CtxMatrix *matrix, float x, float y);
-int ctx_is_set_now (Ctx *ctx, uint32_t hash);
+int ctx_is_set_now (Ctx *ctx, uint64_t hash);
void ctx_set_size (Ctx *ctx, int width, int height);
+static inline float ctx_matrix_get_scale (CtxMatrix *matrix)
+{
+ return ctx_maxf (ctx_maxf (ctx_fabsf (matrix->m[0][0]),
+ ctx_fabsf (matrix->m[0][1]) ),
+ ctx_maxf (ctx_fabsf (matrix->m[1][0]),
+ ctx_fabsf (matrix->m[1][1]) ) );
+}
+
#if CTX_FONTS_FROM_FILE
int ctx_load_font_ttf_file (const char *name, const char *path);
int
@@ -4409,221 +4478,249 @@ _ctx_file_get_contents (const char *path,
#ifndef __CTX_CONSTANTS
#define __CTX_CONSTANTS
-#define CTX_add_stop CTX_STRH('a','d','d','_','s','t','o','p',0,0,0,0,0,0)
-#define CTX_addStop CTX_STRH('a','d','d','S','t','o','p',0,0,0,0,0,0,0)
-#define CTX_alphabetic CTX_STRH('a','l','p','h','a','b','e','t','i','c',0,0,0,0)
-#define CTX_arc CTX_STRH('a','r','c',0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_arc_to CTX_STRH('a','r','c','_','t','o',0,0,0,0,0,0,0,0)
-#define CTX_arcTo CTX_STRH('a','r','c','T','o',0,0,0,0,0,0,0,0,0)
-#define CTX_begin_path CTX_STRH('b','e','g','i','n','_','p','a','t','h',0,0,0,0)
-#define CTX_beginPath CTX_STRH('b','e','g','i','n','P','a','t','h',0,0,0,0,0)
-#define CTX_bevel CTX_STRH('b','e','v','e','l',0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_bottom CTX_STRH('b','o','t','t','o','m',0,0,0,0,0,0,0,0)
-#define CTX_cap CTX_STRH('c','a','p',0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_center CTX_STRH('c','e','n','t','e','r', 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_clear CTX_STRH('c','l','e','a','r',0,0,0,0,0,0,0,0,0)
-#define CTX_color CTX_STRH('c','o','l','o','r',0,0,0,0,0,0,0,0,0)
-#define CTX_copy CTX_STRH('c','o','p','y',0,0,0,0,0,0,0,0,0,0)
-#define CTX_clip CTX_STRH('c','l','i','p',0,0,0,0,0,0,0,0,0,0)
-#define CTX_close_path CTX_STRH('c','l','o','s','e','_','p','a','t','h',0,0,0,0)
-#define CTX_closePath CTX_STRH('c','l','o','s','e','P','a','t','h',0,0,0,0,0)
-#define CTX_cmyka CTX_STRH('c','m','y','k','a',0,0,0,0,0,0,0,0,0)
-#define CTX_cmyk CTX_STRH('c','m','y','k',0,0,0,0,0,0,0,0,0,0)
-#define CTX_color CTX_STRH('c','o','l','o','r',0,0,0,0,0,0,0,0,0)
-
-#define CTX_blending CTX_STRH('b','l','e','n','d','i','n','g',0,0,0,0,0,0)
-#define CTX_blend CTX_STRH('b','l','e','n','d',0,0,0,0,0,0,0,0,0)
-#define CTX_blending_mode CTX_STRH('b','l','e','n','d','i','n','g','_','m','o','d','e',0)
-#define CTX_blendingMode CTX_STRH('b','l','e','n','d','i','n','g','M','o','d','e',0,0)
-#define CTX_blend_mode CTX_STRH('b','l','e','n','d','_','m','o','d','e',0,0,0,0)
-#define CTX_blendMode CTX_STRH('b','l','e','n','d','M','o','d','e',0,0,0,0,0)
-
-#define CTX_composite CTX_STRH('c','o','m','p','o','s','i','t','i','e',0,0,0,0)
-#define CTX_compositing_mode CTX_STRH('c','o','m','p','o','s','i','t','i','n','g','_','m','o')
-#define CTX_compositingMode CTX_STRH('c','o','m','p','o','s','i','t','i','n','g','M','o','d')
-#define CTX_curve_to CTX_STRH('c','u','r','v','e','_','t','o',0,0,0,0,0,0)
-#define CTX_curveTo CTX_STRH('c','u','r','v','e','T','o',0,0,0,0,0,0,0)
-#define CTX_darken CTX_STRH('d','a','r','k','e','n',0,0,0,0,0,0,0,0)
-#define CTX_defineGlyph CTX_STRH('d','e','f','i','n','e','G','l','y','p','h',0,0,0)
-#define CTX_kerningPair CTX_STRH('k','e','r','n','i','n','g','P','a','i','r',0,0,0)
-#define CTX_destinationIn CTX_STRH('d','e','s','t','i','n','a','t','i','o','n','I','n',0)
-#define CTX_destination_in CTX_STRH('d','e','s','t','i','n','a','t','i','o','n','_','i','n')
-#define CTX_destinationAtop CTX_STRH('d','e','s','t','i','n','a','t','i','o','n','A','t','o')
-#define CTX_destination_atop CTX_STRH('d','e','s','t','i','n','a','t','i','o','n','_','a','t')
-#define CTX_destinationOver CTX_STRH('d','e','s','t','i','n','a','t','i','o','n','O','v','e')
-#define CTX_destination_over CTX_STRH('d','e','s','t','i','n','a','t','i','o','n','-','o','v')
-#define CTX_destinationOut CTX_STRH('d','e','s','t','i','n','a','t','i','o','n','O','u','t')
-#define CTX_destination_out CTX_STRH('d','e','s','t','i','n','a','t','i','o','n','_','o','u')
-#define CTX_difference CTX_STRH('d','i','f','f','e','r','e','n','c','e',0,0,0,0)
-#define CTX_done CTX_STRH('d','o','n','e',0,0,0,0,0,0,0,0,0,0)
-#define CTX_drgba CTX_STRH('d','r','g','b','a',0,0,0,0,0,0,0,0,0)
-#define CTX_drgb CTX_STRH('d','r','g','b',0,0,0,0,0,0,0,0,0,0)
-#define CTX_end CTX_STRH('e','n','d',0,0,0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_endfun CTX_STRH('e','n','d','f','u','n',0,0,0,0,0,0,0,0)
-
-#define CTX_end_group CTX_STRH('e','n','d','_','G','r','o','u','p',0,0,0,0,0)
-#define CTX_endGroup CTX_STRH('e','n','d','G','r','o','u','p',0,0,0,0,0,0)
-
-#define CTX_even_odd CTX_STRH('e','v','e','n','_','o','d','d',0,0,0,0,0,0)
-#define CTX_evenOdd CTX_STRH('e','v','e','n','O','d','d',0,0,0,0,0,0,0)
-
-
-
-#define CTX_exit CTX_STRH('e','x','i','t',0,0,0,0,0,0,0,0,0,0)
-#define CTX_fill CTX_STRH('f','i','l','l',0,0,0,0,0,0,0,0,0,0)
-#define CTX_fill_rule CTX_STRH('f','i','l','l','_','r','u','l','e',0,0,0,0,0)
-#define CTX_fillRule CTX_STRH('f','i','l','l','R','u','l','e',0,0,0,0,0,0)
-#define CTX_flush CTX_STRH('f','l','u','s','h',0,0,0,0,0,0,0,0,0)
-#define CTX_font CTX_STRH('f','o','n','t',0,0,0,0,0,0,0,0,0,0)
-#define CTX_font_size CTX_STRH('f','o','n','t','_','s','i','z','e',0,0,0,0,0)
-#define CTX_setFontSize CTX_STRH('s','e','t','F','o','n','t','S','i','z','e',0,0,0)
-#define CTX_fontSize CTX_STRH('f','o','n','t','S','i','z','e',0,0,0,0,0,0)
-#define CTX_function CTX_STRH('f','u','n','c','t','i','o','n',0,0,0,0,0,0)
-#define CTX_getkey CTX_STRH('g','e','t','k','e','y',0,0,0,0,0,0,0,0)
-#define CTX_global_alpha CTX_STRH('g','l','o','b','a','l','_','a','l','p','h','a',0,0)
-#define CTX_globalAlpha CTX_STRH('g','l','o','b','a','l','A','l','p','h','a',0,0,0)
-#define CTX_glyph CTX_STRH('g','l','y','p','h',0,0,0,0,0,0,0,0,0)
-#define CTX_gradient_add_stop CTX_STRH('g','r','a','d','i','e','n','t','_','a','d','d','_','s')
-#define CTX_gradientAddStop CTX_STRH('g','r','a','d','i','e','n','t','A','d','d','S','t','o')
-#define CTX_graya CTX_STRH('g','r','a','y','a',0,0,0,0,0,0,0,0,0)
-#define CTX_gray CTX_STRH('g','r','a','y',0,0,0,0,0,0,0,0,0,0)
-#define CTX_H
-#define CTX_hanging CTX_STRH('h','a','n','g','i','n','g',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)
-#define CTX_hor_line_to CTX_STRH('h','o','r','_','l','i','n','e','_','t','o',0,0,0)
-#define CTX_horLineTo CTX_STRH('h','o','r','L','i','n','e','T','o',0,0,0,0,0)
-#define CTX_hue CTX_STRH('h','u','e',0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_identity CTX_STRH('i','d','e','n','t','i','t','y',0,0,0,0,0,0)
-#define CTX_ideographic CTX_STRH('i','d','e','o','g','r','a','p','h','i','c',0,0,0)
-#define CTX_join CTX_STRH('j','o','i','n',0,0,0,0,0,0,0,0,0,0)
-#define CTX_laba CTX_STRH('l','a','b','a',0,0,0,0,0,0,0,0,0,0)
-#define CTX_lab CTX_STRH('l','a','b',0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_lcha CTX_STRH('l','c','h','a',0,0,0,0,0,0,0,0,0,0)
-#define CTX_lch CTX_STRH('l','c','h',0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_left CTX_STRH('l','e','f','t',0,0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_lighter CTX_STRH('l','i','g','h','t','e','r',0,0,0,0,0,0,0)
-#define CTX_lighten CTX_STRH('l','i','g','h','t','e','n',0,0,0,0,0,0,0)
-#define CTX_linear_gradient CTX_STRH('l','i','n','e','a','r','_','g','r','a','d','i','e','n')
-#define CTX_linearGradient CTX_STRH('l','i','n','e','a','r','G','r','a','d','i','e','n','t')
-#define CTX_line_cap CTX_STRH('l','i','n','e','_','c','a','p',0,0,0,0,0,0)
-#define CTX_lineCap CTX_STRH('l','i','n','e','C','a','p',0,0,0,0,0,0,0)
-#define CTX_setLineCap CTX_STRH('s','e','t','L','i','n','e','C','a','p',0,0,0,0)
-#define CTX_line_height CTX_STRH('l','i','n','e','_','h','e','i','h','t',0,0,0,0)
-#define CTX_line_join CTX_STRH('l','i','n','e','_','j','o','i','n',0,0,0,0,0)
-#define CTX_lineJoin CTX_STRH('l','i','n','e','J','o','i','n',0,0,0,0,0,0)
-#define CTX_setLineJoin CTX_STRH('s','e','t','L','i','n','e','J','o','i','n',0,0,0)
-#define CTX_line_spacing CTX_STRH('l','i','n','e','_','s','p','a','c','i','n','g',0,0)
-#define CTX_line_to CTX_STRH('l','i','n','e','_','t','o',0,0,0,0,0,0,0)
-#define CTX_lineTo CTX_STRH('l','i','n','e','T','o',0,0,0,0,0,0,0,0)
-#define CTX_lineDash CTX_STRH('l','i','n','e','D','a','s','h',0,0,0,0,0,0)
-#define CTX_line_width CTX_STRH('l','i','n','e','_','w','i','d','t','h',0,0,0,0)
-#define CTX_lineWidth CTX_STRH('l','i','n','e','W','i','d','t','h',0,0,0,0,0)
-#define CTX_setLineWidth CTX_STRH('s','e','t','L','i','n','e','W','i','d','t','h',0,0)
-#define CTX_view_box CTX_STRH('v','i','e','w','_','b','o','x',0,0,0,0,0,0)
-#define CTX_viewBox CTX_STRH('v','i','e','w','B','o','x',0,0,0,0,0,0,0)
-#define CTX_middle CTX_STRH('m','i','d','d','l','e',0, 0, 0, 0, 0, 0,0,0)
-#define CTX_miter CTX_STRH('m','i','t','e','r',0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_miter_limit CTX_STRH('m','i','t','e','r','_','l','i','m','i','t',0,0,0)
-#define CTX_miterLimit CTX_STRH('m','i','t','e','r','L','i','m','i','t',0,0,0,0)
-#define CTX_move_to CTX_STRH('m','o','v','e','_','t','o',0,0,0,0,0,0,0)
-#define CTX_moveTo CTX_STRH('m','o','v','e','T','o',0,0,0,0,0,0,0,0)
-#define CTX_multiply CTX_STRH('m','u','l','t','i','p','l','y',0,0,0,0,0,0)
-#define CTX_new_page CTX_STRH('n','e','w','_','p','a','g','e',0,0,0,0,0,0)
-#define CTX_newPage CTX_STRH('n','e','w','P','a','g','e',0,0,0,0,0,0,0)
-#define CTX_new_path CTX_STRH('n','e','w','_','p','a','t','h',0,0,0,0,0,0)
-#define CTX_newPath CTX_STRH('n','e','w','P','a','t','h',0,0,0,0,0,0,0)
-#define CTX_new_state CTX_STRH('n','e','w','_','s','t','a','t','e',0,0,0,0,0)
-#define CTX_none CTX_STRH('n','o','n','e', 0 ,0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_normal CTX_STRH('n','o','r','m','a','l',0,0,0,0,0,0,0,0)
-#define CTX_quad_to CTX_STRH('q','u','a','d','_','t','o',0,0,0,0,0,0,0)
-#define CTX_quadTo CTX_STRH('q','u','a','d','T','o',0,0,0,0,0,0,0,0)
-#define CTX_radial_gradient CTX_STRH('r','a','d','i','a','l','_','g','r','a','d','i','e','n')
-#define CTX_radialGradient CTX_STRH('r','a','d','i','a','l','G','r','a','d','i','e','n','t')
-#define CTX_rectangle CTX_STRH('r','e','c','t','a','n','g','l','e',0,0,0,0,0)
-#define CTX_rect CTX_STRH('r','e','c','t',0,0,0,0,0,0,0,0,0,0)
-#define CTX_rel_arc_to CTX_STRH('r','e','l','_','a','r','c','_','t','o',0,0,0,0)
-#define CTX_relArcTo CTX_STRH('r','e','l','A','r','c','T','o',0,0,0,0,0,0)
-#define CTX_rel_curve_to CTX_STRH('r','e','l','_','c','u','r','v','e','_','t','o',0,0)
-#define CTX_relCurveTo CTX_STRH('r','e','l','C','u','r','v','e','T','o',0,0,0,0)
-#define CTX_rel_hor_line_to CTX_STRH('r','e','l','_','h','o','r','_','l','i','n','e',0,0)
-#define CTX_relHorLineTo CTX_STRH('r','e','l','H','o','r','L','i','n','e','T','o',0,0)
-#define CTX_rel_line_to CTX_STRH('r','e','l','_','l','i','n','e','_','t','o',0,0,0)
-#define CTX_relLineTo CTX_STRH('r','e','l','L','i','n','e','T','o',0,0,0,0,0)
-#define CTX_rel_move_to CTX_STRH('r','e','l','_','m','o','v','e','_','t','o',0,0,0)
-#define CTX_relMoveTo CTX_STRH('r','e','l','M','o','v','e','T','o',0,0,0,0,0)
-#define CTX_rel_quad_to CTX_STRH('r','e','l','_','q','u','a','d','_','t','o',0,0,0)
-#define CTX_relQuadTo CTX_STRH('r','e','l','Q','u','a','d','T','o',0,0,0,0,0)
-#define CTX_rel_smoothq_to CTX_STRH('r','e','l','_','s','m','o','o','t','h','q','_','t','o')
-#define CTX_relSmoothqTo CTX_STRH('r','e','l','S','m','o','o','t','h','q','T','o',0,0)
-#define CTX_rel_smooth_to CTX_STRH('r','e','l','_','s','m','o','o','t','h','_','t','o',0)
-#define CTX_relSmoothTo CTX_STRH('r','e','l','S','m','o','o','t','h','T','o',0,0,0)
-#define CTX_rel_ver_line_to CTX_STRH('r','e','l','_','v','e','r','_','l','i','n','e',0,0)
-#define CTX_relVerLineTo CTX_STRH('r','e','l','V','e','r','L','i','n','e','T','o',0,0)
-#define CTX_restore CTX_STRH('r','e','s','t','o','r','e',0,0,0,0,0,0,0)
-#define CTX_reset CTX_STRH('r','e','s','e','t',0,0,0,0,0,0,0,0,0)
-#define CTX_rgba CTX_STRH('r','g','b','a',0,0,0,0,0,0,0,0,0,0)
-#define CTX_rgb CTX_STRH('r','g','b',0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_right CTX_STRH('r','i','g','h','t',0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_rotate CTX_STRH('r','o','t','a','t','e',0,0,0,0,0,0,0,0)
-#define CTX_round CTX_STRH('r','o','u','n','d',0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_round_rectangle CTX_STRH('r','o','u','n','d','_','r','e','c','t','a','n','g','l')
-#define CTX_roundRectangle CTX_STRH('r','o','u','n','d','R','e','c','t','a','n','g','l','e')
-#define CTX_save CTX_STRH('s','a','v','e',0,0,0,0,0,0,0,0,0,0)
-#define CTX_save CTX_STRH('s','a','v','e',0,0,0,0,0,0,0,0,0,0)
-#define CTX_scale CTX_STRH('s','c','a','l','e',0,0,0,0,0,0,0,0,0)
-#define CTX_screen CTX_STRH('s','c','r','e','e','n',0,0,0,0,0,0,0,0)
-#define CTX_setkey CTX_STRH('s','e','t','k','e','y',0,0,0,0,0,0,0,0)
-#define CTX_shadowBlur CTX_STRH('s','h','a','d','o','w','B','l','u','r',0,0,0,0)
-#define CTX_shadowColor CTX_STRH('s','h','a','d','o','w','C','o','l','o','r',0,0,0)
-#define CTX_shadowOffsetX CTX_STRH('s','h','a','d','o','w','O','f','f','s','e','t','X',0)
-#define CTX_shadowOffsetY CTX_STRH('s','h','a','d','o','w','O','f','f','s','e','t','Y',0)
-#define CTX_smooth_quad_to CTX_STRH('s','m','o','o','t','h','_','q','u','a','d','_','t','o')
-#define CTX_smoothQuadTo CTX_STRH('s','m','o','o','t','h','Q','u','a','d','T','o',0,0)
-#define CTX_smooth_to CTX_STRH('s','m','o','o','t','h','_','t','o',0,0,0,0,0)
-#define CTX_smoothTo CTX_STRH('s','m','o','o','t','h','T','o',0,0,0,0,0,0)
-#define CTX_sourceIn CTX_STRH('s','o','u','r','c','e','I','n',0,0,0,0,0,0)
-#define CTX_source_in CTX_STRH('s','o','u','r','c','e','_','i','n',0,0,0,0,0)
-#define CTX_sourceAtop CTX_STRH('s','o','u','r','c','e','A','t','o','p',0,0,0,0)
-#define CTX_source_atop CTX_STRH('s','o','u','r','c','e','_','a','t','o','p',0,0,0)
-#define CTX_sourceOut CTX_STRH('s','o','u','r','c','e','O','u','t',0,0,0,0,0)
-#define CTX_source_out CTX_STRH('s','o','u','r','c','e','_','o','u','t',0,0,0,0)
-#define CTX_sourceOver CTX_STRH('s','o','u','r','c','e','O','v','e','r',0,0,0,0)
-#define CTX_source_over CTX_STRH('s','o','u','r','c','e','_','o','v','e','r',0,0,0)
-#define CTX_square CTX_STRH('s','q','u','a','r','e', 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_start CTX_STRH('s','t','a','r','t',0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_start_move CTX_STRH('s','t','a','r','t','_','m','o','v','e',0,0,0,0)
-#define CTX_start_group CTX_STRH('s','t','a','r','t','_','G','r','o','u','p',0,0,0)
-#define CTX_startGroup CTX_STRH('s','t','a','r','t','G','r','o','u','p',0,0,0,0)
-#define CTX_stroke CTX_STRH('s','t','r','o','k','e',0,0,0,0,0,0,0,0)
-#define CTX_text_align CTX_STRH('t','e','x','t','_','a','l','i','g','n',0, 0,0,0)
-#define CTX_textAlign CTX_STRH('t','e','x','t','A','l','i','g','n',0, 0, 0,0,0)
-#define CTX_texture CTX_STRH('t','e','x','t','u','r','e',0,0,0, 0, 0,0,0)
-#define CTX_text_baseline CTX_STRH('t','e','x','t','_','b','a','s','e','l','i','n','e',0)
-#define CTX_text_baseline CTX_STRH('t','e','x','t','_','b','a','s','e','l','i','n','e',0)
-#define CTX_textBaseline CTX_STRH('t','e','x','t','B','a','s','e','l','i','n','e',0,0)
-#define CTX_text CTX_STRH('t','e','x','t',0,0,0,0,0,0,0,0,0,0)
-#define CTX_text_direction CTX_STRH('t','e','x','t','_','d','i','r','e','c','t','i','o','n')
-#define CTX_textDirection CTX_STRH('t','e','x','t','D','i','r','e','c','t','i','o','n',0)
-#define CTX_text_indent CTX_STRH('t','e','x','t','_','i','n','d','e','n','t', 0,0,0)
-#define CTX_text_stroke CTX_STRH('t','e','x','t','_','s','t','r','o','k','e', 0,0,0)
-#define CTX_textStroke CTX_STRH('t','e','x','t','S','t','r','o','k','e', 0, 0,0,0)
-#define CTX_top CTX_STRH('t','o','p',0,0,0, 0, 0, 0, 0, 0, 0,0,0)
-#define CTX_transform CTX_STRH('t','r','a','n','s','f','o','r','m',0,0,0,0,0)
-#define CTX_translate CTX_STRH('t','r','a','n','s','l','a','t','e',0,0,0,0,0)
-#define CTX_verLineTo CTX_STRH('v','e','r','L','i','n','e','T','o',0,0,0,0,0)
-#define CTX_ver_line_to CTX_STRH('v','e','r','_','l','i','n','e','_','t','o',0,0,0)
-#define CTX_width CTX_STRH('w','i','d','t','h',0,0,0,0,0,0,0,0,0)
-#define CTX_winding CTX_STRH('w','i','n','d','i','n', 'g', 0, 0, 0, 0, 0,0,0)
-#define CTX_x CTX_STRH('x',0,0,0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_xor CTX_STRH('x','o','r',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_colorSpace CTX_STRH('c','o','l','o','r','S','p','a','c','e',0,0,0,0)
-#define CTX_userRGB CTX_STRH('u','s','e','r','R','G','B',0,0,0,0,0,0,0)
-#define CTX_userCMYK CTX_STRH('u','s','e','r','C','M','Y','K',0,0,0,0,0,0)
-#define CTX_deviceRGB CTX_STRH('d','e','v','i','c','e','r','R','G','B',0,0,0,0)
-#define CTX_deviceCMYK CTX_STRH('d','e','v','i','c','e','r','C','M','Y','K',0,0,0)
+#define TOKENHASH(a) ((uint64_t)a)
+
+#define CTX_add_stop TOKENHASH(1274978316678)
+#define CTX_addStop TOKENHASH(40799943078278)
+#define CTX_alphabetic TOKENHASH(2629359926678406)
+#define CTX_arc TOKENHASH(11526)
+#define CTX_arc_to TOKENHASH(1187065094)
+#define CTX_arcTo TOKENHASH(38558051590)
+#define CTX_begin_path TOKENHASH(3004110681622984)
+#define CTX_beginPath TOKENHASH(8437143659599196)
+#define CTX_bevel TOKENHASH(29868488)
+#define CTX_bottom TOKENHASH(1043772488)
+#define CTX_cap TOKENHASH(37066)
+#define CTX_center TOKENHASH(1358332362)
+#define CTX_clear TOKENHASH(42154890)
+#define CTX_color TOKENHASH(43086922)
+#define CTX_copy TOKENHASH(1807434)
+#define CTX_clip TOKENHASH(1203082)
+#define CTX_close_path TOKENHASH(3004110663420810)
+#define CTX_closePath TOKENHASH(8437144279135038)
+#define CTX_cmyka TOKENHASH(7199690)
+#define CTX_cmyk TOKENHASH(908234)
+#define CTX_cmykaS TOKENHASH(36313095114)
+#define CTX_cmykS TOKENHASH(1135467466)
+#define CTX_color TOKENHASH(43086922)
+#define CTX_blending TOKENHASH(653586873224)
+#define CTX_blend TOKENHASH(13646728)
+#define CTX_blending_mode TOKENHASH(8147360531130856)
+#define CTX_blendingMode TOKENHASH(7483585768187540)
+#define CTX_blend_mode TOKENHASH(2758775686577032)
+#define CTX_blendMode TOKENHASH(7773213171090182)
+#define CTX_composite TOKENHASH(16930059746378)
+#define CTX_compositing_mode TOKENHASH(2417816728103524)
+#define CTX_compositingMode TOKENHASH(2807194446992106)
+#define CTX_curve_to TOKENHASH(1215559149002)
+#define CTX_curveTo TOKENHASH(39483449320906)
+#define CTX_darken TOKENHASH(1089315020)
+#define CTX_defineGlyph TOKENHASH(2497926167421194)
+#define CTX_defineTexture TOKENHASH(2623744577477404)
+#define CTX_kerningPair TOKENHASH(6964644556489058)
+#define CTX_destinationIn TOKENHASH(8153299143600102)
+#define CTX_destination_in TOKENHASH(3824201982576824)
+#define CTX_destinationAtop TOKENHASH(8185118415574560)
+#define CTX_destination_atop TOKENHASH(7742210324901698)
+#define CTX_destinationOver TOKENHASH(3261713333438500)
+#define CTX_destination_over TOKENHASH(7742210324728474)
+#define CTX_destinationOut TOKENHASH(7742210322269456)
+#define CTX_destination_out TOKENHASH(8153299143489102)
+#define CTX_difference TOKENHASH(2756492040618700)
+#define CTX_done TOKENHASH(492620)
+#define CTX_drgba TOKENHASH(6573324)
+#define CTX_drgb TOKENHASH(281868)
+#define CTX_drgbaS TOKENHASH(36312468748)
+#define CTX_drgbS TOKENHASH(1134841100)
+#define CTX_end TOKENHASH(13326)
+#define CTX_endfun TOKENHASH(1122513934)
+#define CTX_end_group TOKENHASH(41200834917390)
+#define CTX_endGroup TOKENHASH(3570227948106766)
+#define CTX_even_odd TOKENHASH(426345774606)
+#define CTX_evenOdd TOKENHASH(13671748091406)
+#define CTX_exit TOKENHASH(1465998)
+#define CTX_fill TOKENHASH(946896)
+#define CTX_fill_rule TOKENHASH(16405972808400)
+#define CTX_fillRule TOKENHASH(2776813389378256)
+#define CTX_flush TOKENHASH(22395792)
+#define CTX_font TOKENHASH(1475664)
+#define CTX_font_size TOKENHASH(17342343316560)
+#define CTX_setFontSize TOKENHASH(8657699789799734)
+#define CTX_fontSize TOKENHASH(2806775148872784)
+#define CTX_function TOKENHASH(1136803546576)
+#define CTX_getkey TOKENHASH(1827516882)
+#define CTX_global_alpha TOKENHASH(6945103263242432)
+#define CTX_globalAlpha TOKENHASH(2684560928159160)
+#define CTX_glyph TOKENHASH(22207378)
+#define CTX_gradient_add_stop TOKENHASH(7829524561074416)
+#define CTX_gradientAddStop TOKENHASH(8126442749593072)
+#define CTX_graya TOKENHASH(8068370)
+#define CTX_gray TOKENHASH(1776914)
+#define CTX_grayaS TOKENHASH(36313963794)
+#define CTX_grayS TOKENHASH(1136336146)
+#define CTX_hanging TOKENHASH(20424786132)
+#define CTX_height TOKENHASH(1497979348)
+#define CTX_hor_line_to TOKENHASH(8345271542735158)
+#define CTX_horLineTo TOKENHASH(3629696407754856)
+#define CTX_hue TOKENHASH(15828)
+#define CTX_identity TOKENHASH(1903455910294)
+#define CTX_ideographic TOKENHASH(4370819675496700)
+#define CTX_imageSmoothing TOKENHASH(4268778175825416)
+#define CTX_join TOKENHASH(1072216)
+#define CTX_laba TOKENHASH(205020)
+#define CTX_lab TOKENHASH(8412)
+#define CTX_lcha TOKENHASH(217436)
+#define CTX_lch TOKENHASH(20828)
+#define CTX_labaS TOKENHASH(1134764252)
+#define CTX_labS TOKENHASH(35463388)
+#define CTX_lchaS TOKENHASH(1134776668)
+#define CTX_lchS TOKENHASH(35475804)
+#define CTX_left TOKENHASH(1458652)
+#define CTX_lighter TOKENHASH(43466246876)
+#define CTX_lighten TOKENHASH(34876312284)
+#define CTX_linear_gradient TOKENHASH(7801595375834212)
+#define CTX_linearGradient TOKENHASH(4439260636789186)
+#define CTX_line_cap TOKENHASH(1243731165916)
+#define CTX_lineCap TOKENHASH(3436510399409980)
+#define CTX_setLineCap TOKENHASH(7897176123029482)
+#define CTX_line_height TOKENHASH(3300223516389168)
+#define CTX_line_join TOKENHASH(35977601450716)
+#define CTX_lineJoin TOKENHASH(3403122163024604)
+#define CTX_setLineJoin TOKENHASH(2768281536656332)
+#define CTX_line_spacing TOKENHASH(2519451230887150)
+#define CTX_line_to TOKENHASH(37986206428)
+#define CTX_lineTo TOKENHASH(1233857774300)
+#define CTX_lineDash TOKENHASH(3001937455186652)
+#define CTX_lineDashOffset TOKENHASH(3704120356324362)
+#define CTX_line_width TOKENHASH(3004303386575580)
+#define CTX_lineWidth TOKENHASH(8241159254028040)
+#define CTX_setLineWidth TOKENHASH(8037913618228476)
+#define CTX_view_box TOKENHASH(1823485803248)
+#define CTX_viewBox TOKENHASH(3915860941641152)
+#define CTX_middle TOKENHASH(499528414)
+#define CTX_miter TOKENHASH(42447582)
+#define CTX_miter_limit TOKENHASH(4281255327472850)
+#define CTX_miterLimit TOKENHASH(7937453649653124)
+#define CTX_move_to TOKENHASH(37986223198)
+#define CTX_moveTo TOKENHASH(1233857791070)
+#define CTX_multiply TOKENHASH(1886723143134)
+#define CTX_new_page TOKENHASH(500602882528)
+#define CTX_newPage TOKENHASH(16020123011552)
+#define CTX_new_path TOKENHASH(734678600160)
+#define CTX_newPath TOKENHASH(23510545975776)
+#define CTX_new_state TOKENHASH(16912954280416)
+#define CTX_none TOKENHASH(492640)
+#define CTX_normal TOKENHASH(946840672)
+#define CTX_quad_to TOKENHASH(37986115046)
+#define CTX_quadTo TOKENHASH(1233857682918)
+#define CTX_radial_gradient TOKENHASH(8267515704460560)
+#define CTX_radialGradient TOKENHASH(4399889250822134)
+#define CTX_rectangle TOKENHASH(16375644301800)
+#define CTX_rect TOKENHASH(1452520)
+#define CTX_rel_arc_to TOKENHASH(3496527781786088)
+#define CTX_relArcTo TOKENHASH(3209152175601038)
+#define CTX_rel_curve_to TOKENHASH(4439651822639910)
+#define CTX_relCurveTo TOKENHASH(7294415873689320)
+#define CTX_rel_hor_line_to TOKENHASH(7051067105640810)
+#define CTX_relHorLineTo TOKENHASH(8737419863647946)
+#define CTX_relVerLineTo TOKENHASH(8737441317512906)
+#define CTX_rel_line_to TOKENHASH(8345271542378314)
+#define CTX_relLineTo TOKENHASH(3629696197927444)
+#define CTX_rel_move_to TOKENHASH(8344984486309706)
+#define CTX_relMoveTo TOKENHASH(3571677202293268)
+#define CTX_rel_quad_to TOKENHASH(8343627754794826)
+#define CTX_relQuadTo TOKENHASH(7894357900599828)
+#define CTX_rel_smoothq_to TOKENHASH(7340038162167138)
+#define CTX_relSmoothqTo TOKENHASH(3188040406230844)
+#define CTX_rel_smooth_to TOKENHASH(8144941131301668)
+#define CTX_relSmoothTo TOKENHASH(8947422784198618)
+#define CTX_rel_ver_line_to TOKENHASH(8148126344839530)
+#define CTX_restore TOKENHASH(16411699688)
+#define CTX_reset TOKENHASH(46639592)
+#define CTX_rgba TOKENHASH(205416)
+#define CTX_rgb TOKENHASH(8808)
+#define CTX_rgbaS TOKENHASH(1134764648)
+#define CTX_rgbS TOKENHASH(35463784)
+#define CTX_right TOKENHASH(46811880)
+#define CTX_rotate TOKENHASH(516142184)
+#define CTX_round TOKENHASH(13679720)
+#define CTX_round_rectangle TOKENHASH(4332080966833870)
+#define CTX_roundRectangle TOKENHASH(8317255488676642)
+#define CTX_save TOKENHASH(508138)
+#define CTX_scale TOKENHASH(15604074)
+#define CTX_screen TOKENHASH(1088921962)
+#define CTX_setkey TOKENHASH(1827516906)
+#define CTX_shadowBlur TOKENHASH(2924056626980284)
+#define CTX_shadowColor TOKENHASH(3509599043947446)
+#define CTX_shadowOffsetX TOKENHASH(8499312693589794)
+#define CTX_shadowOffsetY TOKENHASH(8499312693589796)
+#define CTX_smooth_quad_to TOKENHASH(6832232668547050)
+#define CTX_smoothQuadTo TOKENHASH(8278352345012646)
+#define CTX_smooth_to TOKENHASH(38898089692138)
+#define CTX_smoothTo TOKENHASH(3515270388878314)
+#define CTX_sourceIn TOKENHASH(3444145493687402)
+#define CTX_source_in TOKENHASH(35942915423338)
+#define CTX_sourceAtop TOKENHASH(2920281959978332)
+#define CTX_source_atop TOKENHASH(3007410591464110)
+#define CTX_sourceOut TOKENHASH(7371294932695718)
+#define CTX_source_out TOKENHASH(3851660580666474)
+#define CTX_sourceOver TOKENHASH(7584784067385004)
+#define CTX_source_over TOKENHASH(8690648756484770)
+#define CTX_square TOKENHASH(511950058)
+#define CTX_start TOKENHASH(47455658)
+#define CTX_start_move TOKENHASH(2798358138985898)
+#define CTX_start_group TOKENHASH(7836274863228782)
+#define CTX_startGroup TOKENHASH(3812645199786240)
+#define CTX_stroke TOKENHASH(498181546)
+#define CTX_text_align TOKENHASH(3398277113762284)
+#define CTX_textAlign TOKENHASH(3063795447820748)
+#define CTX_texture TOKENHASH(16424292844)
+#define CTX_text_baseline TOKENHASH(2589194334827348)
+#define CTX_text_baseline TOKENHASH(2589194334827348)
+#define CTX_textBaseline TOKENHASH(8381669925369340)
+#define CTX_fillRect TOKENHASH(3811453831115472)
+#define CTX_text TOKENHASH(1495532)
+#define CTX_text_direction TOKENHASH(3614589880641524)
+#define CTX_textDirection TOKENHASH(6790122975782654)
+#define CTX_text_indent TOKENHASH(3633795456290560)
+#define CTX_text_stroke TOKENHASH(8259523149811490)
+#define CTX_strokeText TOKENHASH(8131451867629426)
+#define CTX_strokeRect TOKENHASH(8165399289138988)
+#define CTX_top TOKENHASH(37996)
+#define CTX_transform TOKENHASH(34396827557164)
+#define CTX_translate TOKENHASH(16912418348332)
+#define CTX_verLineTo TOKENHASH(3629696413166220)
+#define CTX_ver_line_to TOKENHASH(8345271542726354)
+#define CTX_width TOKENHASH(22426354)
+#define CTX_winding TOKENHASH(20424590066)
+#define CTX_x TOKENHASH(52)
+#define CTX_xor TOKENHASH(42100)
+#define CTX_y TOKENHASH(54)
+#define CTX_colorSpace TOKENHASH(3674150843793134)
+#define CTX_userRGB TOKENHASH(59177128181102)
+#define CTX_userCMYK TOKENHASH(3354734206905240)
+#define CTX_deviceRGB TOKENHASH(7818727413767480)
+#define CTX_deviceCMYK TOKENHASH(8943291245184210)
+#define CTX_silver TOKENHASH(1358459626)
+#define CTX_fuchsia TOKENHASH(7225355728)
+#define CTX_gray TOKENHASH(1776914)
+#define CTX_yellow TOKENHASH(1714319862)
+#define CTX_white TOKENHASH(16145074)
+#define CTX_maroon TOKENHASH(1110548702)
+#define CTX_magenta TOKENHASH(7952877790)
+#define CTX_blue TOKENHASH(506760)
+#define CTX_green TOKENHASH(34028818)
+#define CTX_red TOKENHASH(12776)
+#define CTX_purple TOKENHASH(500344292)
+#define CTX_olive TOKENHASH(16276386)
+#define CTX_teal TOKENHASH(924140)
+#define CTX_black TOKENHASH(27597704)
+#define CTX_cyan TOKENHASH(1056458)
+#define CTX_navy TOKENHASH(1818848)
+#define CTX_lime TOKENHASH(490204)
+#define CTX_aqua TOKENHASH(244934)
+#define CTX_transparent TOKENHASH(3654078210101184)
+#define CTX_currentColor TOKENHASH(7501877057638746)
#endif
#ifndef __CTX_LIBC_H
@@ -4744,9 +4841,6 @@ typedef struct _CtxSource CtxSource;
#define CTX_VALID_GRAYA_U8 (1<<6)
#define CTX_VALID_LABA ((1<<7) | CTX_VALID_GRAYA)
-//_ctx_target_space (ctx, icc);
-//_ctx_space (ctx);
-
struct _CtxColor
{
uint8_t magic; // for colors used in keydb, set to a non valid start of
@@ -4801,7 +4895,7 @@ struct _CtxGradientStop
enum _CtxSourceType
{
CTX_SOURCE_COLOR = 0,
- CTX_SOURCE_IMAGE,
+ CTX_SOURCE_TEXTURE,
CTX_SOURCE_LINEAR_GRADIENT,
CTX_SOURCE_RADIAL_GRADIENT,
};
@@ -4817,11 +4911,25 @@ struct _CtxBuffer
int width;
int height;
int stride;
- int revision; // XXX NYI, number to update when contents change
- //
+ char *eid; // might be NULL, when not - should be unique for pixel contents
+ int frame; // last frame used in, everything > 3 can be removed,
+ // as clients wont rely on it.
CtxPixelFormatInfo *format;
void (*free_func) (void *pixels, void *user_data);
void *user_data;
+
+#if CTX_ENABLE_CM
+#if CTX_BABL
+ const Babl *space;
+#else
+ void *space;
+#endif
+#endif
+#if 1
+ CtxBuffer *color_managed; /* only valid for one render target, cache
+ for a specific space
+ */
+#endif
};
//void _ctx_user_to_device (CtxState *state, float *x, float *y);
@@ -4848,7 +4956,7 @@ struct _CtxSource
float x0;
float y0;
CtxBuffer *buffer;
- } image;
+ } texture;
struct
{
float x0;
@@ -4881,12 +4989,13 @@ struct _CtxGState
int stringpool_pos;
CtxMatrix transform;
- //CtxSource source_stroke;
- CtxSource source;
+ CtxSource source_stroke;
+ CtxSource source_fill;
float global_alpha_f;
uint8_t global_alpha_u8;
float line_width;
+ float line_dash_offset;
float miter_limit;
float font_size;
#if CTX_ENABLE_SHADOW_BLUR
@@ -4904,16 +5013,21 @@ struct _CtxGState
#if CTX_ENABLE_CM
#if CTX_BABL
const Babl *device_space;
+ const Babl *texture_space;
const Babl *rgb_space;
const Babl *cmyk_space;
const Babl *fish_rgbaf_user_to_device;
+ const Babl *fish_rgbaf_texture_to_device;
const Babl *fish_rgbaf_device_to_user;
+
#else
void *device_space;
+ void *texture_space;
void *rgb_space;
void *cmyk_space;
void *fish_rgbaf_user_to_device; // dummy padding
+ void *fish_rgbaf_texture_to_device; // dummy padding
void *fish_rgbaf_device_to_user; // dummy padding
#endif
#endif
@@ -4923,14 +5037,15 @@ struct _CtxGState
float dashes[CTX_PARSER_MAX_ARGS];
int n_dashes;
- CtxColorModel color_model;
+ CtxColorModel color_model;
/* bitfield-pack small state-parts */
- CtxLineCap line_cap:2;
- CtxLineJoin line_join:2;
- CtxFillRule fill_rule:1;
- unsigned int font:6;
- unsigned int bold:1;
- unsigned int italic:1;
+ CtxLineCap line_cap:2;
+ CtxLineJoin line_join:2;
+ CtxFillRule fill_rule:1;
+ unsigned int image_smoothing:1;
+ unsigned int font:6;
+ unsigned int bold:1;
+ unsigned int italic:1;
};
typedef enum
@@ -4958,8 +5073,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
@@ -4970,7 +5083,7 @@ struct _CtxDrawlist
typedef struct _CtxKeyDbEntry CtxKeyDbEntry;
struct _CtxKeyDbEntry
{
- uint32_t key;
+ uint64_t key;
float value;
//union { float f[1]; uint8_t u8[4]; }value;
};
@@ -5150,16 +5263,26 @@ struct _CtxEvents
#endif
-struct
-_Ctx
+typedef struct _CtxEidInfo
+{
+ char *eid;
+ int frame;
+ int width;
+ int height;
+} CtxEidInfo;
+
+struct _Ctx
{
CtxImplementation *renderer;
CtxDrawlist drawlist;
int transformation;
CtxBuffer texture[CTX_MAX_TEXTURES];
+ Ctx *texture_cache;
+ CtxList *eid_db;
int rev;
void *backend;
CtxState state; /**/
+ int frame; /* used for texture lifetime */
#if CTX_EVENTS
CtxCursor cursor;
int quit;
@@ -5184,12 +5307,17 @@ void ctx_buffer_free (CtxBuffer *buffer);
void
ctx_state_gradient_clear_stops (CtxState *state);
-
void ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data);
void ctx_interpret_transforms (CtxState *state, CtxEntry *entry, void *data);
void ctx_interpret_pos (CtxState *state, CtxEntry *entry, void *data);
void ctx_interpret_pos_transform (CtxState *state, CtxEntry *entry, void *data);
+struct _CtxInternalFsEntry
+{
+ char *path;
+ int length;
+ char *data;
+};
struct _CtxPixelFormatInfo
{
@@ -5237,6 +5365,8 @@ ctx_unichar_to_utf8 (uint32_t ch,
uint32_t
ctx_utf8_to_unichar (const char *input);
+
+
typedef struct _CtxHasher CtxHasher;
typedef struct CtxEdge
@@ -5306,9 +5436,6 @@ struct _CtxRasterizer
int col_min;
int col_max;
-#if CTX_BRAILLE_TEXT
- CtxList *glyphs;
-#endif
CtxDrawlist edge_list;
@@ -5318,11 +5445,13 @@ struct _CtxRasterizer
void *buf;
+
#if CTX_COMPOSITING_GROUPS
void *saved_buf; // when group redirected
CtxBuffer *group[CTX_GROUP_MAX];
#endif
+
float x; // < redundant? use state instead?
float y;
@@ -5333,9 +5462,6 @@ struct _CtxRasterizer
int has_prev:2;
int preserve:1;
int uses_transforms:1;
-#if CTX_BRAILLE_TEXT
- int term_glyphs:1; // store appropriate glyphs for redisplay
-#endif
int16_t blit_x;
int16_t blit_y;
@@ -5363,10 +5489,32 @@ struct _CtxRasterizer
CtxBuffer *clip_buffer;
#endif
- uint8_t *clip_mask;
+ int clip_rectangle;
+
#if CTX_SHAPE_CACHE
CtxShapeCache shape_cache;
#endif
+#if CTX_BRAILLE_TEXT
+ int term_glyphs:1; // store appropriate glyphs for redisplay
+ CtxList *glyphs;
+#endif
+};
+
+struct _CtxSHA1 {
+ uint64_t length;
+ uint32_t state[5], curlen;
+ unsigned char buf[64];
+};
+
+
+struct _CtxHasher
+{
+ CtxRasterizer rasterizer;
+ int cols;
+ int rows;
+ uint8_t *hashes;
+ CtxSHA1 sha1_fill;
+ CtxSHA1 sha1_stroke;
};
#if CTX_RASTERIZER
@@ -5426,40 +5574,20 @@ struct _CtxCtx
int was_down;
};
-// XXX common members of sdl and fbdev, it is more!
-typedef struct _CtxThreaded CtxThreaded;
-struct _CtxThreaded
-{
- void (*render) (void *fb, CtxCommand *command);
- void (*reset) (void *fb);
- void (*flush) (void *fb);
- char *(*get_clipboard) (void *ctxctx);
- void (*set_clipboard) (void *ctxctx, const char *text);
- void (*free) (void *fb);
- Ctx *ctx;
- Ctx *ctx_copy;
- int width;
- int height;
- int cols;
- int rows;
- int was_down;
- Ctx *host[CTX_MAX_THREADS];
- CtxAntialias antialias;
-};
-
extern int _ctx_max_threads;
extern int _ctx_enable_hash_cache;
void
-ctx_set (Ctx *ctx, uint32_t key_hash, const char *string, int len);
+ctx_set (Ctx *ctx, uint64_t key_hash, const char *string, int len);
const char *
ctx_get (Ctx *ctx, const char *key);
-int ctx_renderer_is_braille (Ctx *ctx);
+int ctx_renderer_is_term (Ctx *ctx);
Ctx *ctx_new_ctx (int width, int height);
Ctx *ctx_new_fb (int width, int height, int drm);
Ctx *ctx_new_sdl (int width, int height);
-Ctx *ctx_new_braille (int width, int height);
+Ctx *ctx_new_term (int width, int height);
+Ctx *ctx_new_termimg (int width, int height);
int ctx_resolve_font (const char *name);
extern float ctx_u8_float[256];
@@ -5514,11 +5642,11 @@ static void ctx_color_set_graya (CtxState *state, CtxColor *color, float gray, f
int ctx_color_model_get_components (CtxColorModel model);
-void ctx_state_set (CtxState *state, uint32_t key, float value);
+void ctx_state_set (CtxState *state, uint64_t key, float value);
static void
ctx_matrix_set (CtxMatrix *matrix, float a, float b, float c, float d, float e, float f);
static void ctx_font_setup ();
-float ctx_state_get (CtxState *state, uint32_t hash);
+float ctx_state_get (CtxState *state, uint64_t hash);
#if CTX_RASTERIZER
@@ -5645,827 +5773,1052 @@ static inline void *ctx_calloc (size_t size, size_t count);
void ctx_screenshot (Ctx *ctx, const char *output_path);
-typedef struct _CtxSHA1 CtxSHA1;
CtxSHA1 *ctx_sha1_new (void);
void ctx_sha1_free (CtxSHA1 *sha1);
int ctx_sha1_process(CtxSHA1 *sha1, const unsigned char * msg, unsigned long len);
int ctx_sha1_done(CtxSHA1 * sha1, unsigned char *out);
+void _ctx_texture_lock (void);
+void _ctx_texture_unlock (void);
+uint8_t *ctx_define_texture_pixel_data (CtxEntry *entry);
+void ctx_buffer_pixels_free (void *pixels, void *userdata);
-#endif
-
+/*ctx_texture_init:
+ * return value: eid, as passed in or if NULL generated by hashing pixels and width/height
+ * XXX this is low-level and not to be used directly use define_texture instead. XXX
+ */
+const char *ctx_texture_init (
+ Ctx *ctx,
+ const char *eid,
+ int width,
+ int height,
+ int stride,
+ CtxPixelFormat format,
+ void *space,
+ uint8_t *pixels,
+ void (*freefunc) (void *pixels, void *user_data),
+ void *user_data);
-#if CTX_IMPLEMENTATION
-#ifndef CTX_DRAWLIST_H
-#define CTX_DRAWLIST_H
+#if CTX_TILED
+#include <threads.h>
+#endif
+typedef struct _CtxTiled CtxTiled;
-static int
-ctx_conts_for_entry (CtxEntry *entry);
-static void
-ctx_iterator_init (CtxIterator *iterator,
- CtxDrawlist *drawlist,
- int start_pos,
- int flags);
-
-CtxCommand *
-ctx_iterator_next (CtxIterator *iterator);
-int ctx_iterator_pos (CtxIterator *iterator);
-
-static void ctx_drawlist_compact (CtxDrawlist *drawlist);
-static void
-ctx_drawlist_resize (CtxDrawlist *drawlist, int desired_size);
-static int
-ctx_drawlist_add_single (CtxDrawlist *drawlist, CtxEntry *entry);
-int
-ctx_add_single (Ctx *ctx, void *entry);
-int ctx_drawlist_add_entry (CtxDrawlist *drawlist, CtxEntry *entry);
-int
-ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry);
-int ctx_append_drawlist (Ctx *ctx, void *data, int length);
-int ctx_set_drawlist (Ctx *ctx, void *data, int length);
-int ctx_get_drawlist_count (Ctx *ctx);
-const CtxEntry *ctx_get_drawlist (Ctx *ctx);
-int
-ctx_add_data (Ctx *ctx, void *data, int length);
+struct _CtxTiled
+{
+ void (*render) (void *term, CtxCommand *command);
+ void (*reset) (void *term);
+ void (*flush) (void *term);
+ char *(*get_clipboard) (void *ctxctx);
+ void (*set_clipboard) (void *ctxctx, const char *text);
+ void (*free) (void *term);
+ Ctx *ctx;
+ int width;
+ int height;
+ int cols;
+ int rows;
+ int was_down;
+ uint8_t *pixels;
+ Ctx *ctx_copy;
+ Ctx *host[CTX_MAX_THREADS];
+ CtxAntialias antialias;
+ int quit;
+#if CTX_TILED
+ _Atomic int thread_quit;
+#endif
+ int shown_frame;
+ int render_frame;
+ int rendered_frame[CTX_MAX_THREADS];
+ int frame;
+ int min_col; // hasher cols and rows
+ int min_row;
+ int max_col;
+ int max_row;
+ uint8_t hashes[CTX_HASH_ROWS * CTX_HASH_COLS * 20];
+ int8_t tile_affinity[CTX_HASH_ROWS * CTX_HASH_COLS]; // which render thread no is
+ // responsible for a tile
+ //
-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);
+ int pointer_down[3];
-static CtxEntry
-ctx_void (CtxCode code);
-static CtxEntry
-ctx_f (CtxCode code, float x, float y);
-static CtxEntry
-ctx_u32 (CtxCode code, uint32_t x, uint32_t y);
-#if 0
-static CtxEntry
-ctx_s32 (CtxCode code, int32_t x, int32_t y);
+ CtxCursor shown_cursor;
+#if CTX_TILED
+ cnd_t cond;
+ mtx_t mtx;
#endif
+};
-CtxEntry
-ctx_s16 (CtxCode code, int x0, int y0, int x1, int y1);
-static CtxEntry
-ctx_u8 (CtxCode code,
- uint8_t a, uint8_t b, uint8_t c, uint8_t d,
- uint8_t e, uint8_t f, uint8_t g, uint8_t h);
+void
+_ctx_texture_prepare_color_management (CtxRasterizer *rasterizer,
+ CtxBuffer *buffer);
-#define CTX_PROCESS_VOID(cmd) do {\
- CtxEntry command = ctx_void (cmd); \
- ctx_process (ctx, &command);}while(0) \
+#endif
-#define CTX_PROCESS_F(cmd, x, y) do {\
- CtxEntry command = ctx_f(cmd, x, y);\
- ctx_process (ctx, &command);}while(0)
-#define CTX_PROCESS_F1(cmd, x) do {\
- CtxEntry command = ctx_f(cmd, x, 0);\
- ctx_process (ctx, &command);}while(0)
+#if CTX_IMPLEMENTATION
-#define CTX_PROCESS_U32(cmd, x, y) do {\
- CtxEntry command = ctx_u32(cmd, x, y);\
- ctx_process (ctx, &command);}while(0)
+#define SHA1_IMPLEMENTATION
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis gmail com, http://libtom.org
+ *
+ * The plain ANSIC sha1 functionality has been extracted from libtomcrypt,
+ * and is included directly in the sources. /Øyvind K. - since libtomcrypt
+ * is public domain the adaptations done here to make the sha1 self contained
+ * also is public domain.
+ */
+#ifndef __SHA1_H
+#define __SHA1_H
+#include <inttypes.h>
-#define CTX_PROCESS_U8(cmd, x) do {\
- CtxEntry command = ctx_u8(cmd, x,0,0,0,0,0,0,0);\
- ctx_process (ctx, &command);}while(0)
+int ctx_sha1_init(CtxSHA1 * sha1);
+CtxSHA1 *ctx_sha1_new (void)
+{
+ CtxSHA1 *state = (CtxSHA1*)calloc (sizeof (CtxSHA1), 1);
+ ctx_sha1_init (state);
+ return state;
+}
+void ctx_sha1_free (CtxSHA1 *sha1)
+{
+ free (sha1);
+}
-#if CTX_BITPACK_PACKER
-static int
-ctx_last_history (CtxDrawlist *drawlist);
+#if 0
+ CtxSHA1 sha1;
+ ctx_sha1_init (&sha1);
+ ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxIntRectangle));
+ ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
#endif
-#if CTX_BITPACK_PACKER
-static void
-ctx_drawlist_remove_tiny_curves (CtxDrawlist *drawlist, int start_pos);
-
-static void
-ctx_drawlist_bitpack (CtxDrawlist *drawlist, int start_pos);
+#ifdef FF0
+#undef FF0
#endif
-
-static void
-ctx_drawlist_compact (CtxDrawlist *drawlist);
-static void
-ctx_process_cmd_str (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1);
-static void
-ctx_process_cmd_str_with_len (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1, int
len);
-
+#ifdef FF1
+#undef FF1
#endif
-#ifndef __CTX_UTIL_H
-#define __CTX_UTIL_H
+#ifdef SHA1_IMPLEMENTATION
+#include <stdlib.h>
+#include <string.h>
-inline static float ctx_fast_hypotf (float x, float y)
-{
- if (x < 0) { x = -x; }
- if (y < 0) { y = -y; }
- if (x < y)
- { return 0.96f * y + 0.4f * x; }
- else
- { return 0.96f * x + 0.4f * y; }
-}
+#define STORE64H(x, y)
\
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
-static int ctx_str_is_number (const char *str)
-{
- int got_digit = 0;
- for (int i = 0; str[i]; i++)
- {
- if (str[i] >= '0' && str[i] <= '9')
- {
- got_digit ++;
- }
- else if (str[i] == '.')
- {
- }
- else
- return 0;
- }
- if (got_digit)
- return 1;
- return 0;
-}
+#define STORE32H(x, y)
\
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
-#if CTX_FONTS_FROM_FILE
-int
-_ctx_file_get_contents (const char *path,
- unsigned char **contents,
- long *length)
-{
- FILE *file;
- long size;
- long remaining;
- char *buffer;
- file = fopen (path, "rb");
- if (!file)
- { return -1; }
- fseek (file, 0, SEEK_END);
- size = remaining = ftell (file);
- if (length)
- { *length =size; }
- rewind (file);
- buffer = (char*)malloc (size + 8);
- if (!buffer)
- {
- fclose (file);
- return -1;
- }
- remaining -= fread (buffer, 1, remaining, file);
- if (remaining)
- {
- fclose (file);
- free (buffer);
- return -1;
- }
- fclose (file);
- *contents = (unsigned char*) buffer;
- buffer[size] = 0;
- return 0;
-}
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
-void
-_ctx_file_set_contents (const char *path,
- const unsigned char *contents,
- long length)
-{
- FILE *file;
- file = fopen (path, "wb");
- if (!file)
- { return; }
- if (length < 0) length = strlen ((const char*)contents);
- fwrite (contents, 1, length, file);
- fclose (file);
-}
+/* rotates the hard way */
+#define ROL(x, y) ((((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned
long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROLc(x, y) ROL(x,y)
+#define CRYPT_OK 0
+#define CRYPT_ERROR 1
+#define CRYPT_NOP 2
+#ifndef MAX
+ #define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#endif
+#ifndef MIN
+ #define MIN(x, y) ( ((x)<(y))?(x):(y) )
#endif
+/* a simple macro for making hash "process" functions */
+#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \
+int func_name (CtxSHA1 *sha1, const unsigned char *in, unsigned long inlen) \
+{ \
+ unsigned long n; \
+ int err; \
+ assert (sha1 != NULL); \
+ assert (in != NULL); \
+ if (sha1->curlen > sizeof(sha1->buf)) { \
+ return -1; \
+ } \
+ while (inlen > 0) { \
+ if (sha1->curlen == 0 && inlen >= block_size) { \
+ if ((err = compress_name (sha1, (unsigned char *)in)) != CRYPT_OK) { \
+ return err; \
+ } \
+ sha1->length += block_size * 8; \
+ in += block_size; \
+ inlen -= block_size; \
+ } else { \
+ n = MIN(inlen, (block_size - sha1->curlen)); \
+ memcpy(sha1->buf + sha1->curlen, in, (size_t)n); \
+ sha1->curlen += n; \
+ in += n; \
+ inlen -= n; \
+ if (sha1->curlen == block_size) { \
+ if ((err = compress_name (sha1, sha1->buf)) != CRYPT_OK) { \
+ return err; \
+ } \
+ sha1->length += 8*block_size; \
+ sha1->curlen = 0; \
+ } \
+ } \
+ } \
+ return CRYPT_OK; \
+}
-#endif
+/**********************/
+#define F0(x,y,z) (z ^ (x & (y ^ z)))
+#define F1(x,y,z) (x ^ y ^ z)
+#define F2(x,y,z) ((x & y) | (z & (x | y)))
+#define F3(x,y,z) (x ^ y ^ z)
-static int
-ctx_conts_for_entry (CtxEntry *entry)
+static int ctx_sha1_compress(CtxSHA1 *sha1, unsigned char *buf)
{
- switch (entry->code)
- {
- case CTX_DATA:
- return entry->data.u32[1];
- case CTX_LINEAR_GRADIENT:
- return 1;
- case CTX_RADIAL_GRADIENT:
- case CTX_ARC:
- case CTX_ARC_TO:
- case CTX_REL_ARC_TO:
- case CTX_CURVE_TO:
- case CTX_REL_CURVE_TO:
- case CTX_APPLY_TRANSFORM:
- case CTX_COLOR:
- case CTX_ROUND_RECTANGLE:
- case CTX_SHADOW_COLOR:
- return 2;
- case CTX_RECTANGLE:
- case CTX_VIEW_BOX:
- case CTX_REL_QUAD_TO:
- case CTX_QUAD_TO:
- case CTX_TEXTURE:
- return 1;
- default:
- return 0;
+ uint32_t a,b,c,d,e,W[80],i;
+
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32H(W[i], buf + (4*i));
}
-}
-// expanding arc_to to arc can be the job
-// of a layer in front of renderer?
-// doing:
-// rectangle
-// arc
-// ... etc reduction to beziers
-// or even do the reduction to
-// polylines directly here...
-// making the rasterizer able to
-// only do poly-lines? will that be faster?
+ /* copy state */
+ a = sha1->state[0];
+ b = sha1->state[1];
+ c = sha1->state[2];
+ d = sha1->state[3];
+ e = sha1->state[4];
-/* the iterator - should decode bitpacked data as well -
- * making the rasterizers simpler, possibly do unpacking
- * all the way to absolute coordinates.. unless mixed
- * relative/not are wanted.
- */
+ /* expand it */
+ for (i = 16; i < 80; i++) {
+ W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
+ }
+ /* compress */
+ /* round one */
+ #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
+ #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
+ #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
+ #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
+
+ for (i = 0; i < 20; ) {
+ FF0(a,b,c,d,e,i++);
+ FF0(e,a,b,c,d,i++);
+ FF0(d,e,a,b,c,i++);
+ FF0(c,d,e,a,b,i++);
+ FF0(b,c,d,e,a,i++);
+ }
-static void
-ctx_iterator_init (CtxIterator *iterator,
- CtxDrawlist *drawlist,
- int start_pos,
- int flags)
-{
- iterator->drawlist = drawlist;
- iterator->flags = flags;
- iterator->bitpack_pos = 0;
- iterator->bitpack_length = 0;
- iterator->pos = start_pos;
- iterator->end_pos = drawlist->count;
- iterator->first_run = 1; // -1 is a marker used for first run
- ctx_memset (iterator->bitpack_command, 0, sizeof (iterator->bitpack_command) );
-}
+ /* round two */
+ for (; i < 40; ) {
+ FF1(a,b,c,d,e,i++);
+ FF1(e,a,b,c,d,i++);
+ FF1(d,e,a,b,c,i++);
+ FF1(c,d,e,a,b,i++);
+ FF1(b,c,d,e,a,i++);
+ }
-int ctx_iterator_pos (CtxIterator *iterator)
-{
- return iterator->pos;
-}
+ /* round three */
+ for (; i < 60; ) {
+ FF2(a,b,c,d,e,i++);
+ FF2(e,a,b,c,d,i++);
+ FF2(d,e,a,b,c,i++);
+ FF2(c,d,e,a,b,i++);
+ FF2(b,c,d,e,a,i++);
+ }
-static CtxEntry *_ctx_iterator_next (CtxIterator *iterator)
-{
- int ret = iterator->pos;
- CtxEntry *entry = &iterator->drawlist->entries[ret];
- if (ret >= iterator->end_pos)
- { return NULL; }
- if (iterator->first_run == 0)
- { iterator->pos += (ctx_conts_for_entry (entry) + 1); }
- iterator->first_run = 0;
- if (iterator->pos >= iterator->end_pos)
- { return NULL; }
- return &iterator->drawlist->entries[iterator->pos];
-}
+ /* round four */
+ for (; i < 80; ) {
+ FF3(a,b,c,d,e,i++);
+ FF3(e,a,b,c,d,i++);
+ FF3(d,e,a,b,c,i++);
+ FF3(c,d,e,a,b,i++);
+ FF3(b,c,d,e,a,i++);
+ }
-// 6024x4008
-#if CTX_BITPACK
-static void
-ctx_iterator_expand_s8_args (CtxIterator *iterator, CtxEntry *entry)
-{
- int no = 0;
- for (int cno = 0; cno < 4; cno++)
- for (int d = 0; d < 2; d++, no++)
- iterator->bitpack_command[cno].data.f[d] =
- entry->data.s8[no] * 1.0f / CTX_SUBDIV;
- iterator->bitpack_command[0].code =
- iterator->bitpack_command[1].code =
- iterator->bitpack_command[2].code =
- iterator->bitpack_command[3].code = CTX_CONT;
- iterator->bitpack_length = 4;
- iterator->bitpack_pos = 0;
+ #undef FF0
+ #undef FF1
+ #undef FF2
+ #undef FF3
+
+ /* store */
+ sha1->state[0] = sha1->state[0] + a;
+ sha1->state[1] = sha1->state[1] + b;
+ sha1->state[2] = sha1->state[2] + c;
+ sha1->state[3] = sha1->state[3] + d;
+ sha1->state[4] = sha1->state[4] + e;
+
+ return CRYPT_OK;
}
-static void
-ctx_iterator_expand_s16_args (CtxIterator *iterator, CtxEntry *entry)
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+int ctx_sha1_init(CtxSHA1 * sha1)
{
- int no = 0;
- for (int cno = 0; cno < 2; cno++)
- for (int d = 0; d < 2; d++, no++)
- iterator->bitpack_command[cno].data.f[d] = entry->data.s16[no] * 1.0f /
- CTX_SUBDIV;
- iterator->bitpack_command[0].code =
- iterator->bitpack_command[1].code = CTX_CONT;
- iterator->bitpack_length = 2;
- iterator->bitpack_pos = 0;
+ assert(sha1 != NULL);
+ sha1->state[0] = 0x67452301UL;
+ sha1->state[1] = 0xefcdab89UL;
+ sha1->state[2] = 0x98badcfeUL;
+ sha1->state[3] = 0x10325476UL;
+ sha1->state[4] = 0xc3d2e1f0UL;
+ sha1->curlen = 0;
+ sha1->length = 0;
+ return CRYPT_OK;
}
-#endif
-CtxCommand *
-ctx_iterator_next (CtxIterator *iterator)
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+HASH_PROCESS(ctx_sha1_process, ctx_sha1_compress, sha1, 64)
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (20 bytes)
+ @return CRYPT_OK if successful
+*/
+int ctx_sha1_done(CtxSHA1 * sha1, unsigned char *out)
{
- CtxEntry *ret;
-#if CTX_BITPACK
- int expand_bitpack = iterator->flags & CTX_ITERATOR_EXPAND_BITPACK;
-again:
- if (iterator->bitpack_length)
- {
- ret = &iterator->bitpack_command[iterator->bitpack_pos];
- iterator->bitpack_pos += (ctx_conts_for_entry (ret) + 1);
- if (iterator->bitpack_pos >= iterator->bitpack_length)
- {
- iterator->bitpack_length = 0;
+ int i;
+
+ assert(sha1 != NULL);
+ assert(out != NULL);
+
+ if (sha1->curlen >= sizeof(sha1->buf)) {
+ return -1;
+ }
+
+ /* increase the length of the message */
+ sha1->length += sha1->curlen * 8;
+
+ /* append the '1' bit */
+ sha1->buf[sha1->curlen++] = (unsigned char)0x80;
+
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (sha1->curlen > 56) {
+ while (sha1->curlen < 64) {
+ sha1->buf[sha1->curlen++] = (unsigned char)0;
}
- return (CtxCommand *) ret;
+ ctx_sha1_compress(sha1, sha1->buf);
+ sha1->curlen = 0;
+ }
+
+ /* pad upto 56 bytes of zeroes */
+ while (sha1->curlen < 56) {
+ sha1->buf[sha1->curlen++] = (unsigned char)0;
+ }
+
+ /* store length */
+ STORE64H(sha1->length, sha1->buf+56);
+ ctx_sha1_compress(sha1, sha1->buf);
+
+ /* copy output */
+ for (i = 0; i < 5; i++) {
+ STORE32H(sha1->state[i], out+(4*i));
}
+ return CRYPT_OK;
+}
#endif
- ret = _ctx_iterator_next (iterator);
-#if CTX_BITPACK
- if (ret && expand_bitpack)
- switch ((CtxCode)(ret->code))
- {
- case CTX_REL_CURVE_TO_REL_LINE_TO:
- ctx_iterator_expand_s8_args (iterator, ret);
- iterator->bitpack_command[0].code = CTX_REL_CURVE_TO;
- iterator->bitpack_command[1].code =
- iterator->bitpack_command[2].code = CTX_CONT;
- iterator->bitpack_command[3].code = CTX_REL_LINE_TO;
- // 0.0 here is a common optimization - so check for it
- if (ret->data.s8[6]== 0 && ret->data.s8[7] == 0)
- { iterator->bitpack_length = 3; }
- else
- iterator->bitpack_length = 4;
- goto again;
- case CTX_REL_LINE_TO_REL_CURVE_TO:
- ctx_iterator_expand_s8_args (iterator, ret);
- iterator->bitpack_command[0].code = CTX_REL_LINE_TO;
- iterator->bitpack_command[1].code = CTX_REL_CURVE_TO;
- iterator->bitpack_length = 2;
- goto again;
- case CTX_REL_CURVE_TO_REL_MOVE_TO:
- ctx_iterator_expand_s8_args (iterator, ret);
- iterator->bitpack_command[0].code = CTX_REL_CURVE_TO;
- iterator->bitpack_command[3].code = CTX_REL_MOVE_TO;
- iterator->bitpack_length = 4;
- goto again;
- case CTX_REL_LINE_TO_X4:
- ctx_iterator_expand_s8_args (iterator, ret);
- iterator->bitpack_command[0].code =
- iterator->bitpack_command[1].code =
- iterator->bitpack_command[2].code =
- iterator->bitpack_command[3].code = CTX_REL_LINE_TO;
- iterator->bitpack_length = 4;
- goto again;
- case CTX_REL_QUAD_TO_S16:
- ctx_iterator_expand_s16_args (iterator, ret);
- iterator->bitpack_command[0].code = CTX_REL_QUAD_TO;
- iterator->bitpack_length = 1;
- goto again;
- case CTX_REL_QUAD_TO_REL_QUAD_TO:
- ctx_iterator_expand_s8_args (iterator, ret);
- iterator->bitpack_command[0].code =
- iterator->bitpack_command[2].code = CTX_REL_QUAD_TO;
- iterator->bitpack_length = 3;
- goto again;
- case CTX_REL_LINE_TO_X2:
- ctx_iterator_expand_s16_args (iterator, ret);
- iterator->bitpack_command[0].code =
- iterator->bitpack_command[1].code = CTX_REL_LINE_TO;
- iterator->bitpack_length = 2;
- goto again;
- case CTX_REL_LINE_TO_REL_MOVE_TO:
- ctx_iterator_expand_s16_args (iterator, ret);
- iterator->bitpack_command[0].code = CTX_REL_LINE_TO;
- iterator->bitpack_command[1].code = CTX_REL_MOVE_TO;
- iterator->bitpack_length = 2;
- goto again;
- case CTX_MOVE_TO_REL_LINE_TO:
- ctx_iterator_expand_s16_args (iterator, ret);
- iterator->bitpack_command[0].code = CTX_MOVE_TO;
- iterator->bitpack_command[1].code = CTX_REL_MOVE_TO;
- iterator->bitpack_length = 2;
- goto again;
- case CTX_FILL_MOVE_TO:
- iterator->bitpack_command[1] = *ret;
- iterator->bitpack_command[0].code = CTX_FILL;
- iterator->bitpack_command[1].code = CTX_MOVE_TO;
- iterator->bitpack_pos = 0;
- iterator->bitpack_length = 2;
- goto again;
- case CTX_LINEAR_GRADIENT:
- case CTX_QUAD_TO:
- case CTX_REL_QUAD_TO:
- case CTX_TEXTURE:
- case CTX_RECTANGLE:
- case CTX_VIEW_BOX:
- case CTX_ARC:
- case CTX_ARC_TO:
- case CTX_REL_ARC_TO:
- case CTX_COLOR:
- case CTX_SHADOW_COLOR:
- case CTX_RADIAL_GRADIENT:
- case CTX_CURVE_TO:
- case CTX_REL_CURVE_TO:
- case CTX_APPLY_TRANSFORM:
- case CTX_ROUND_RECTANGLE:
- case CTX_TEXT:
- case CTX_TEXT_STROKE:
- case CTX_FONT:
- case CTX_LINE_DASH:
- case CTX_FILL:
- case CTX_NOP:
- case CTX_MOVE_TO:
- case CTX_LINE_TO:
- case CTX_REL_MOVE_TO:
- case CTX_REL_LINE_TO:
- case CTX_VER_LINE_TO:
- case CTX_REL_VER_LINE_TO:
- case CTX_HOR_LINE_TO:
- case CTX_REL_HOR_LINE_TO:
- case CTX_ROTATE:
- case CTX_FLUSH:
- case CTX_TEXT_ALIGN:
- case CTX_TEXT_BASELINE:
- case CTX_TEXT_DIRECTION:
- case CTX_MITER_LIMIT:
- case CTX_GLOBAL_ALPHA:
- case CTX_COMPOSITING_MODE:
- case CTX_BLEND_MODE:
- case CTX_SHADOW_BLUR:
- case CTX_SHADOW_OFFSET_X:
- case CTX_SHADOW_OFFSET_Y:
- case CTX_RESET:
- case CTX_EXIT:
- case CTX_BEGIN_PATH:
- case CTX_CLOSE_PATH:
- case CTX_SAVE:
- case CTX_CLIP:
- case CTX_PRESERVE:
- case CTX_DEFINE_GLYPH:
- case CTX_IDENTITY:
- case CTX_FONT_SIZE:
- case CTX_START_GROUP:
- case CTX_END_GROUP:
- case CTX_RESTORE:
- case CTX_LINE_WIDTH:
- case CTX_STROKE:
- case CTX_KERNING_PAIR:
- case CTX_SCALE:
- case CTX_GLYPH:
- case CTX_SET_PIXEL:
- case CTX_FILL_RULE:
- case CTX_LINE_CAP:
- case CTX_LINE_JOIN:
- case CTX_NEW_PAGE:
- case CTX_SET_KEY:
- case CTX_TRANSLATE:
- case CTX_GRADIENT_STOP:
- case CTX_CONT: // shouldnt happen
- iterator->bitpack_length = 0;
- return (CtxCommand *) ret;
-#if 1
- default: // XXX remove - and get better warnings
- iterator->bitpack_command[0] = ret[0];
- iterator->bitpack_command[1] = ret[1];
- iterator->bitpack_command[2] = ret[2];
- iterator->bitpack_command[3] = ret[3];
- iterator->bitpack_command[4] = ret[4];
- iterator->bitpack_pos = 0;
- iterator->bitpack_length = 1;
- goto again;
+
#endif
- }
#endif
- return (CtxCommand *) ret;
+
+#if CTX_IMPLEMENTATION
+#ifndef THASH_H
+#define THASH_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#define THASH_NO_INTERNING // ctx doesn't make use of thash_decode
+
+#define THASH_ENTER_DIRECT 16
+
+#define THASH_SPACE 0
+#define THASH_DEC_OFFSET 29
+#define THASH_INC_OFFSET 30
+#define THASH_ENTER_UTF5 31
+#define THASH_START_OFFSET 'l'
+#define THASH_JUMP_OFFSET 27
+#define THASH_MAXLEN 10
+
+// todo: better whitespace handling for double version
+
+
+static inline int thash_new_offset (uint32_t unichar)
+{
+ int offset = unichar % 32;
+ return unichar - offset + 14; // this gives ~85% compression on test corpus
+ return unichar; // this gives 88% compression on test corpus
}
-static void ctx_drawlist_compact (CtxDrawlist *drawlist);
-static void
-ctx_drawlist_resize (CtxDrawlist *drawlist, int desired_size)
+static int thash_is_in_range (uint32_t offset, uint32_t unichar)
{
-#if CTX_DRAWLIST_STATIC
- if (drawlist->flags & CTX_DRAWLIST_EDGE_LIST)
+ if (unichar == 32)
+ return 1;
+ if (offset - unichar <= 13 ||
+ unichar - offset <= 14)
+ return 1;
+ return 0;
+}
+
+static int thash_is_in_jump_range_dec (uint32_t offset, uint32_t unichar)
+{
+ return thash_is_in_range (offset - THASH_JUMP_OFFSET, unichar);
+}
+
+static int thash_is_in_jump_range_inc (uint32_t offset, uint32_t unichar)
+{
+ return thash_is_in_range (offset + THASH_JUMP_OFFSET, unichar);
+}
+
+uint32_t ctx_utf8_to_unichar (const char *input);
+int ctx_unichar_to_utf8 (uint32_t ch, uint8_t *dest);
+int ctx_utf8_len (const unsigned char first_byte);
+
+static int thash_utf5_length (uint32_t unichar)
+{
+ int octets = 0;
+ if (unichar == 0) return 1;
+ while (unichar)
+ { octets ++;
+ unichar /= 16;
+ }
+ return octets;
+}
+
+typedef struct EncodeUtf5 {
+ int is_utf5;
+ int offset;
+ int length;
+ void *write_data;
+ uint32_t current;
+} EncodeUtf5;
+
+void thash_encode_utf5 (const char *input, int inlen,
+ char *output, int *r_outlen)
+{
+ uint32_t offset = THASH_START_OFFSET;
+
+ int is_utf5 = 1;
+ int len = 0;
+
+ for (int i = 0; i < inlen; i+= ctx_utf8_len (input[i]))
+ {
+ int val = ctx_utf8_to_unichar(&input[i]);
+ int next_val = ' '; // always in range
+ int next_next_val = ' ';
+ int first_len = ctx_utf8_len (input[i]);
+ if (i + first_len < inlen)
{
- static CtxEntry sbuf[CTX_MAX_EDGE_LIST_SIZE];
- drawlist->entries = &sbuf[0];
- drawlist->size = CTX_MAX_EDGE_LIST_SIZE;
+ int next_len = ctx_utf8_to_unichar (&input[i + first_len]);
+ if (i + first_len + next_len < inlen)
+ {
+ next_next_val = ctx_utf8_to_unichar (&input[i + first_len + next_len]);
+ }
}
- else if (drawlist->flags & CTX_DRAWLIST_CURRENT_PATH)
+
+ if (is_utf5)
{
- static CtxEntry sbuf[CTX_MAX_EDGE_LIST_SIZE];
- drawlist->entries = &sbuf[0];
- drawlist->size = CTX_MAX_EDGE_LIST_SIZE;
- }
- else
+ int in_range =
+ thash_is_in_range (offset, val) +
+ thash_is_in_range (offset, next_val) +
+ thash_is_in_range (offset, next_next_val);
+ int change_cost = 4;
+ int no_change_cost = thash_utf5_length (val) + thash_utf5_length (next_val)
+ + thash_utf5_length (next_next_val);
+
+ if (in_range > 2 && change_cost < no_change_cost)
+ {
+ output[len++] = THASH_ENTER_DIRECT;
+ is_utf5 = 0;
+ }
+ } else
{
- static CtxEntry sbuf[CTX_MAX_JOURNAL_SIZE];
- drawlist->entries = &sbuf[0];
- drawlist->size = CTX_MAX_JOURNAL_SIZE;
- ctx_drawlist_compact (drawlist);
- }
-#else
- int new_size = desired_size;
- int min_size = CTX_MIN_JOURNAL_SIZE;
- int max_size = CTX_MAX_JOURNAL_SIZE;
- if ((drawlist->flags & CTX_DRAWLIST_EDGE_LIST))
- {
- min_size = CTX_MIN_EDGE_LIST_SIZE;
- max_size = CTX_MAX_EDGE_LIST_SIZE;
- }
- else if (drawlist->flags & CTX_DRAWLIST_CURRENT_PATH)
- {
- min_size = CTX_MIN_EDGE_LIST_SIZE;
- max_size = CTX_MAX_EDGE_LIST_SIZE;
- }
- else
- {
- ctx_drawlist_compact (drawlist);
+ if (!thash_is_in_range(offset, val))
+ {
+ if (thash_is_in_jump_range_dec (offset, val))
+ {
+ output[len++] = THASH_DEC_OFFSET;
+ offset -= THASH_JUMP_OFFSET;
+ }
+ else if (thash_is_in_jump_range_inc (offset, val))
+ {
+ output[len++] = THASH_INC_OFFSET;
+ offset += THASH_JUMP_OFFSET;
+ }
+ else
+ {
+ output[len++] = THASH_ENTER_UTF5;
+ is_utf5 = 1;
+ }
+ }
}
- if (new_size < drawlist->size)
- { return; }
- if (drawlist->size == max_size)
- { return; }
- if (new_size < min_size)
- { new_size = min_size; }
- if (new_size < drawlist->count)
- { new_size = drawlist->count + 4; }
- if (new_size >= max_size)
- { new_size = max_size; }
- if (new_size != drawlist->size)
+ if (is_utf5)
{
- //fprintf (stderr, "growing drawlist %p %i to %d from %d\n", drawlist, drawlist->flags, new_size,
drawlist->size);
- if (drawlist->entries)
+ int octets = 0;
+ offset = thash_new_offset (val);
+ while (val)
+ {
+ int oval = val % 16;
+ int last = 0;
+ if (val / 32 == 0) last = 16;
+ output[len+ (octets++)] = oval + last;
+ val /= 16;
+ }
+ for (int j = 0; j < octets/2; j++) // mirror in-place
+ {
+ int tmp = output[len+j];
+ output[len+j] = output[len+octets-1-j];
+ output[len+octets-1-j] = tmp;
+ }
+ len += octets;
+ }
+ else
+ {
+ if (val == 32)
+ {
+ output[len++] = THASH_SPACE;
+ }
+ else
+ {
+ output[len++]= val-offset+14;
+ }
+ }
+ }
+ if (len && output[len-1]==0)
+ output[len++] = 16;
+ output[len]=0;
+ *r_outlen = len;
+}
+
+uint64_t _thash (const char *utf8)
+{
+ char encoded[4096]="";
+ int encoded_len=0;
+ int wordlen = 0;
+ thash_encode_utf5 (utf8, strlen (utf8), encoded, &encoded_len);
+#if 0
+ Word word = {0};
+ word.utf5 = (encoded[0] != THASH_ENTER_DIRECT);
+ for (int i = !word.utf5; i < encoded_len; i++)
+ word_set_val (&word, wordlen++, encoded[i]);
+ return word.hash;
+#else
+ uint64_t hash = 0;
+ int utf5 = (encoded[0] != THASH_ENTER_DIRECT);
+ for (int i = !utf5; i < encoded_len; i++)
+ {
+ uint64_t val = encoded[i];
+
+ if (wordlen < THASH_MAXLEN)
{
- //printf ("grow %p to %d from %d\n", drawlist, new_size, drawlist->size);
- CtxEntry *ne = (CtxEntry *) malloc (sizeof (CtxEntry) * new_size);
- memcpy (ne, drawlist->entries, drawlist->size * sizeof (CtxEntry) );
- free (drawlist->entries);
- drawlist->entries = ne;
- //drawlist->entries = (CtxEntry*)malloc (drawlist->entries, sizeof (CtxEntry) * new_size);
+ hash = hash | (val << (5*wordlen));
+ hash &= (((uint64_t)1<<52)-1);
}
- else
+ else
{
- //printf ("allocating for %p %d\n", drawlist, new_size);
- drawlist->entries = (CtxEntry *) malloc (sizeof (CtxEntry) * new_size);
+ hash = hash ^ ((hash << 4) + val);
+ hash &= (((uint64_t)1<<52)-1);
}
- drawlist->size = new_size;
- }
- //fprintf (stderr, "drawlist %p is %d\n", drawlist, drawlist->size);
+ wordlen++;
+ }
+ hash <<= 1;
+ if (wordlen >= THASH_MAXLEN)
+ hash |= ((uint64_t)1<<51); // overflowed
+ return hash | utf5;
#endif
}
-static int
-ctx_drawlist_add_single (CtxDrawlist *drawlist, CtxEntry *entry)
+typedef struct _Interned Interned;
+
+struct _Interned {
+ uint64_t hash;
+ char *string;
+};
+
+static Interned *interned = NULL;
+static int n_interned = 0;
+static int s_interned = 0;
+static int interned_sorted = 1;
+
+static int interned_compare (const void *a, const void *b)
{
- int max_size = CTX_MAX_JOURNAL_SIZE;
- int ret = drawlist->count;
- if (drawlist->flags & CTX_DRAWLIST_EDGE_LIST)
- {
- max_size = CTX_MAX_EDGE_LIST_SIZE;
- }
- else if (drawlist->flags & CTX_DRAWLIST_CURRENT_PATH)
- {
- max_size = CTX_MAX_EDGE_LIST_SIZE;
- }
- if (drawlist->flags & CTX_DRAWLIST_DOESNT_OWN_ENTRIES)
+ const Interned *ia = a;
+ const Interned *ib = b;
+ if (ia->hash < ib->hash ) return -1;
+ else if (ia->hash > ib->hash ) return 1;
+ return 0;
+}
+
+
+uint64_t thash (const char *utf8)
+{
+ uint64_t hash = _thash (utf8);
+#ifdef THASH_NO_INTERNING
+ return hash;
+#endif
+ if (hash & ((uint64_t)1<<51)) /* overflowed */
+ {
+ int i;
+ for (i = 0; i < n_interned; i++)
{
- return ret;
+ Interned *entry = &interned[i];
+ if (entry->hash == hash)
+ return hash;
}
- if (ret + 8 >= drawlist->size - 20)
+
+ if (n_interned + 1 >= s_interned)
{
- int new_ = CTX_MAX (drawlist->size * 2, ret + 8);
- ctx_drawlist_resize (drawlist, new_);
+ s_interned = (s_interned + 128)*1.5;
+ //fprintf (stderr, "\r%p %i ", interned, s_interned);
+ interned = realloc (interned, s_interned * sizeof (Interned));
}
- if (drawlist->count >= max_size - 20)
{
- return 0;
+ Interned *entry = &interned[n_interned];
+ entry->hash = hash;
+ entry->string = strdup (utf8);
}
- drawlist->entries[drawlist->count] = *entry;
- ret = drawlist->count;
- drawlist->count++;
- return ret;
+ n_interned++;
+ interned_sorted = 0;
+ }
+ return hash;
}
+uint64_t ctx_strhash(const char *str, int ignored) { return thash (str);}
+typedef struct ThashUtf5Dec {
+ int is_utf5;
+ int offset;
+ void *write_data;
+ uint32_t current;
+ void (*append_unichar) (uint32_t unichar, void *write_data);
+} ThashUtf5Dec;
+typedef struct ThashUtf5DecDefaultData {
+ uint8_t *buf;
+ int length;
+} ThashUtf5DecDefaultData;
+static void thash_decode_utf5_append_unichar_as_utf8 (uint32_t unichar, void *write_data)
+{
+ ThashUtf5DecDefaultData *data = write_data;
+ unsigned char utf8[8]="";
+ utf8[ctx_unichar_to_utf8 (unichar, utf8)]=0;
+ for (int j = 0; utf8[j]; j++)
+ data->buf[data->length++]=utf8[j];
+ data->buf[data->length]=0;
+}
-int
-ctx_add_single (Ctx *ctx, void *entry)
+void thash_decode_utf5 (ThashUtf5Dec *dec, uint8_t in)
{
- return ctx_drawlist_add_single (&ctx->drawlist, (CtxEntry *) entry);
+ if (dec->is_utf5)
+ {
+ if (in > 16)
+ {
+ if (dec->current)
+ {
+ dec->offset = thash_new_offset (dec->current);
+ dec->append_unichar (dec->current, dec->write_data);
+ dec->current = 0;
+ }
+ }
+ if (in == THASH_ENTER_DIRECT)
+ {
+ if (dec->current)
+ {
+ dec->offset = thash_new_offset (dec->current);
+ dec->append_unichar (dec->current, dec->write_data);
+ dec->current = 0;
+ }
+ dec->is_utf5 = 0;
+ }
+ else
+ {
+ dec->current = dec->current * 16 + (in % 16);
+ }
+ }
+ else
+ {
+ switch (in)
+ {
+ case THASH_ENTER_UTF5: dec->is_utf5 = 1; break;
+ case THASH_SPACE: dec->append_unichar (' ', dec->write_data); break;
+ case THASH_DEC_OFFSET: dec->offset -= THASH_JUMP_OFFSET; break;
+ case THASH_INC_OFFSET: dec->offset += THASH_JUMP_OFFSET; break;
+ default:
+ dec->append_unichar (dec->offset + in - 14, dec->write_data);
+ }
+ }
}
-int
-ctx_drawlist_add_entry (CtxDrawlist *drawlist, CtxEntry *entry)
+void thash_decode_utf5_bytes (int is_utf5,
+ const unsigned char *input, int inlen,
+ char *output, int *r_outlen)
{
- int length = ctx_conts_for_entry (entry) + 1;
- int ret = 0;
- for (int i = 0; i < length; i ++)
+ ThashUtf5DecDefaultData append_data= {(unsigned char*)output, };
+ ThashUtf5Dec dec = {is_utf5,
+ THASH_START_OFFSET,
+ &append_data,
+ 0, thash_decode_utf5_append_unichar_as_utf8
+ };
+ for (int i = 0; i < inlen; i++)
+ {
+ thash_decode_utf5 (&dec, input[i]);
+ }
+ if (dec.current)
+ dec.append_unichar (dec.current, dec.write_data);
+ if (r_outlen)*r_outlen = append_data.length;
+}
+
+const char *thash_decode (uint64_t hash)
+{
+ if (!interned_sorted && interned)
+ {
+ qsort (interned, n_interned, sizeof (Interned), interned_compare);
+ interned_sorted = 1;
+ }
+ if (hash & ((uint64_t)1<<51))
+ {
+
+ for (int i = 0; i < n_interned; i++)
{
- ret = ctx_drawlist_add_single (drawlist, &entry[i]);
+ Interned *entry = &interned[i];
+ if (entry->hash == hash)
+ return entry->string;
}
+ return "[missing string]";
+ }
+
+ static char ret[4096]="";
+ uint8_t utf5[40]="";
+ uint64_t tmp = hash & (((uint64_t)1<<51)-1);
+ int len = 0;
+ int is_utf5 = tmp & 1;
+ tmp /= 2;
+ int in_utf5 = is_utf5;
+ while (tmp > 0)
+ {
+ uint64_t remnant = tmp % 32;
+ uint64_t val = remnant;
+
+ if ( in_utf5 && val == THASH_ENTER_DIRECT) in_utf5 = 0;
+ else if (!in_utf5 && val == THASH_ENTER_UTF5) in_utf5 = 1;
+
+ utf5[len++] = val;
+ tmp -= remnant;
+ tmp /= 32;
+ }
+ if (in_utf5 && len && utf5[len-1] > 'G')
+ {
+ utf5[len++] = 0;//utf5_alphabet[0];
+ }
+ utf5[len]=0;
+ int retlen = sizeof (ret);
+ thash_decode_utf5_bytes (is_utf5, utf5, len, ret, &retlen);
+ ret[len]=0;
return ret;
}
#if 0
-int
-ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry)
+
+#include <assert.h>
+#pragma pack(push,1)
+typedef union Word
+{
+ uint64_t hash;
+ struct {
+ unsigned int utf5:1;
+ unsigned int c0:5;
+ unsigned int c1:5;
+ unsigned int c2:5;
+ unsigned int c3:5;
+ unsigned int c4:5;
+ unsigned int c5:5;
+ unsigned int c6:5;
+ unsigned int c7:5;
+ unsigned int c8:5;
+ unsigned int c9:5;
+ unsigned int overflowed:1;
+ };
+} Word;
+
+static inline void word_set_val (Word *word, int no, int val)
{
- int length = ctx_conts_for_entry (entry) + 1;
- int tmp_pos = ctx_drawlist_add_entry (drawlist, entry);
- for (int i = 0; i < length; i++)
- {
- for (int j = pos + i + 1; j < tmp_pos; j++)
- drawlist->entries[j] = entry[j-1];
- drawlist->entries[pos + i] = entry[i];
+#if 0
+ switch(no)
+ {
+ case 0: word->c0 = val; break;
+ case 1: word->c1 = val; break;
+ case 2: word->c2 = val; break;
+ case 3: word->c3 = val; break;
+ case 4: word->c4 = val; break;
+ case 5: word->c5 = val; break;
+ case 6: word->c6 = val; break;
+ case 7: word->c7 = val; break;
+ case 8: word->c8 = val; break;
+ case 9: word->c9 = val; break;
+ default:
+ // for overflow only works when setting all in sequence
+ word->hash = word->hash + ((uint64_t)(val) << (5*no+1));
+ word->overflowed = 1;
+ break;
}
- return pos;
-}
+#else
+ word->hash = word->hash | ((uint64_t)(val) << (5*no+1));
+ if (no >= 9)
+ word->hash |= ((uint64_t)1<<51);
+ word->hash &= (((uint64_t)1<<52)-1);
#endif
-int
-ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry)
+}
+
+static inline int word_get_val (Word *word, int no)
{
- int length = ctx_conts_for_entry (entry) + 1;
- int tmp_pos = ctx_drawlist_add_entry (drawlist, entry);
-#if 1
- for (int i = 0; i < length; i++)
+ switch(no)
{
- for (int j = tmp_pos; j > pos + i; j--)
- drawlist->entries[j] = drawlist->entries[j-1];
- drawlist->entries[pos + i] = entry[i];
+ case 0: return word->c0;break;
+ case 1: return word->c1;break;
+ case 2: return word->c2;break;
+ case 3: return word->c3;break;
+ case 4: return word->c4;break;
+ case 5: return word->c5;break;
+ case 6: return word->c6;break;
+ case 7: return word->c7;break;
+ case 8: return word->c8;break;
+ case 9: return word->c9;break;
}
- return pos;
-#endif
- return tmp_pos;
}
-int ctx_append_drawlist (Ctx *ctx, void *data, int length)
+static inline int word_get_length (Word *word)
{
- CtxEntry *entries = (CtxEntry *) data;
- if (length % sizeof (CtxEntry) )
- {
- ctx_log("drawlist not multiple of 9\n");
- return -1;
- }
- for (unsigned int i = 0; i < length / sizeof (CtxEntry); i++)
- {
- ctx_drawlist_add_single (&ctx->drawlist, &entries[i]);
- }
- return 0;
+ int len = 0;
+ if (word->c0) len ++; else return len;
+ if (word->c1) len ++; else return len;
+ if (word->c2) len ++; else return len;
+ if (word->c3) len ++; else return len;
+ if (word->c4) len ++; else return len;
+ if (word->c5) len ++; else return len;
+ if (word->c6) len ++; else return len;
+ if (word->c7) len ++; else return len;
+ if (word->c8) len ++; else return len;
+ if (word->c9) len ++; else return len;
+ return len;
}
-int ctx_set_drawlist (Ctx *ctx, void *data, int length)
+
+static Word *word_append_unichar (Word *word, uint32_t unichar)
{
- CtxDrawlist *drawlist = &ctx->drawlist;
- ctx->drawlist.count = 0;
- if (drawlist->flags & CTX_DRAWLIST_DOESNT_OWN_ENTRIES)
+ //word_set_char (word, word_get_length (word), unichar);
+ // append unichar - possibly advancing.
+ return word;
+}
+#endif
+
+#endif
+/* atty - audio interface and driver for terminals
+ * Copyright (C) 2020 Øyvind Kolås <pippin gimp org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static const char *base64_map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+static void bin2base64_group (const unsigned char *in, int remaining, char *out)
+{
+ unsigned char digit[4] = {0,0,64,64};
+ int i;
+ digit[0] = in[0] >> 2;
+ digit[1] = ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4);
+ if (remaining > 1)
{
- return -1;
+ digit[2] = ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6);
+ if (remaining > 2)
+ digit[3] = ((in[2] & 0x3f));
}
- if (length % 9) return -1;
- ctx_drawlist_resize (drawlist, length/9);
- memcpy (drawlist->entries, data, length);
- drawlist->count = length / 9;
- return length;
+ for (i = 0; i < 4; i++)
+ out[i] = base64_map[digit[i]];
}
-
-int ctx_get_drawlist_count (Ctx *ctx)
+void
+ctx_bin2base64 (const void *bin,
+ int bin_length,
+ char *ascii)
{
- return ctx->drawlist.count;
+ /* this allocation is a hack to ensure we always produce the same result,
+ * regardless of padding data accidentally taken into account.
+ */
+ unsigned char *bin2 = calloc (bin_length + 4, 1);
+ unsigned const char *p = bin2;
+ int i;
+ memcpy (bin2, bin, 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);
+ ascii[i*4]=0;
}
-const CtxEntry *ctx_get_drawlist (Ctx *ctx)
+static unsigned char base64_revmap[255];
+static void base64_revmap_init (void)
{
- return ctx->drawlist.entries;
+ static int done = 0;
+ if (done)
+ return;
+
+ for (int i = 0; i < 255; i ++)
+ base64_revmap[i]=255;
+ for (int i = 0; i < 64; i ++)
+ base64_revmap[((const unsigned char*)base64_map)[i]]=i;
+ /* include variants used in URI encodings for decoder,
+ * even if that is not how we encode
+ */
+ base64_revmap['-']=62;
+ base64_revmap['_']=63;
+ base64_revmap['+']=62;
+ base64_revmap['/']=63;
+
+ done = 1;
}
+
int
-ctx_add_data (Ctx *ctx, void *data, int length)
+ctx_base642bin (const char *ascii,
+ int *length,
+ unsigned char *bin)
{
- if (length % sizeof (CtxEntry) )
- {
- //ctx_log("err\n");
- return -1;
+ int i;
+ int charno = 0;
+ int outputno = 0;
+ int carry = 0;
+ base64_revmap_init ();
+ for (i = 0; ascii[i]; i++)
+ {
+ int bits = base64_revmap[((const unsigned char*)ascii)[i]];
+ if (length && outputno > *length)
+ {
+ *length = -1;
+ return -1;
+ }
+ if (bits != 255)
+ {
+ switch (charno % 4)
+ {
+ case 0:
+ carry = bits;
+ break;
+ case 1:
+ bin[outputno] = (carry << 2) | (bits >> 4);
+ outputno++;
+ carry = bits & 15;
+ break;
+ case 2:
+ bin[outputno] = (carry << 4) | (bits >> 2);
+ outputno++;
+ carry = bits & 3;
+ break;
+ case 3:
+ bin[outputno] = (carry << 6) | bits;
+ outputno++;
+ carry = 0;
+ break;
+ }
+ charno++;
+ }
}
- /* some more input verification might be in order.. like
- * verify that it is well-formed up to length?
- *
- * also - it would be very useful to stop processing
- * upon flush - and do drawlist resizing.
- */
- return ctx_drawlist_add_entry (&ctx->drawlist, (CtxEntry *) data);
+ bin[outputno]=0;
+ if (length)
+ *length= outputno;
+ return outputno;
}
+#ifndef CTX_DRAWLIST_H
+#define CTX_DRAWLIST_H
-int ctx_drawlist_add_u32 (CtxDrawlist *drawlist, CtxCode code, uint32_t u32[2])
-{
- CtxEntry entry = {code, {{0},}};
- entry.data.u32[0] = u32[0];
- entry.data.u32[1] = u32[1];
- return ctx_drawlist_add_single (drawlist, &entry);
-}
+static int
+ctx_conts_for_entry (CtxEntry *entry);
+static void
+ctx_iterator_init (CtxIterator *iterator,
+ CtxDrawlist *drawlist,
+ int start_pos,
+ int flags);
-int ctx_drawlist_add_data (CtxDrawlist *drawlist, const void *data, int length)
-{
- CtxEntry entry = {CTX_DATA, {{0},}};
- entry.data.u32[0] = 0;
- entry.data.u32[1] = 0;
- int ret = ctx_drawlist_add_single (drawlist, &entry);
- if (!data) { return -1; }
- int length_in_blocks;
- if (length <= 0) { length = strlen ( (char *) data) + 1; }
- length_in_blocks = length / sizeof (CtxEntry);
- length_in_blocks += (length % sizeof (CtxEntry) ) ?1:0;
- if (drawlist->count + length_in_blocks + 4 > drawlist->size)
- { ctx_drawlist_resize (drawlist, drawlist->count * 1.2 + length_in_blocks + 32); }
- if (drawlist->count >= drawlist->size)
- { return -1; }
- drawlist->count += length_in_blocks;
- drawlist->entries[ret].data.u32[0] = length;
- drawlist->entries[ret].data.u32[1] = length_in_blocks;
- memcpy (&drawlist->entries[ret+1], data, length);
- {
- //int reverse = ctx_drawlist_add (drawlist, CTX_DATA_REV);
- CtxEntry entry = {CTX_DATA_REV, {{0},}};
- entry.data.u32[0] = length;
- entry.data.u32[1] = length_in_blocks;
- ctx_drawlist_add_single (drawlist, &entry);
- /* this reverse marker exist to enable more efficient
- front to back traversal, can be ignored in other
- direction, is this needed after string setters as well?
- */
- }
- return ret;
-}
+CtxCommand *
+ctx_iterator_next (CtxIterator *iterator);
+int ctx_iterator_pos (CtxIterator *iterator);
-static CtxEntry
-ctx_void (CtxCode code)
-{
- CtxEntry command;
- command.code = code;
- command.data.u32[0] = 0;
- command.data.u32[1] = 0;
- return command;
-}
+static void ctx_drawlist_compact (CtxDrawlist *drawlist);
+static void
+ctx_drawlist_resize (CtxDrawlist *drawlist, int desired_size);
+static int
+ctx_drawlist_add_single (CtxDrawlist *drawlist, CtxEntry *entry);
+int
+ctx_add_single (Ctx *ctx, void *entry);
+int ctx_drawlist_add_entry (CtxDrawlist *drawlist, CtxEntry *entry);
+int
+ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry);
+int ctx_append_drawlist (Ctx *ctx, void *data, int length);
+int ctx_set_drawlist (Ctx *ctx, void *data, int length);
+int ctx_get_drawlist_count (Ctx *ctx);
+const CtxEntry *ctx_get_drawlist (Ctx *ctx);
+int
+ctx_add_data (Ctx *ctx, void *data, int length);
-static CtxEntry
-ctx_f (CtxCode code, float x, float y)
-{
- CtxEntry command = ctx_void (code);
- command.data.f[0] = x;
- command.data.f[1] = y;
- return command;
-}
+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);
static CtxEntry
-ctx_u32 (CtxCode code, uint32_t x, uint32_t y)
-{
- CtxEntry command = ctx_void (code);
- command.data.u32[0] = x;
- command.data.u32[1] = y;
- return command;
-}
-
+ctx_void (CtxCode code);
+static CtxEntry
+ctx_f (CtxCode code, float x, float y);
+static CtxEntry
+ctx_u32 (CtxCode code, uint32_t x, uint32_t y);
#if 0
static CtxEntry
-ctx_s32 (CtxCode code, int32_t x, int32_t y)
-{
- CtxEntry command = ctx_void (code);
- command.data.s32[0] = x;
- command.data.s32[1] = y;
- return command;
-}
+ctx_s32 (CtxCode code, int32_t x, int32_t y);
#endif
CtxEntry
-ctx_s16 (CtxCode code, int x0, int y0, int x1, int y1)
-{
- CtxEntry command = ctx_void (code);
- command.data.s16[0] = x0;
- command.data.s16[1] = y0;
- command.data.s16[2] = x1;
- command.data.s16[3] = y1;
- return command;
-}
-
+ctx_s16 (CtxCode code, int x0, int y0, int x1, int y1);
static CtxEntry
ctx_u8 (CtxCode code,
uint8_t a, uint8_t b, uint8_t c, uint8_t d,
- uint8_t e, uint8_t f, uint8_t g, uint8_t h)
-{
- CtxEntry command = ctx_void (code);
- command.data.u8[0] = a;
- command.data.u8[1] = b;
- command.data.u8[2] = c;
- command.data.u8[3] = d;
- command.data.u8[4] = e;
- command.data.u8[5] = f;
- command.data.u8[6] = g;
- command.data.u8[7] = h;
- return command;
-}
+ uint8_t e, uint8_t f, uint8_t g, uint8_t h);
#define CTX_PROCESS_VOID(cmd) do {\
CtxEntry command = ctx_void (cmd); \
@@ -6488,5648 +6841,5579 @@ ctx_u8 (CtxCode code,
ctx_process (ctx, &command);}while(0)
+#if CTX_BITPACK_PACKER
+static int
+ctx_last_history (CtxDrawlist *drawlist);
+#endif
+
+#if CTX_BITPACK_PACKER
static void
-ctx_process_cmd_str_with_len (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1, int
len)
-{
- CtxEntry commands[1 + 2 + len/8];
- ctx_memset (commands, 0, sizeof (commands) );
- commands[0] = ctx_u32 (code, arg0, arg1);
- commands[1].code = CTX_DATA;
- commands[1].data.u32[0] = len;
- commands[1].data.u32[1] = len/9+1;
- memcpy( (char *) &commands[2].data.u8[0], string, len);
- ( (char *) (&commands[2].data.u8[0]) ) [len]=0;
- ctx_process (ctx, commands);
-}
+ctx_drawlist_remove_tiny_curves (CtxDrawlist *drawlist, int start_pos);
static void
-ctx_process_cmd_str (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1)
+ctx_drawlist_bitpack (CtxDrawlist *drawlist, int start_pos);
+#endif
+
+static void
+ctx_drawlist_compact (CtxDrawlist *drawlist);
+static void
+ctx_process_cmd_str (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1);
+static void
+ctx_process_cmd_str_float (Ctx *ctx, CtxCode code, const char *string, float arg0, float arg1);
+static void
+ctx_process_cmd_str_with_len (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1, int
len);
+
+#endif
+
+#ifndef __CTX_UTIL_H
+#define __CTX_UTIL_H
+
+inline static float ctx_fast_hypotf (float x, float y)
{
- ctx_process_cmd_str_with_len (ctx, code, string, arg0, arg1, strlen (string));
+ if (x < 0) { x = -x; }
+ if (y < 0) { y = -y; }
+ if (x < y)
+ { return 0.96f * y + 0.4f * x; }
+ else
+ { return 0.96f * x + 0.4f * y; }
}
-
-#if CTX_BITPACK_PACKER
-static int
-ctx_last_history (CtxDrawlist *drawlist)
+static int ctx_str_is_number (const char *str)
{
- int last_history = 0;
- int i = 0;
- while (i < drawlist->count)
+ int got_digit = 0;
+ for (int i = 0; str[i]; i++)
+ {
+ if (str[i] >= '0' && str[i] <= '9')
{
- CtxEntry *entry = &drawlist->entries[i];
- i += (ctx_conts_for_entry (entry) + 1);
+ got_digit ++;
}
- return last_history;
+ else if (str[i] == '.')
+ {
+ }
+ else
+ return 0;
+ }
+ if (got_digit)
+ return 1;
+ return 0;
}
-#endif
-#if CTX_BITPACK_PACKER
+#if CTX_FONTS_FROM_FILE
-static float
-find_max_dev (CtxEntry *entry, int nentrys)
+typedef struct CtxFileContent
{
- float max_dev = 0.0;
- for (int c = 0; c < nentrys; c++)
+ char *path;
+ unsigned char *contents;
+ long length;
+ int free_data;
+} CtxFileContent;
+
+CtxList *registered_contents = NULL;
+
+void
+ctx_register_contents (const char *path,
+ const unsigned char *contents,
+ long length,
+ int free_data)
+{
+ // if (path[0] != '/') && strchr(path, ':'))
+ // with this check regular use is faster, but we lose
+ // generic filesystem overrides..
+ for (CtxList *l = registered_contents; l; l = l->next)
+ {
+ CtxFileContent *c = l->data;
+ if (!strcmp (c->path, path))
{
- for (int d = 0; d < 2; d++)
- {
- if (entry[c].data.f[d] > max_dev)
- { max_dev = entry[c].data.f[d]; }
- if (entry[c].data.f[d] < -max_dev)
- { max_dev = -entry[c].data.f[d]; }
- }
+ if (c->free_data)
+ {
+ free (c->contents);
+ }
+ c->free_data = free_data;
+ c->contents = (unsigned char*)contents;
+ c->length = length;
+ return;
}
- return max_dev;
+ }
+ CtxFileContent *c = calloc (sizeof (CtxFileContent), 1);
+ c->free_data = free_data;
+ c->contents = (unsigned char*)contents;
+ c->length = length;
+ ctx_list_append (®istered_contents, c);
}
-static void
-pack_s8_args (CtxEntry *entry, int npairs)
+void
+_ctx_file_set_contents (const char *path,
+ const unsigned char *contents,
+ long length)
{
- for (int c = 0; c < npairs; c++)
- for (int d = 0; d < 2; d++)
- { entry[0].data.s8[c*2+d]=entry[c].data.f[d] * CTX_SUBDIV; }
+ FILE *file;
+ file = fopen (path, "wb");
+ if (!file)
+ { return; }
+ if (length < 0) length = strlen ((const char*)contents);
+ fwrite (contents, 1, length, file);
+ fclose (file);
}
-static void
-pack_s16_args (CtxEntry *entry, int npairs)
+static int
+__ctx_file_get_contents (const char *path,
+ unsigned char **contents,
+ long *length)
{
- for (int c = 0; c < npairs; c++)
- for (int d = 0; d < 2; d++)
- { entry[0].data.s16[c*2+d]=entry[c].data.f[d] * CTX_SUBDIV; }
+ FILE *file;
+ long size;
+ long remaining;
+ char *buffer;
+ file = fopen (path, "rb");
+ if (!file)
+ { return -1; }
+ fseek (file, 0, SEEK_END);
+ size = remaining = ftell (file);
+ if (length)
+ { *length =size; }
+ rewind (file);
+ buffer = (char*)malloc (size + 8);
+ if (!buffer)
+ {
+ fclose (file);
+ return -1;
+ }
+ remaining -= fread (buffer, 1, remaining, file);
+ if (remaining)
+ {
+ fclose (file);
+ free (buffer);
+ return -1;
+ }
+ fclose (file);
+ *contents = (unsigned char*) buffer;
+ buffer[size] = 0;
+ return 0;
}
+
+#include <limits.h>
+
+int
+ctx_get_contents (const char *uri,
+ unsigned char **contents,
+ long *length);
+
+
+
#endif
-#if CTX_BITPACK_PACKER
-static void
-ctx_drawlist_remove_tiny_curves (CtxDrawlist *drawlist, int start_pos)
+
+#endif
+
+
+static int
+ctx_conts_for_entry (CtxEntry *entry)
{
- CtxIterator iterator;
- if ( (drawlist->flags & CTX_TRANSFORMATION_BITPACK) == 0)
- { return; }
- ctx_iterator_init (&iterator, drawlist, start_pos, CTX_ITERATOR_FLAT);
- iterator.end_pos = drawlist->count - 5;
- CtxCommand *command = NULL;
- while ( (command = ctx_iterator_next (&iterator) ) )
+ switch (entry->code)
{
- CtxEntry *entry = &command->entry;
- /* things smaller than this have probably been scaled down
- beyond recognition, bailing for both better packing and less rasterization work
- */
- if (command[0].code == CTX_REL_CURVE_TO)
+ case CTX_DATA:
+ return entry->data.u32[1];
+ case CTX_LINEAR_GRADIENT:
+ //case CTX_DEFINE_TEXTURE:
+ return 1;
+ case CTX_RADIAL_GRADIENT:
+ case CTX_ARC:
+ case CTX_ARC_TO:
+ case CTX_REL_ARC_TO:
+ case CTX_CURVE_TO:
+ case CTX_REL_CURVE_TO:
+ case CTX_APPLY_TRANSFORM:
+ case CTX_COLOR:
+ case CTX_ROUND_RECTANGLE:
+ case CTX_SHADOW_COLOR:
+ return 2;
+ case CTX_FILL_RECT:
+ case CTX_STROKE_RECT:
+ case CTX_RECTANGLE:
+ case CTX_VIEW_BOX:
+ case CTX_REL_QUAD_TO:
+ case CTX_QUAD_TO:
+ return 1;
+
+ case CTX_TEXT:
+ case CTX_LINE_DASH:
+ case CTX_COLOR_SPACE:
+ case CTX_STROKE_TEXT:
+ case CTX_FONT:
+ case CTX_TEXTURE:
{
- float max_dev = find_max_dev (entry, 3);
- if (max_dev < 1.0)
- {
- entry[0].code = CTX_REL_LINE_TO;
- entry[0].data.f[0] = entry[2].data.f[0];
- entry[0].data.f[1] = entry[2].data.f[1];
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- }
+ int eid_len = entry[1].data.u32[1];
+ return eid_len + 1;
+ }
+ case CTX_DEFINE_TEXTURE:
+ {
+ int eid_len = entry[2].data.u32[1];
+ int pix_len = entry[2 + eid_len + 1].data.u32[1];
+ return eid_len + pix_len + 2 + 1;
}
+
+ default:
+ return 0;
}
}
-#endif
-#if CTX_BITPACK_PACKER
+// expanding arc_to to arc can be the job
+// of a layer in front of renderer?
+// doing:
+// rectangle
+// arc
+// ... etc reduction to beziers
+// or even do the reduction to
+// polylines directly here...
+// making the rasterizer able to
+// only do poly-lines? will that be faster?
+
+/* the iterator - should decode bitpacked data as well -
+ * making the rasterizers simpler, possibly do unpacking
+ * all the way to absolute coordinates.. unless mixed
+ * relative/not are wanted.
+ */
+
+
static void
-ctx_drawlist_bitpack (CtxDrawlist *drawlist, int start_pos)
+ctx_iterator_init (CtxIterator *iterator,
+ CtxDrawlist *drawlist,
+ int start_pos,
+ int flags)
+{
+ iterator->drawlist = drawlist;
+ iterator->flags = flags;
+ iterator->bitpack_pos = 0;
+ iterator->bitpack_length = 0;
+ iterator->pos = start_pos;
+ iterator->end_pos = drawlist->count;
+ iterator->first_run = 1; // -1 is a marker used for first run
+ ctx_memset (iterator->bitpack_command, 0, sizeof (iterator->bitpack_command) );
+}
+
+int ctx_iterator_pos (CtxIterator *iterator)
{
+ return iterator->pos;
+}
+
+static CtxEntry *_ctx_iterator_next (CtxIterator *iterator)
+{
+ int ret = iterator->pos;
+ CtxEntry *entry = &iterator->drawlist->entries[ret];
+ if (ret >= iterator->end_pos)
+ { return NULL; }
+ if (iterator->first_run == 0)
+ { iterator->pos += (ctx_conts_for_entry (entry) + 1); }
+ iterator->first_run = 0;
+ if (iterator->pos >= iterator->end_pos)
+ { return NULL; }
+ return &iterator->drawlist->entries[iterator->pos];
+}
+
+// 6024x4008
#if CTX_BITPACK
- int i = 0;
- if ( (drawlist->flags & CTX_TRANSFORMATION_BITPACK) == 0)
- { return; }
- ctx_drawlist_remove_tiny_curves (drawlist, drawlist->bitpack_pos);
- i = drawlist->bitpack_pos;
- if (start_pos > i)
- { i = start_pos; }
- while (i < drawlist->count - 4) /* the -4 is to avoid looking past
- initialized data we're not ready
- to bitpack yet*/
+static void
+ctx_iterator_expand_s8_args (CtxIterator *iterator, CtxEntry *entry)
+{
+ int no = 0;
+ for (int cno = 0; cno < 4; cno++)
+ for (int d = 0; d < 2; d++, no++)
+ iterator->bitpack_command[cno].data.f[d] =
+ entry->data.s8[no] * 1.0f / CTX_SUBDIV;
+ iterator->bitpack_command[0].code =
+ iterator->bitpack_command[1].code =
+ iterator->bitpack_command[2].code =
+ iterator->bitpack_command[3].code = CTX_CONT;
+ iterator->bitpack_length = 4;
+ iterator->bitpack_pos = 0;
+}
+
+static void
+ctx_iterator_expand_s16_args (CtxIterator *iterator, CtxEntry *entry)
+{
+ int no = 0;
+ for (int cno = 0; cno < 2; cno++)
+ for (int d = 0; d < 2; d++, no++)
+ iterator->bitpack_command[cno].data.f[d] = entry->data.s16[no] * 1.0f /
+ CTX_SUBDIV;
+ iterator->bitpack_command[0].code =
+ iterator->bitpack_command[1].code = CTX_CONT;
+ iterator->bitpack_length = 2;
+ iterator->bitpack_pos = 0;
+}
+#endif
+
+CtxCommand *
+ctx_iterator_next (CtxIterator *iterator)
+{
+ CtxEntry *ret;
+#if CTX_BITPACK
+ int expand_bitpack = iterator->flags & CTX_ITERATOR_EXPAND_BITPACK;
+again:
+ if (iterator->bitpack_length)
{
- CtxEntry *entry = &drawlist->entries[i];
- if (entry[0].code == CTX_SET_RGBA_U8 &&
- entry[1].code == CTX_MOVE_TO &&
- entry[2].code == CTX_REL_LINE_TO &&
- entry[3].code == CTX_REL_LINE_TO &&
- entry[4].code == CTX_REL_LINE_TO &&
- entry[5].code == CTX_REL_LINE_TO &&
- entry[6].code == CTX_FILL &&
- ctx_fabsf (entry[2].data.f[0] - 1.0f) < 0.02f &&
- ctx_fabsf (entry[3].data.f[1] - 1.0f) < 0.02f)
+ ret = &iterator->bitpack_command[iterator->bitpack_pos];
+ iterator->bitpack_pos += (ctx_conts_for_entry (ret) + 1);
+ if (iterator->bitpack_pos >= iterator->bitpack_length)
{
- entry[0].code = CTX_SET_PIXEL;
- entry[0].data.u16[2] = entry[1].data.f[0];
- entry[0].data.u16[3] = entry[1].data.f[1];
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- entry[3].code = CTX_NOP;
- entry[4].code = CTX_NOP;
- entry[5].code = CTX_NOP;
- entry[6].code = CTX_NOP;
- }
-#if 1
- else if (entry[0].code == CTX_REL_LINE_TO)
- {
- if (entry[1].code == CTX_REL_LINE_TO &&
- entry[2].code == CTX_REL_LINE_TO &&
- entry[3].code == CTX_REL_LINE_TO)
- {
- float max_dev = find_max_dev (entry, 4);
- if (max_dev < 114 / CTX_SUBDIV)
- {
- pack_s8_args (entry, 4);
- entry[0].code = CTX_REL_LINE_TO_X4;
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- entry[3].code = CTX_NOP;
- }
- }
- else if (entry[1].code == CTX_REL_CURVE_TO)
- {
- float max_dev = find_max_dev (entry, 4);
- if (max_dev < 114 / CTX_SUBDIV)
- {
- pack_s8_args (entry, 4);
- entry[0].code = CTX_REL_LINE_TO_REL_CURVE_TO;
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- entry[3].code = CTX_NOP;
- }
- }
- else if (entry[1].code == CTX_REL_LINE_TO &&
- entry[2].code == CTX_REL_LINE_TO &&
- entry[3].code == CTX_REL_LINE_TO)
- {
- float max_dev = find_max_dev (entry, 4);
- if (max_dev < 114 / CTX_SUBDIV)
- {
- pack_s8_args (entry, 4);
- entry[0].code = CTX_REL_LINE_TO_X4;
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- entry[3].code = CTX_NOP;
- }
- }
- else if (entry[1].code == CTX_REL_MOVE_TO)
- {
- float max_dev = find_max_dev (entry, 2);
- if (max_dev < 31000 / CTX_SUBDIV)
- {
- pack_s16_args (entry, 2);
- entry[0].code = CTX_REL_LINE_TO_REL_MOVE_TO;
- entry[1].code = CTX_NOP;
- }
- }
- else if (entry[1].code == CTX_REL_LINE_TO)
- {
- float max_dev = find_max_dev (entry, 2);
- if (max_dev < 31000 / CTX_SUBDIV)
- {
- pack_s16_args (entry, 2);
- entry[0].code = CTX_REL_LINE_TO_X2;
- entry[1].code = CTX_NOP;
- }
- }
+ iterator->bitpack_length = 0;
}
+ return (CtxCommand *) ret;
+ }
#endif
-#if 1
- else if (entry[0].code == CTX_REL_CURVE_TO)
- {
- if (entry[3].code == CTX_REL_LINE_TO)
- {
- float max_dev = find_max_dev (entry, 4);
- if (max_dev < 114 / CTX_SUBDIV)
- {
- pack_s8_args (entry, 4);
- entry[0].code = CTX_REL_CURVE_TO_REL_LINE_TO;
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- entry[3].code = CTX_NOP;
- }
- }
- else if (entry[3].code == CTX_REL_MOVE_TO)
- {
- float max_dev = find_max_dev (entry, 4);
- if (max_dev < 114 / CTX_SUBDIV)
- {
- pack_s8_args (entry, 4);
- entry[0].code = CTX_REL_CURVE_TO_REL_MOVE_TO;
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- entry[3].code = CTX_NOP;
- }
- }
+ ret = _ctx_iterator_next (iterator);
+#if CTX_BITPACK
+ if (ret && expand_bitpack)
+ switch ((CtxCode)(ret->code))
+ {
+ case CTX_REL_CURVE_TO_REL_LINE_TO:
+ ctx_iterator_expand_s8_args (iterator, ret);
+ iterator->bitpack_command[0].code = CTX_REL_CURVE_TO;
+ iterator->bitpack_command[1].code =
+ iterator->bitpack_command[2].code = CTX_CONT;
+ iterator->bitpack_command[3].code = CTX_REL_LINE_TO;
+ // 0.0 here is a common optimization - so check for it
+ if (ret->data.s8[6]== 0 && ret->data.s8[7] == 0)
+ { iterator->bitpack_length = 3; }
else
- {
- float max_dev = find_max_dev (entry, 3);
- if (max_dev < 114 / CTX_SUBDIV)
- {
- pack_s8_args (entry, 3);
- ctx_arg_s8 (6) =
- ctx_arg_s8 (7) = 0;
- entry[0].code = CTX_REL_CURVE_TO_REL_LINE_TO;
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- }
- }
- }
+ iterator->bitpack_length = 4;
+ goto again;
+ case CTX_REL_LINE_TO_REL_CURVE_TO:
+ ctx_iterator_expand_s8_args (iterator, ret);
+ iterator->bitpack_command[0].code = CTX_REL_LINE_TO;
+ iterator->bitpack_command[1].code = CTX_REL_CURVE_TO;
+ iterator->bitpack_length = 2;
+ goto again;
+ case CTX_REL_CURVE_TO_REL_MOVE_TO:
+ ctx_iterator_expand_s8_args (iterator, ret);
+ iterator->bitpack_command[0].code = CTX_REL_CURVE_TO;
+ iterator->bitpack_command[3].code = CTX_REL_MOVE_TO;
+ iterator->bitpack_length = 4;
+ goto again;
+ case CTX_REL_LINE_TO_X4:
+ ctx_iterator_expand_s8_args (iterator, ret);
+ iterator->bitpack_command[0].code =
+ iterator->bitpack_command[1].code =
+ iterator->bitpack_command[2].code =
+ iterator->bitpack_command[3].code = CTX_REL_LINE_TO;
+ iterator->bitpack_length = 4;
+ goto again;
+ case CTX_REL_QUAD_TO_S16:
+ ctx_iterator_expand_s16_args (iterator, ret);
+ iterator->bitpack_command[0].code = CTX_REL_QUAD_TO;
+ iterator->bitpack_length = 1;
+ goto again;
+ case CTX_REL_QUAD_TO_REL_QUAD_TO:
+ ctx_iterator_expand_s8_args (iterator, ret);
+ iterator->bitpack_command[0].code =
+ iterator->bitpack_command[2].code = CTX_REL_QUAD_TO;
+ iterator->bitpack_length = 3;
+ goto again;
+ case CTX_REL_LINE_TO_X2:
+ ctx_iterator_expand_s16_args (iterator, ret);
+ iterator->bitpack_command[0].code =
+ iterator->bitpack_command[1].code = CTX_REL_LINE_TO;
+ iterator->bitpack_length = 2;
+ goto again;
+ case CTX_REL_LINE_TO_REL_MOVE_TO:
+ ctx_iterator_expand_s16_args (iterator, ret);
+ iterator->bitpack_command[0].code = CTX_REL_LINE_TO;
+ iterator->bitpack_command[1].code = CTX_REL_MOVE_TO;
+ iterator->bitpack_length = 2;
+ goto again;
+ case CTX_MOVE_TO_REL_LINE_TO:
+ ctx_iterator_expand_s16_args (iterator, ret);
+ iterator->bitpack_command[0].code = CTX_MOVE_TO;
+ iterator->bitpack_command[1].code = CTX_REL_MOVE_TO;
+ iterator->bitpack_length = 2;
+ goto again;
+ case CTX_FILL_MOVE_TO:
+ iterator->bitpack_command[1] = *ret;
+ iterator->bitpack_command[0].code = CTX_FILL;
+ iterator->bitpack_command[1].code = CTX_MOVE_TO;
+ iterator->bitpack_pos = 0;
+ iterator->bitpack_length = 2;
+ goto again;
+ case CTX_LINEAR_GRADIENT:
+ case CTX_QUAD_TO:
+ case CTX_REL_QUAD_TO:
+ case CTX_TEXTURE:
+ case CTX_RECTANGLE:
+ case CTX_VIEW_BOX:
+ case CTX_ARC:
+ case CTX_ARC_TO:
+ case CTX_REL_ARC_TO:
+ case CTX_COLOR:
+ case CTX_SHADOW_COLOR:
+ case CTX_RADIAL_GRADIENT:
+ case CTX_CURVE_TO:
+ case CTX_REL_CURVE_TO:
+ case CTX_APPLY_TRANSFORM:
+ case CTX_ROUND_RECTANGLE:
+ case CTX_TEXT:
+ case CTX_STROKE_TEXT:
+ case CTX_FONT:
+ case CTX_LINE_DASH:
+ case CTX_FILL:
+ case CTX_NOP:
+ case CTX_MOVE_TO:
+ case CTX_LINE_TO:
+ case CTX_REL_MOVE_TO:
+ case CTX_REL_LINE_TO:
+ case CTX_VER_LINE_TO:
+ case CTX_REL_VER_LINE_TO:
+ case CTX_HOR_LINE_TO:
+ case CTX_REL_HOR_LINE_TO:
+ case CTX_ROTATE:
+ case CTX_FLUSH:
+ case CTX_TEXT_ALIGN:
+ case CTX_TEXT_BASELINE:
+ case CTX_TEXT_DIRECTION:
+ case CTX_MITER_LIMIT:
+ case CTX_GLOBAL_ALPHA:
+ case CTX_COMPOSITING_MODE:
+ case CTX_BLEND_MODE:
+ case CTX_SHADOW_BLUR:
+ case CTX_SHADOW_OFFSET_X:
+ case CTX_SHADOW_OFFSET_Y:
+ case CTX_RESET:
+ case CTX_EXIT:
+ case CTX_BEGIN_PATH:
+ case CTX_CLOSE_PATH:
+ case CTX_SAVE:
+ case CTX_CLIP:
+ case CTX_PRESERVE:
+ case CTX_DEFINE_GLYPH:
+ case CTX_IDENTITY:
+ case CTX_FONT_SIZE:
+ case CTX_START_GROUP:
+ case CTX_END_GROUP:
+ case CTX_RESTORE:
+ case CTX_LINE_WIDTH:
+ case CTX_LINE_DASH_OFFSET:
+ case CTX_STROKE:
+ case CTX_KERNING_PAIR:
+ case CTX_SCALE:
+ case CTX_GLYPH:
+ case CTX_SET_PIXEL:
+ case CTX_FILL_RULE:
+ case CTX_LINE_CAP:
+ case CTX_LINE_JOIN:
+ case CTX_NEW_PAGE:
+ case CTX_SET_KEY:
+ case CTX_TRANSLATE:
+ case CTX_DEFINE_TEXTURE:
+ case CTX_GRADIENT_STOP:
+ case CTX_DATA: // XXX : would be better if we hide the DATAs
+ case CTX_CONT: // shouldnt happen
+ default:
+ iterator->bitpack_length = 0;
+ return (CtxCommand *) ret;
+#if 0
+ default: // XXX remove - and get better warnings
+ iterator->bitpack_command[0] = ret[0];
+ iterator->bitpack_command[1] = ret[1];
+ iterator->bitpack_command[2] = ret[2];
+ iterator->bitpack_command[3] = ret[3];
+ iterator->bitpack_command[4] = ret[4];
+ iterator->bitpack_pos = 0;
+ iterator->bitpack_length = 1;
+ goto again;
#endif
-#if 1
- else if (entry[0].code == CTX_REL_QUAD_TO)
- {
- if (entry[2].code == CTX_REL_QUAD_TO)
- {
- float max_dev = find_max_dev (entry, 4);
- if (max_dev < 114 / CTX_SUBDIV)
- {
- pack_s8_args (entry, 4);
- entry[0].code = CTX_REL_QUAD_TO_REL_QUAD_TO;
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- entry[3].code = CTX_NOP;
- }
- }
- else
- {
- float max_dev = find_max_dev (entry, 2);
- if (max_dev < 3100 / CTX_SUBDIV)
- {
- pack_s16_args (entry, 2);
- entry[0].code = CTX_REL_QUAD_TO_S16;
- entry[1].code = CTX_NOP;
- }
- }
- }
-#endif
-#if 1
- else if (entry[0].code == CTX_FILL &&
- entry[1].code == CTX_MOVE_TO)
- {
- entry[0] = entry[1];
- entry[0].code = CTX_FILL_MOVE_TO;
- entry[1].code = CTX_NOP;
- }
-#endif
-#if 1
- else if (entry[0].code == CTX_MOVE_TO &&
- entry[1].code == CTX_MOVE_TO &&
- entry[2].code == CTX_MOVE_TO)
- {
- entry[0] = entry[2];
- entry[0].code = CTX_MOVE_TO;
- entry[1].code = CTX_NOP;
- entry[2].code = CTX_NOP;
- }
-#endif
-#if 1
- else if ( (entry[0].code == CTX_MOVE_TO &&
- entry[1].code == CTX_MOVE_TO) ||
- (entry[0].code == CTX_REL_MOVE_TO &&
- entry[1].code == CTX_MOVE_TO) )
- {
- entry[0] = entry[1];
- entry[0].code = CTX_MOVE_TO;
- entry[1].code = CTX_NOP;
- }
-#endif
- i += (ctx_conts_for_entry (entry) + 1);
- }
- int source = drawlist->bitpack_pos;
- int target = drawlist->bitpack_pos;
- int removed = 0;
- /* remove nops that have been inserted as part of shortenings
- */
- while (source < drawlist->count)
- {
- CtxEntry *sentry = &drawlist->entries[source];
- CtxEntry *tentry = &drawlist->entries[target];
- while (sentry->code == CTX_NOP && source < drawlist->count)
- {
- source++;
- sentry = &drawlist->entries[source];
- removed++;
- }
- if (sentry != tentry)
- { *tentry = *sentry; }
- source ++;
- target ++;
- }
- drawlist->count -= removed;
- drawlist->bitpack_pos = drawlist->count;
+ }
#endif
+ return (CtxCommand *) ret;
}
-#endif
-
+static void ctx_drawlist_compact (CtxDrawlist *drawlist);
static void
-ctx_drawlist_compact (CtxDrawlist *drawlist)
+ctx_drawlist_resize (CtxDrawlist *drawlist, int desired_size)
{
-#if CTX_BITPACK_PACKER
- int last_history;
- last_history = ctx_last_history (drawlist);
+#if CTX_DRAWLIST_STATIC
+ if (drawlist->flags & CTX_DRAWLIST_EDGE_LIST)
+ {
+ static CtxEntry sbuf[CTX_MAX_EDGE_LIST_SIZE];
+ drawlist->entries = &sbuf[0];
+ drawlist->size = CTX_MAX_EDGE_LIST_SIZE;
+ }
+ else if (drawlist->flags & CTX_DRAWLIST_CURRENT_PATH)
+ {
+ static CtxEntry sbuf[CTX_MAX_EDGE_LIST_SIZE];
+ drawlist->entries = &sbuf[0];
+ drawlist->size = CTX_MAX_EDGE_LIST_SIZE;
+ }
+ else
+ {
+ static CtxEntry sbuf[CTX_MAX_JOURNAL_SIZE];
+ drawlist->entries = &sbuf[0];
+ drawlist->size = CTX_MAX_JOURNAL_SIZE;
+ ctx_drawlist_compact (drawlist);
+ }
#else
- if (drawlist) {};
-#endif
-#if CTX_BITPACK_PACKER
- ctx_drawlist_bitpack (drawlist, last_history);
+ int new_size = desired_size;
+ int min_size = CTX_MIN_JOURNAL_SIZE;
+ int max_size = CTX_MAX_JOURNAL_SIZE;
+ if ((drawlist->flags & CTX_DRAWLIST_EDGE_LIST))
+ {
+ min_size = CTX_MIN_EDGE_LIST_SIZE;
+ max_size = CTX_MAX_EDGE_LIST_SIZE;
+ }
+ else if (drawlist->flags & CTX_DRAWLIST_CURRENT_PATH)
+ {
+ min_size = CTX_MIN_EDGE_LIST_SIZE;
+ max_size = CTX_MAX_EDGE_LIST_SIZE;
+ }
+ else
+ {
+ ctx_drawlist_compact (drawlist);
+ }
+
+ if (new_size < drawlist->size)
+ { return; }
+ if (drawlist->size == max_size)
+ { return; }
+ if (new_size < min_size)
+ { new_size = min_size; }
+ if (new_size < drawlist->count)
+ { new_size = drawlist->count + 4; }
+ if (new_size >= max_size)
+ { new_size = max_size; }
+ if (new_size != drawlist->size)
+ {
+ //fprintf (stderr, "growing drawlist %p %i to %d from %d\n", drawlist, drawlist->flags, new_size,
drawlist->size);
+ if (drawlist->entries)
+ {
+ //printf ("grow %p to %d from %d\n", drawlist, new_size, drawlist->size);
+ CtxEntry *ne = (CtxEntry *) malloc (sizeof (CtxEntry) * new_size);
+ memcpy (ne, drawlist->entries, drawlist->size * sizeof (CtxEntry) );
+ free (drawlist->entries);
+ drawlist->entries = ne;
+ //drawlist->entries = (CtxEntry*)malloc (drawlist->entries, sizeof (CtxEntry) * new_size);
+ }
+ else
+ {
+ //fprintf (stderr, "allocating for %p %d\n", drawlist, new_size);
+ drawlist->entries = (CtxEntry *) malloc (sizeof (CtxEntry) * new_size);
+ }
+ drawlist->size = new_size;
+ }
+ //fprintf (stderr, "drawlist %p is %d\n", drawlist, drawlist->size);
#endif
}
+static int
+ctx_drawlist_add_single (CtxDrawlist *drawlist, CtxEntry *entry)
+{
+ int max_size = CTX_MAX_JOURNAL_SIZE;
+ int ret = drawlist->count;
+ if (drawlist->flags & CTX_DRAWLIST_EDGE_LIST)
+ {
+ max_size = CTX_MAX_EDGE_LIST_SIZE;
+ }
+ else if (drawlist->flags & CTX_DRAWLIST_CURRENT_PATH)
+ {
+ max_size = CTX_MAX_EDGE_LIST_SIZE;
+ }
+ if (drawlist->flags & CTX_DRAWLIST_DOESNT_OWN_ENTRIES)
+ {
+ return ret;
+ }
+ if (ret + 1024 >= drawlist->size - 40)
+ {
+ int new_ = CTX_MAX (drawlist->size * 2, ret + 1024);
+ ctx_drawlist_resize (drawlist, new_);
+ }
-#ifndef __CTX_TRANSFORM
-#define __CTX_TRANSFORM
+ if (drawlist->count >= max_size - 20)
+ {
+ return 0;
+ }
+ drawlist->entries[drawlist->count] = *entry;
+ ret = drawlist->count;
+ drawlist->count++;
+ return ret;
+}
-static void
-_ctx_user_to_device (CtxState *state, float *x, float *y)
+int
+ctx_add_single (Ctx *ctx, void *entry)
{
- ctx_matrix_apply_transform (&state->gstate.transform, x, y);
+ return ctx_drawlist_add_single (&ctx->drawlist, (CtxEntry *) entry);
}
-static void
-_ctx_user_to_device_distance (CtxState *state, float *x, float *y)
+int
+ctx_drawlist_add_entry (CtxDrawlist *drawlist, CtxEntry *entry)
{
- const CtxMatrix *m = &state->gstate.transform;
- ctx_matrix_apply_transform (m, x, y);
- *x -= m->m[2][0];
- *y -= m->m[2][1];
+ int length = ctx_conts_for_entry (entry) + 1;
+ int ret = 0;
+ for (int i = 0; i < length; i ++)
+ {
+ ret = ctx_drawlist_add_single (drawlist, &entry[i]);
+ }
+ return ret;
}
-void ctx_user_to_device (Ctx *ctx, float *x, float *y)
+#if 0
+int
+ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry)
{
- _ctx_user_to_device (&ctx->state, x, y);
+ int length = ctx_conts_for_entry (entry) + 1;
+ int tmp_pos = ctx_drawlist_add_entry (drawlist, entry);
+ for (int i = 0; i < length; i++)
+ {
+ for (int j = pos + i + 1; j < tmp_pos; j++)
+ drawlist->entries[j] = entry[j-1];
+ drawlist->entries[pos + i] = entry[i];
+ }
+ return pos;
}
-void ctx_user_to_device_distance (Ctx *ctx, float *x, float *y)
+#endif
+int
+ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry)
{
- _ctx_user_to_device_distance (&ctx->state, x, y);
+ int length = ctx_conts_for_entry (entry) + 1;
+ int tmp_pos = ctx_drawlist_add_entry (drawlist, entry);
+#if 1
+ for (int i = 0; i < length; i++)
+ {
+ for (int j = tmp_pos; j > pos + i; j--)
+ drawlist->entries[j] = drawlist->entries[j-1];
+ drawlist->entries[pos + i] = entry[i];
+ }
+ return pos;
+#endif
+ return tmp_pos;
}
-static void
-ctx_matrix_set (CtxMatrix *matrix, float a, float b, float c, float d, float e, float f)
+int ctx_append_drawlist (Ctx *ctx, void *data, int length)
{
- matrix->m[0][0] = a;
- matrix->m[0][1] = b;
- matrix->m[1][0] = c;
- matrix->m[1][1] = d;
- matrix->m[2][0] = e;
- matrix->m[2][1] = f;
+ CtxEntry *entries = (CtxEntry *) data;
+ if (length % sizeof (CtxEntry) )
+ {
+ ctx_log("drawlist not multiple of 9\n");
+ return -1;
+ }
+ for (unsigned int i = 0; i < length / sizeof (CtxEntry); i++)
+ {
+ ctx_drawlist_add_single (&ctx->drawlist, &entries[i]);
+ }
+ return 0;
}
-void
-ctx_matrix_identity (CtxMatrix *matrix)
+int ctx_set_drawlist (Ctx *ctx, void *data, int length)
{
- matrix->m[0][0] = 1.0f;
- matrix->m[0][1] = 0.0f;
- matrix->m[1][0] = 0.0f;
- matrix->m[1][1] = 1.0f;
- matrix->m[2][0] = 0.0f;
- matrix->m[2][1] = 0.0f;
+ CtxDrawlist *drawlist = &ctx->drawlist;
+ ctx->drawlist.count = 0;
+ if (drawlist->flags & CTX_DRAWLIST_DOESNT_OWN_ENTRIES)
+ {
+ return -1;
+ }
+ if (length % 9) return -1;
+ ctx_drawlist_resize (drawlist, length/9);
+ memcpy (drawlist->entries, data, length);
+ drawlist->count = length / 9;
+ return length;
}
-void
-ctx_matrix_multiply (CtxMatrix *result,
- const CtxMatrix *t,
- const CtxMatrix *s)
+int ctx_get_drawlist_count (Ctx *ctx)
{
- CtxMatrix r;
- r.m[0][0] = t->m[0][0] * s->m[0][0] + t->m[0][1] * s->m[1][0];
- r.m[0][1] = t->m[0][0] * s->m[0][1] + t->m[0][1] * s->m[1][1];
- r.m[1][0] = t->m[1][0] * s->m[0][0] + t->m[1][1] * s->m[1][0];
- r.m[1][1] = t->m[1][0] * s->m[0][1] + t->m[1][1] * s->m[1][1];
- r.m[2][0] = t->m[2][0] * s->m[0][0] + t->m[2][1] * s->m[1][0] + s->m[2][0];
- r.m[2][1] = t->m[2][0] * s->m[0][1] + t->m[2][1] * s->m[1][1] + s->m[2][1];
- *result = r;
+ return ctx->drawlist.count;
}
-
-void
-ctx_matrix_translate (CtxMatrix *matrix, float x, float y)
+const CtxEntry *ctx_get_drawlist (Ctx *ctx)
{
- CtxMatrix transform;
- transform.m[0][0] = 1.0f;
- transform.m[0][1] = 0.0f;
- transform.m[1][0] = 0.0f;
- transform.m[1][1] = 1.0f;
- transform.m[2][0] = x;
- transform.m[2][1] = y;
- ctx_matrix_multiply (matrix, &transform, matrix);
+ return ctx->drawlist.entries;
}
-void
-ctx_matrix_scale (CtxMatrix *matrix, float x, float y)
+int
+ctx_add_data (Ctx *ctx, void *data, int length)
{
- CtxMatrix transform;
- transform.m[0][0] = x;
- transform.m[0][1] = 0.0f;
- transform.m[1][0] = 0.0f;
- transform.m[1][1] = y;
- transform.m[2][0] = 0.0f;
- transform.m[2][1] = 0.0f;
- ctx_matrix_multiply (matrix, &transform, matrix);
+ if (length % sizeof (CtxEntry) )
+ {
+ //ctx_log("err\n");
+ return -1;
+ }
+ /* some more input verification might be in order.. like
+ * verify that it is well-formed up to length?
+ *
+ * also - it would be very useful to stop processing
+ * upon flush - and do drawlist resizing.
+ */
+ return ctx_drawlist_add_entry (&ctx->drawlist, (CtxEntry *) data);
}
-void
-ctx_matrix_rotate (CtxMatrix *matrix, float angle)
+int ctx_drawlist_add_u32 (CtxDrawlist *drawlist, CtxCode code, uint32_t u32[2])
{
- CtxMatrix transform;
- float val_sin = ctx_sinf (angle);
- float val_cos = ctx_cosf (angle);
- transform.m[0][0] = val_cos;
- transform.m[0][1] = val_sin;
- transform.m[1][0] = -val_sin;
- transform.m[1][1] = val_cos;
- transform.m[2][0] = 0.0f;
- transform.m[2][1] = 0.0f;
- ctx_matrix_multiply (matrix, &transform, matrix);
+ CtxEntry entry = {code, {{0},}};
+ entry.data.u32[0] = u32[0];
+ entry.data.u32[1] = u32[1];
+ return ctx_drawlist_add_single (drawlist, &entry);
}
-#if 0
-static void
-ctx_matrix_skew_x (CtxMatrix *matrix, float angle)
+int ctx_drawlist_add_data (CtxDrawlist *drawlist, const void *data, int length)
{
- CtxMatrix transform;
- float val_tan = ctx_tanf (angle);
- transform.m[0][0] = 1.0f;
- transform.m[0][1] = 0.0f;
- transform.m[1][0] = val_tan;
- transform.m[1][1] = 1.0f;
- transform.m[2][0] = 0.0f;
- transform.m[2][1] = 0.0f;
- ctx_matrix_multiply (matrix, &transform, matrix);
+ CtxEntry entry = {CTX_DATA, {{0},}};
+ entry.data.u32[0] = 0;
+ entry.data.u32[1] = 0;
+ int ret = ctx_drawlist_add_single (drawlist, &entry);
+ if (!data) { return -1; }
+ int length_in_blocks;
+ if (length <= 0) { length = strlen ( (char *) data) + 1; }
+ length_in_blocks = length / sizeof (CtxEntry);
+ length_in_blocks += (length % sizeof (CtxEntry) ) ?1:0;
+ if (drawlist->count + length_in_blocks + 4 > drawlist->size)
+ { ctx_drawlist_resize (drawlist, drawlist->count * 1.2 + length_in_blocks + 32); }
+ if (drawlist->count >= drawlist->size)
+ { return -1; }
+ drawlist->count += length_in_blocks;
+ drawlist->entries[ret].data.u32[0] = length;
+ drawlist->entries[ret].data.u32[1] = length_in_blocks;
+ memcpy (&drawlist->entries[ret+1], data, length);
+ {
+ //int reverse = ctx_drawlist_add (drawlist, CTX_DATA_REV);
+ CtxEntry entry = {CTX_DATA_REV, {{0},}};
+ entry.data.u32[0] = length;
+ entry.data.u32[1] = length_in_blocks;
+ ctx_drawlist_add_single (drawlist, &entry);
+ /* this reverse marker exist to enable more efficient
+ front to back traversal, can be ignored in other
+ direction, is this needed after string setters as well?
+ */
+ }
+ return ret;
}
-static void
-ctx_matrix_skew_y (CtxMatrix *matrix, float angle)
+static CtxEntry
+ctx_void (CtxCode code)
{
- CtxMatrix transform;
- float val_tan = ctx_tanf (angle);
- transform.m[0][0] = 1.0f;
- transform.m[0][1] = val_tan;
- transform.m[1][0] = 0.0f;
- transform.m[1][1] = 1.0f;
- transform.m[2][0] = 0.0f;
- transform.m[2][1] = 0.0f;
- ctx_matrix_multiply (matrix, &transform, matrix);
+ CtxEntry command;
+ command.code = code;
+ command.data.u32[0] = 0;
+ command.data.u32[1] = 0;
+ return command;
}
-#endif
-
-void
-ctx_identity (Ctx *ctx)
+static CtxEntry
+ctx_f (CtxCode code, float x, float y)
{
- CTX_PROCESS_VOID (CTX_IDENTITY);
+ CtxEntry command = ctx_void (code);
+ command.data.f[0] = x;
+ command.data.f[1] = y;
+ return command;
}
-void
-ctx_apply_transform (Ctx *ctx, float a, float b, // hscale, hskew
- float c, float d, // vskew, vscale
- float e, float f) // htran, vtran
+static CtxEntry
+ctx_u32 (CtxCode code, uint32_t x, uint32_t y)
{
- CtxEntry command[3]=
- {
- ctx_f (CTX_APPLY_TRANSFORM, a, b),
- ctx_f (CTX_CONT, c, d),
- ctx_f (CTX_CONT, e, f)
- };
- ctx_process (ctx, command);
+ CtxEntry command = ctx_void (code);
+ command.data.u32[0] = x;
+ command.data.u32[1] = y;
+ return command;
}
-void
-ctx_get_transform (Ctx *ctx, float *a, float *b,
- float *c, float *d,
- float *e, float *f)
+#if 0
+static CtxEntry
+ctx_s32 (CtxCode code, int32_t x, int32_t y)
{
- if (a) { *a = ctx->state.gstate.transform.m[0][0]; }
- if (b) { *b = ctx->state.gstate.transform.m[0][1]; }
- if (c) { *c = ctx->state.gstate.transform.m[1][0]; }
- if (d) { *d = ctx->state.gstate.transform.m[1][1]; }
- if (e) { *e = ctx->state.gstate.transform.m[2][0]; }
- if (f) { *f = ctx->state.gstate.transform.m[2][1]; }
+ CtxEntry command = ctx_void (code);
+ command.data.s32[0] = x;
+ command.data.s32[1] = y;
+ return command;
}
+#endif
-void ctx_apply_matrix (Ctx *ctx, CtxMatrix *matrix)
+CtxEntry
+ctx_s16 (CtxCode code, int x0, int y0, int x1, int y1)
{
- ctx_apply_transform (ctx,
- matrix->m[0][0], matrix->m[0][1],
- matrix->m[1][0], matrix->m[1][1],
- matrix->m[2][0], matrix->m[2][1]);
+ CtxEntry command = ctx_void (code);
+ command.data.s16[0] = x0;
+ command.data.s16[1] = y0;
+ command.data.s16[2] = x1;
+ command.data.s16[3] = y1;
+ return command;
}
-void ctx_get_matrix (Ctx *ctx, CtxMatrix *matrix)
+static CtxEntry
+ctx_u8 (CtxCode code,
+ uint8_t a, uint8_t b, uint8_t c, uint8_t d,
+ uint8_t e, uint8_t f, uint8_t g, uint8_t h)
{
- *matrix = ctx->state.gstate.transform;
+ CtxEntry command = ctx_void (code);
+ command.data.u8[0] = a;
+ command.data.u8[1] = b;
+ command.data.u8[2] = c;
+ command.data.u8[3] = d;
+ command.data.u8[4] = e;
+ command.data.u8[5] = f;
+ command.data.u8[6] = g;
+ command.data.u8[7] = h;
+ return command;
}
-void ctx_set_matrix (Ctx *ctx, CtxMatrix *matrix)
-{
- ctx_identity (ctx);
- ctx_apply_matrix (ctx, matrix);
-}
+#define CTX_PROCESS_VOID(cmd) do {\
+ CtxEntry command = ctx_void (cmd); \
+ ctx_process (ctx, &command);}while(0) \
-void ctx_rotate (Ctx *ctx, float x)
-{
- if (x == 0.0f)
- return;
- CTX_PROCESS_F1 (CTX_ROTATE, x);
- if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
- { ctx->drawlist.count--; }
-}
+#define CTX_PROCESS_F(cmd, x, y) do {\
+ CtxEntry command = ctx_f(cmd, x, y);\
+ ctx_process (ctx, &command);}while(0)
-void ctx_scale (Ctx *ctx, float x, float y)
-{
- if (x == 1.0f && y == 1.0f)
- return;
- CTX_PROCESS_F (CTX_SCALE, x, y);
- if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
- { ctx->drawlist.count--; }
-}
+#define CTX_PROCESS_F1(cmd, x) do {\
+ CtxEntry command = ctx_f(cmd, x, 0);\
+ ctx_process (ctx, &command);}while(0)
-void ctx_translate (Ctx *ctx, float x, float y)
-{
- if (x == 0.0f && y == 0.0f)
- return;
- CTX_PROCESS_F (CTX_TRANSLATE, x, y);
- if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
- { ctx->drawlist.count--; }
-}
-
-void
-ctx_matrix_invert (CtxMatrix *m)
-{
- CtxMatrix t = *m;
- float invdet, det = m->m[0][0] * m->m[1][1] -
- m->m[1][0] * m->m[0][1];
- if (det > -0.0000001f && det < 0.0000001f)
- {
- m->m[0][0] = m->m[0][1] =
- m->m[1][0] = m->m[1][1] =
- m->m[2][0] = m->m[2][1] = 0.0;
- return;
- }
- invdet = 1.0f / det;
- m->m[0][0] = t.m[1][1] * invdet;
- m->m[1][0] = -t.m[1][0] * invdet;
- m->m[2][0] = (t.m[1][0] * t.m[2][1] - t.m[1][1] * t.m[2][0]) * invdet;
- m->m[0][1] = -t.m[0][1] * invdet;
- m->m[1][1] = t.m[0][0] * invdet;
- m->m[2][1] = (t.m[0][1] * t.m[2][0] - t.m[0][0] * t.m[2][1]) * invdet ;
-}
-
-void
-ctx_matrix_apply_transform (const CtxMatrix *m, float *x, float *y)
-{
- float x_in = *x;
- float y_in = *y;
- *x = ( (x_in * m->m[0][0]) + (y_in * m->m[1][0]) + m->m[2][0]);
- *y = ( (y_in * m->m[1][1]) + (x_in * m->m[0][1]) + m->m[2][1]);
-}
-
-
-#endif
-#ifndef __CTX_COLOR
-#define __CTX_COLOR
-
-int ctx_color_model_get_components (CtxColorModel model)
-{
- switch (model)
- {
- case CTX_GRAY:
- return 1;
- case CTX_GRAYA:
- case CTX_GRAYA_A:
- return 1;
- case CTX_RGB:
- case CTX_LAB:
- case CTX_LCH:
- case CTX_DRGB:
- return 3;
- case CTX_CMYK:
- case CTX_DCMYK:
- case CTX_LABA:
- case CTX_LCHA:
- case CTX_RGBA:
- case CTX_DRGBA:
- case CTX_RGBA_A:
- case CTX_RGBA_A_DEVICE:
- return 4;
- case CTX_DCMYKA:
- case CTX_CMYKA:
- case CTX_CMYKA_A:
- case CTX_DCMYKA_A:
- return 5;
- }
- return 0;
-}
+#define CTX_PROCESS_U32(cmd, x, y) do {\
+ CtxEntry command = ctx_u32(cmd, x, y);\
+ ctx_process (ctx, &command);}while(0)
-#if 0
-inline static float ctx_u8_to_float (uint8_t val_u8)
-{
- float val_f = val_u8 / 255.0;
- return val_f;
-}
-#else
-float ctx_u8_float[256];
-#endif
+#define CTX_PROCESS_U8(cmd, x) do {\
+ CtxEntry command = ctx_u8(cmd, x,0,0,0,0,0,0,0);\
+ ctx_process (ctx, &command);}while(0)
-CtxColor *ctx_color_new ()
-{
- CtxColor *color = (CtxColor*)ctx_calloc (sizeof (CtxColor), 1);
- return color;
-}
-int ctx_color_is_transparent (CtxColor *color)
+static void
+ctx_process_cmd_str_with_len (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1, int
len)
{
- return color->alpha <= 0.001f;
+ CtxEntry commands[1 + 2 + (len+1+1)/9];
+ ctx_memset (commands, 0, sizeof (commands) );
+ commands[0] = ctx_u32 (code, arg0, arg1);
+ commands[1].code = CTX_DATA;
+ commands[1].data.u32[0] = len;
+ commands[1].data.u32[1] = (len+1+1)/9 + 1;
+ memcpy( (char *) &commands[2].data.u8[0], string, len);
+ ( (char *) (&commands[2].data.u8[0]) ) [len]=0;
+ ctx_process (ctx, commands);
}
-
-void ctx_color_free (CtxColor *color)
+static void
+ctx_process_cmd_str (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1)
{
- free (color);
+ ctx_process_cmd_str_with_len (ctx, code, string, arg0, arg1, strlen (string));
}
-static void ctx_color_set_RGBA8 (CtxState *state, CtxColor *color, uint8_t r, uint8_t g, uint8_t b, uint8_t
a)
+static void
+ctx_process_cmd_str_float (Ctx *ctx, CtxCode code, const char *string, float arg0, float arg1)
{
- color->original = color->valid = CTX_VALID_RGBA_U8;
- color->rgba[0] = r;
- color->rgba[1] = g;
- color->rgba[2] = b;
- color->rgba[3] = a;
-#if CTX_ENABLE_CM
- color->space = state->gstate.device_space;
-#endif
+ uint32_t iarg0;
+ 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));
}
-#if 0
-static void ctx_color_set_RGBA8_ (CtxColor *color, const uint8_t *in)
+#if CTX_BITPACK_PACKER
+static int
+ctx_last_history (CtxDrawlist *drawlist)
{
- ctx_color_set_RGBA8 (color, in[0], in[1], in[2], in[3]);
+ int last_history = 0;
+ int i = 0;
+ while (i < drawlist->count)
+ {
+ CtxEntry *entry = &drawlist->entries[i];
+ i += (ctx_conts_for_entry (entry) + 1);
+ }
+ return last_history;
}
#endif
-static void ctx_color_set_graya (CtxState *state, CtxColor *color, float gray, float alpha)
-{
- color->original = color->valid = CTX_VALID_GRAYA;
- color->l = gray;
- color->alpha = alpha;
-}
-#if 0
-static void ctx_color_set_graya_ (CtxColor *color, const float *in)
-{
- return ctx_color_set_graya (color, in[0], in[1]);
-}
-#endif
+#if CTX_BITPACK_PACKER
-void ctx_color_set_rgba (CtxState *state, CtxColor *color, float r, float g, float b, float a)
+static float
+find_max_dev (CtxEntry *entry, int nentrys)
{
-#if CTX_ENABLE_CM
- color->original = color->valid = CTX_VALID_RGBA;
- color->red = r;
- color->green = g;
- color->blue = b;
- color->space = state->gstate.rgb_space;
-#else
- color->original = color->valid = CTX_VALID_RGBA_DEVICE;
- color->device_red = r;
- color->device_green = g;
- color->device_blue = b;
-#endif
- color->alpha = a;
+ float max_dev = 0.0;
+ for (int c = 0; c < nentrys; c++)
+ {
+ for (int d = 0; d < 2; d++)
+ {
+ if (entry[c].data.f[d] > max_dev)
+ { max_dev = entry[c].data.f[d]; }
+ if (entry[c].data.f[d] < -max_dev)
+ { max_dev = -entry[c].data.f[d]; }
+ }
+ }
+ return max_dev;
}
-static void ctx_color_set_drgba (CtxState *state, CtxColor *color, float r, float g, float b, float a)
+static void
+pack_s8_args (CtxEntry *entry, int npairs)
{
-#if CTX_ENABLE_CM
- color->original = color->valid = CTX_VALID_RGBA_DEVICE;
- color->device_red = r;
- color->device_green = g;
- color->device_blue = b;
- color->alpha = a;
- color->space = state->gstate.device_space;
-#else
- ctx_color_set_rgba (state, color, r, g, b, a);
-#endif
+ for (int c = 0; c < npairs; c++)
+ for (int d = 0; d < 2; d++)
+ { entry[0].data.s8[c*2+d]=entry[c].data.f[d] * CTX_SUBDIV; }
}
-#if 0
-static void ctx_color_set_rgba_ (CtxState *state, CtxColor *color, const float *in)
+static void
+pack_s16_args (CtxEntry *entry, int npairs)
{
- ctx_color_set_rgba (color, in[0], in[1], in[2], in[3]);
+ for (int c = 0; c < npairs; c++)
+ for (int d = 0; d < 2; d++)
+ { entry[0].data.s16[c*2+d]=entry[c].data.f[d] * CTX_SUBDIV; }
}
#endif
-/* the baseline conversions we have whether CMYK support is enabled or not,
- * providing an effort at right rendering
- */
-static void ctx_cmyk_to_rgb (float c, float m, float y, float k, float *r, float *g, float *b)
-{
- *r = (1.0f-c) * (1.0f-k);
- *g = (1.0f-m) * (1.0f-k);
- *b = (1.0f-y) * (1.0f-k);
-}
-
-// XXX needs state
-void ctx_rgb_to_cmyk (float r, float g, float b,
- float *c_out, float *m_out, float *y_out, float *k_out)
+#if CTX_BITPACK_PACKER
+static void
+ctx_drawlist_remove_tiny_curves (CtxDrawlist *drawlist, int start_pos)
{
- float c = 1.0f - r;
- float m = 1.0f - g;
- float y = 1.0f - b;
- float k = ctx_minf (c, ctx_minf (y, m) );
- if (k < 1.0f)
- {
- c = (c - k) / (1.0f - k);
- m = (m - k) / (1.0f - k);
- y = (y - k) / (1.0f - k);
- }
- else
+ CtxIterator iterator;
+ if ( (drawlist->flags & CTX_TRANSFORMATION_BITPACK) == 0)
+ { return; }
+ ctx_iterator_init (&iterator, drawlist, start_pos, CTX_ITERATOR_FLAT);
+ iterator.end_pos = drawlist->count - 5;
+ CtxCommand *command = NULL;
+ while ( (command = ctx_iterator_next (&iterator) ) )
{
- c = m = y = 0.0f;
+ CtxEntry *entry = &command->entry;
+ /* things smaller than this have probably been scaled down
+ beyond recognition, bailing for both better packing and less rasterization work
+ */
+ if (command[0].code == CTX_REL_CURVE_TO)
+ {
+ float max_dev = find_max_dev (entry, 3);
+ if (max_dev < 1.0)
+ {
+ entry[0].code = CTX_REL_LINE_TO;
+ entry[0].data.f[0] = entry[2].data.f[0];
+ entry[0].data.f[1] = entry[2].data.f[1];
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ }
+ }
}
- *c_out = c;
- *m_out = m;
- *y_out = y;
- *k_out = k;
}
+#endif
-#if CTX_ENABLE_CMYK
-static void ctx_color_set_cmyka (CtxState *state, CtxColor *color, float c, float m, float y, float k, float
a)
-{
- color->original = color->valid = CTX_VALID_CMYKA;
- color->cyan = c;
- color->magenta = m;
- color->yellow = y;
- color->key = k;
- color->alpha = a;
-#if CTX_ENABLE_CM
- color->space = state->gstate.cmyk_space;
-#endif
-}
-
-static void ctx_color_set_dcmyka (CtxState *state, CtxColor *color, float c, float m, float y, float k,
float a)
-{
- color->original = color->valid = CTX_VALID_DCMYKA;
- color->device_cyan = c;
- color->device_magenta = m;
- color->device_yellow = y;
- color->device_key = k;
- color->alpha = a;
-#if CTX_ENABLE_CM
- color->space = state->gstate.device_space;
-#endif
-}
-
-#endif
-
-#if CTX_ENABLE_CM
-
-static void ctx_rgb_user_to_device (CtxState *state, float rin, float gin, float bin,
- float *rout, float *gout, float *bout)
-{
-#if CTX_BABL
-#if 0
- fprintf (stderr, "-[%p %p\n",
- state->gstate.fish_rgbaf_user_to_device,
- state->gstate.fish_rgbaf_device_to_user);
-#endif
- if (state->gstate.fish_rgbaf_user_to_device)
- {
- float rgbaf[4]={rin,gin,bin,1.0};
- float rgbafo[4];
- babl_process (state->gstate.fish_rgbaf_user_to_device,
- rgbaf, rgbafo, 1);
-
- *rout = rgbafo[0];
- *gout = rgbafo[1];
- *bout = rgbafo[2];
- return;
- }
-#endif
- *rout = rin;
- *gout = gin;
- *bout = bin;
-}
-
-static void ctx_rgb_device_to_user (CtxState *state, float rin, float gin, float bin,
- float *rout, float *gout, float *bout)
-{
-#if CTX_BABL
-#if 0
- fprintf (stderr, "=[%p %p\n",
- state->gstate.fish_rgbaf_user_to_device,
- state->gstate.fish_rgbaf_device_to_user);
-#endif
- if (state->gstate.fish_rgbaf_device_to_user)
- {
- float rgbaf[4]={rin,gin,bin,1.0};
- float rgbafo[4];
- babl_process (state->gstate.fish_rgbaf_device_to_user,
- rgbaf, rgbafo, 1);
-
- *rout = rgbafo[0];
- *gout = rgbafo[1];
- *bout = rgbafo[2];
- return;
- }
-#endif
- *rout = rin;
- *gout = gin;
- *bout = bin;
-}
-#endif
-
-static void ctx_color_get_drgba (CtxState *state, CtxColor *color, float *out)
+#if CTX_BITPACK_PACKER
+static void
+ctx_drawlist_bitpack (CtxDrawlist *drawlist, int start_pos)
{
- if (! (color->valid & CTX_VALID_RGBA_DEVICE) )
+#if CTX_BITPACK
+ int i = 0;
+ if ( (drawlist->flags & CTX_TRANSFORMATION_BITPACK) == 0)
+ { return; }
+ ctx_drawlist_remove_tiny_curves (drawlist, drawlist->bitpack_pos);
+ i = drawlist->bitpack_pos;
+ if (start_pos > i)
+ { i = start_pos; }
+ while (i < drawlist->count - 4) /* the -4 is to avoid looking past
+ initialized data we're not ready
+ to bitpack yet*/
{
-#if CTX_ENABLE_CM
- if (color->valid & CTX_VALID_RGBA)
+ CtxEntry *entry = &drawlist->entries[i];
+ if (entry[0].code == CTX_SET_RGBA_U8 &&
+ entry[1].code == CTX_MOVE_TO &&
+ entry[2].code == CTX_REL_LINE_TO &&
+ entry[3].code == CTX_REL_LINE_TO &&
+ entry[4].code == CTX_REL_LINE_TO &&
+ entry[5].code == CTX_REL_LINE_TO &&
+ entry[6].code == CTX_FILL &&
+ ctx_fabsf (entry[2].data.f[0] - 1.0f) < 0.02f &&
+ ctx_fabsf (entry[3].data.f[1] - 1.0f) < 0.02f)
{
- ctx_rgb_user_to_device (state, color->red, color->green, color->blue,
- & (color->device_red), & (color->device_green), & (color->device_blue) );
+ entry[0].code = CTX_SET_PIXEL;
+ entry[0].data.u16[2] = entry[1].data.f[0];
+ entry[0].data.u16[3] = entry[1].data.f[1];
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ entry[3].code = CTX_NOP;
+ entry[4].code = CTX_NOP;
+ entry[5].code = CTX_NOP;
+ entry[6].code = CTX_NOP;
}
- else
-#endif
- if (color->valid & CTX_VALID_RGBA_U8)
- {
- float red = ctx_u8_to_float (color->rgba[0]);
- float green = ctx_u8_to_float (color->rgba[1]);
- float blue = ctx_u8_to_float (color->rgba[2]);
-#if CTX_ENABLE_CM
- ctx_rgb_user_to_device (state, red, green, blue,
- & (color->device_red), & (color->device_green), & (color->device_blue) );
-#else
- color->device_red = red;
- color->device_green = green;
- color->device_blue = blue;
-#endif
- color->alpha = ctx_u8_to_float (color->rgba[3]);
- }
-#if CTX_ENABLE_CMYK
- else if (color->valid & CTX_VALID_CMYKA)
- {
- ctx_cmyk_to_rgb (color->cyan, color->magenta, color->yellow, color->key,
- &color->device_red,
- &color->device_green,
- &color->device_blue);
- }
-#endif
- else if (color->valid & CTX_VALID_GRAYA)
- {
- color->device_red =
- color->device_green =
- color->device_blue = color->l;
- }
- color->valid |= CTX_VALID_RGBA_DEVICE;
- }
- out[0] = color->device_red;
- out[1] = color->device_green;
- out[2] = color->device_blue;
- out[3] = color->alpha;
-}
-
-void ctx_color_get_rgba (CtxState *state, CtxColor *color, float *out)
-{
-#if CTX_ENABLE_CM
- if (! (color->valid & CTX_VALID_RGBA) )
- {
- ctx_color_get_drgba (state, color, out);
- if (color->valid & CTX_VALID_RGBA_DEVICE)
+#if 1
+ else if (entry[0].code == CTX_REL_LINE_TO)
{
- ctx_rgb_device_to_user (state, color->device_red, color->device_green, color->device_blue,
- & (color->red), & (color->green), & (color->blue) );
+ if (entry[1].code == CTX_REL_LINE_TO &&
+ entry[2].code == CTX_REL_LINE_TO &&
+ entry[3].code == CTX_REL_LINE_TO)
+ {
+ float max_dev = find_max_dev (entry, 4);
+ if (max_dev < 114 / CTX_SUBDIV)
+ {
+ pack_s8_args (entry, 4);
+ entry[0].code = CTX_REL_LINE_TO_X4;
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ entry[3].code = CTX_NOP;
+ }
+ }
+ else if (entry[1].code == CTX_REL_CURVE_TO)
+ {
+ float max_dev = find_max_dev (entry, 4);
+ if (max_dev < 114 / CTX_SUBDIV)
+ {
+ pack_s8_args (entry, 4);
+ entry[0].code = CTX_REL_LINE_TO_REL_CURVE_TO;
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ entry[3].code = CTX_NOP;
+ }
+ }
+ else if (entry[1].code == CTX_REL_LINE_TO &&
+ entry[2].code == CTX_REL_LINE_TO &&
+ entry[3].code == CTX_REL_LINE_TO)
+ {
+ float max_dev = find_max_dev (entry, 4);
+ if (max_dev < 114 / CTX_SUBDIV)
+ {
+ pack_s8_args (entry, 4);
+ entry[0].code = CTX_REL_LINE_TO_X4;
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ entry[3].code = CTX_NOP;
+ }
+ }
+ else if (entry[1].code == CTX_REL_MOVE_TO)
+ {
+ float max_dev = find_max_dev (entry, 2);
+ if (max_dev < 31000 / CTX_SUBDIV)
+ {
+ pack_s16_args (entry, 2);
+ entry[0].code = CTX_REL_LINE_TO_REL_MOVE_TO;
+ entry[1].code = CTX_NOP;
+ }
+ }
+ else if (entry[1].code == CTX_REL_LINE_TO)
+ {
+ float max_dev = find_max_dev (entry, 2);
+ if (max_dev < 31000 / CTX_SUBDIV)
+ {
+ pack_s16_args (entry, 2);
+ entry[0].code = CTX_REL_LINE_TO_X2;
+ entry[1].code = CTX_NOP;
+ }
+ }
}
- color->valid |= CTX_VALID_RGBA;
- }
- out[0] = color->red;
- out[1] = color->green;
- out[2] = color->blue;
- out[3] = color->alpha;
-#else
- ctx_color_get_drgba (state, color, out);
#endif
-}
-
-
-float ctx_float_color_rgb_to_gray (CtxState *state, const float *rgb)
-{
- // XXX todo replace with correct according to primaries
- return CTX_CSS_RGB_TO_LUMINANCE(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);
-}
-
-void ctx_color_get_graya (CtxState *state, CtxColor *color, float *out)
-{
- if (! (color->valid & CTX_VALID_GRAYA) )
- {
- float rgba[4];
- ctx_color_get_drgba (state, color, rgba);
- color->l = ctx_float_color_rgb_to_gray (state, rgba);
- color->valid |= CTX_VALID_GRAYA;
- }
- out[0] = color->l;
- out[1] = color->alpha;
-}
-
-#if CTX_ENABLE_CMYK
-void ctx_color_get_cmyka (CtxState *state, CtxColor *color, float *out)
-{
- if (! (color->valid & CTX_VALID_CMYKA) )
- {
- if (color->valid & CTX_VALID_GRAYA)
+#if 1
+ else if (entry[0].code == CTX_REL_CURVE_TO)
{
- color->cyan = color->magenta = color->yellow = 0.0;
- color->key = color->l;
+ if (entry[3].code == CTX_REL_LINE_TO)
+ {
+ float max_dev = find_max_dev (entry, 4);
+ if (max_dev < 114 / CTX_SUBDIV)
+ {
+ pack_s8_args (entry, 4);
+ entry[0].code = CTX_REL_CURVE_TO_REL_LINE_TO;
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ entry[3].code = CTX_NOP;
+ }
+ }
+ else if (entry[3].code == CTX_REL_MOVE_TO)
+ {
+ float max_dev = find_max_dev (entry, 4);
+ if (max_dev < 114 / CTX_SUBDIV)
+ {
+ pack_s8_args (entry, 4);
+ entry[0].code = CTX_REL_CURVE_TO_REL_MOVE_TO;
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ entry[3].code = CTX_NOP;
+ }
+ }
+ else
+ {
+ float max_dev = find_max_dev (entry, 3);
+ if (max_dev < 114 / CTX_SUBDIV)
+ {
+ pack_s8_args (entry, 3);
+ ctx_arg_s8 (6) =
+ ctx_arg_s8 (7) = 0;
+ entry[0].code = CTX_REL_CURVE_TO_REL_LINE_TO;
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ }
+ }
}
- else
+#endif
+#if 1
+ else if (entry[0].code == CTX_REL_QUAD_TO)
{
- float rgba[4];
- ctx_color_get_rgba (state, color, rgba);
- ctx_rgb_to_cmyk (rgba[0], rgba[1], rgba[2],
- &color->cyan, &color->magenta, &color->yellow, &color->key);
- color->alpha = rgba[3];
+ if (entry[2].code == CTX_REL_QUAD_TO)
+ {
+ float max_dev = find_max_dev (entry, 4);
+ if (max_dev < 114 / CTX_SUBDIV)
+ {
+ pack_s8_args (entry, 4);
+ entry[0].code = CTX_REL_QUAD_TO_REL_QUAD_TO;
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ entry[3].code = CTX_NOP;
+ }
+ }
+ else
+ {
+ float max_dev = find_max_dev (entry, 2);
+ if (max_dev < 3100 / CTX_SUBDIV)
+ {
+ pack_s16_args (entry, 2);
+ entry[0].code = CTX_REL_QUAD_TO_S16;
+ entry[1].code = CTX_NOP;
+ }
+ }
}
- color->valid |= CTX_VALID_CMYKA;
+#endif
+#if 1
+ else if (entry[0].code == CTX_FILL &&
+ entry[1].code == CTX_MOVE_TO)
+ {
+ entry[0] = entry[1];
+ entry[0].code = CTX_FILL_MOVE_TO;
+ entry[1].code = CTX_NOP;
+ }
+#endif
+#if 1
+ else if (entry[0].code == CTX_MOVE_TO &&
+ entry[1].code == CTX_MOVE_TO &&
+ entry[2].code == CTX_MOVE_TO)
+ {
+ entry[0] = entry[2];
+ entry[0].code = CTX_MOVE_TO;
+ entry[1].code = CTX_NOP;
+ entry[2].code = CTX_NOP;
+ }
+#endif
+#if 1
+ else if ( (entry[0].code == CTX_MOVE_TO &&
+ entry[1].code == CTX_MOVE_TO) ||
+ (entry[0].code == CTX_REL_MOVE_TO &&
+ entry[1].code == CTX_MOVE_TO) )
+ {
+ entry[0] = entry[1];
+ entry[0].code = CTX_MOVE_TO;
+ entry[1].code = CTX_NOP;
+ }
+#endif
+ i += (ctx_conts_for_entry (entry) + 1);
}
- out[0] = color->cyan;
- out[1] = color->magenta;
- out[2] = color->yellow;
- out[3] = color->key;
- out[4] = color->alpha;
-}
-
-#if 0
-static void ctx_color_get_cmyka_u8 (CtxState *state, CtxColor *color, uint8_t *out)
-{
- if (! (color->valid & CTX_VALID_CMYKA_U8) )
+ int source = drawlist->bitpack_pos;
+ int target = drawlist->bitpack_pos;
+ int removed = 0;
+ /* remove nops that have been inserted as part of shortenings
+ */
+ while (source < drawlist->count)
{
- float cmyka[5];
- ctx_color_get_cmyka (color, cmyka);
- for (int i = 0; i < 5; i ++)
- { color->cmyka[i] = ctx_float_to_u8 (cmyka[i]); }
- color->valid |= CTX_VALID_CMYKA_U8;
+ CtxEntry *sentry = &drawlist->entries[source];
+ CtxEntry *tentry = &drawlist->entries[target];
+ while (sentry->code == CTX_NOP && source < drawlist->count)
+ {
+ source++;
+ sentry = &drawlist->entries[source];
+ removed++;
+ }
+ if (sentry != tentry)
+ { *tentry = *sentry; }
+ source ++;
+ target ++;
}
- out[0] = color->cmyka[0];
- out[1] = color->cmyka[1];
- out[2] = color->cmyka[2];
- out[3] = color->cmyka[3];
-}
+ drawlist->count -= removed;
+ drawlist->bitpack_pos = drawlist->count;
#endif
+}
+
#endif
-void
-ctx_color_get_rgba8 (CtxState *state, CtxColor *color, uint8_t *out)
+static void
+ctx_drawlist_compact (CtxDrawlist *drawlist)
{
- if (! (color->valid & CTX_VALID_RGBA_U8) )
- {
- float rgba[4];
- ctx_color_get_drgba (state, color, rgba);
- for (int i = 0; i < 4; i ++)
- { color->rgba[i] = ctx_float_to_u8 (rgba[i]); }
- color->valid |= CTX_VALID_RGBA_U8;
- }
- out[0] = color->rgba[0];
- out[1] = color->rgba[1];
- out[2] = color->rgba[2];
- out[3] = color->rgba[3];
+#if CTX_BITPACK_PACKER
+ int last_history;
+ last_history = ctx_last_history (drawlist);
+#else
+ if (drawlist) {};
+#endif
+#if CTX_BITPACK_PACKER
+ ctx_drawlist_bitpack (drawlist, last_history);
+#endif
}
-void ctx_color_get_graya_u8 (CtxState *state, CtxColor *color, uint8_t *out)
+uint8_t *ctx_define_texture_pixel_data (CtxEntry *entry)
{
- if (! (color->valid & CTX_VALID_GRAYA_U8) )
- {
- float graya[2];
- ctx_color_get_graya (state, color, graya);
- color->l_u8 = ctx_float_to_u8 (graya[0]);
- color->rgba[3] = ctx_float_to_u8 (graya[1]);
- color->valid |= CTX_VALID_GRAYA_U8;
- }
- out[0] = color->l_u8;
- out[1] = color->rgba[3];
+ return &entry[2 + 1 + 1 + ctx_conts_for_entry (&entry[2])].data.u8[0];
}
+#ifndef __CTX_TRANSFORM
+#define __CTX_TRANSFORM
-
-void
-ctx_get_rgba (Ctx *ctx, float *rgba)
+static void
+_ctx_user_to_device (CtxState *state, float *x, float *y)
{
- ctx_color_get_rgba (& (ctx->state), &ctx->state.gstate.source.color, rgba);
+ ctx_matrix_apply_transform (&state->gstate.transform, x, y);
}
-void
-ctx_get_drgba (Ctx *ctx, float *rgba)
+static void
+_ctx_user_to_device_distance (CtxState *state, float *x, float *y)
{
- ctx_color_get_drgba (& (ctx->state), &ctx->state.gstate.source.color, rgba);
+ const CtxMatrix *m = &state->gstate.transform;
+ ctx_matrix_apply_transform (m, x, y);
+ *x -= m->m[2][0];
+ *y -= m->m[2][1];
}
-int ctx_in_fill (Ctx *ctx, float x, float y)
+void ctx_user_to_device (Ctx *ctx, float *x, float *y)
{
- float x1, y1, x2, y2;
- ctx_path_extents (ctx, &x1, &y1, &x2, &y2);
-
- if (x1 <= x && x <= x2 && // XXX - just bounding box for now
- y1 <= y && y <= y2) //
- return 1;
- return 0;
+ _ctx_user_to_device (&ctx->state, x, y);
}
-
-
-#if CTX_ENABLE_CMYK
-void
-ctx_get_cmyka (Ctx *ctx, float *cmyka)
+void ctx_user_to_device_distance (Ctx *ctx, float *x, float *y)
{
- ctx_color_get_cmyka (& (ctx->state), &ctx->state.gstate.source.color, cmyka);
+ _ctx_user_to_device_distance (&ctx->state, x, y);
}
-#endif
-void
-ctx_get_graya (Ctx *ctx, float *ya)
+
+static void
+ctx_matrix_set (CtxMatrix *matrix, float a, float b, float c, float d, float e, float f)
{
- ctx_color_get_graya (& (ctx->state), &ctx->state.gstate.source.color, ya);
+ matrix->m[0][0] = a;
+ matrix->m[0][1] = b;
+ matrix->m[1][0] = c;
+ matrix->m[1][1] = d;
+ matrix->m[2][0] = e;
+ matrix->m[2][1] = f;
}
-void ctx_drgba (Ctx *ctx, float r, float g, float b, float a)
+void
+ctx_matrix_identity (CtxMatrix *matrix)
{
- CtxEntry command[3]=
- {
- ctx_f (CTX_COLOR, CTX_DRGBA, r),
- ctx_f (CTX_CONT, g, b),
- ctx_f (CTX_CONT, a, 0)
- };
- ctx_process (ctx, command);
+ matrix->m[0][0] = 1.0f;
+ matrix->m[0][1] = 0.0f;
+ matrix->m[1][0] = 0.0f;
+ matrix->m[1][1] = 1.0f;
+ matrix->m[2][0] = 0.0f;
+ matrix->m[2][1] = 0.0f;
}
-void ctx_rgba (Ctx *ctx, float r, float g, float b, float a)
+void
+ctx_matrix_multiply (CtxMatrix *result,
+ const CtxMatrix *t,
+ const CtxMatrix *s)
{
- CtxEntry command[3]=
- {
- ctx_f (CTX_COLOR, CTX_RGBA, r),
- ctx_f (CTX_CONT, g, b),
- ctx_f (CTX_CONT, a, 0)
- };
- float rgba[4];
- ctx_color_get_rgba (&ctx->state, &ctx->state.gstate.source.color, rgba);
- if (rgba[0] == r && rgba[1] == g && rgba[2] == b && rgba[3] == a)
- return;
- ctx_process (ctx, command);
+ CtxMatrix r;
+ r.m[0][0] = t->m[0][0] * s->m[0][0] + t->m[0][1] * s->m[1][0];
+ r.m[0][1] = t->m[0][0] * s->m[0][1] + t->m[0][1] * s->m[1][1];
+ r.m[1][0] = t->m[1][0] * s->m[0][0] + t->m[1][1] * s->m[1][0];
+ r.m[1][1] = t->m[1][0] * s->m[0][1] + t->m[1][1] * s->m[1][1];
+ r.m[2][0] = t->m[2][0] * s->m[0][0] + t->m[2][1] * s->m[1][0] + s->m[2][0];
+ r.m[2][1] = t->m[2][0] * s->m[0][1] + t->m[2][1] * s->m[1][1] + s->m[2][1];
+ *result = r;
}
-void ctx_rgb (Ctx *ctx, float r, float g, float b)
+
+void
+ctx_matrix_translate (CtxMatrix *matrix, float x, float y)
{
- ctx_rgba (ctx, r, g, b, 1.0f);
+ CtxMatrix transform;
+ transform.m[0][0] = 1.0f;
+ transform.m[0][1] = 0.0f;
+ transform.m[1][0] = 0.0f;
+ transform.m[1][1] = 1.0f;
+ transform.m[2][0] = x;
+ transform.m[2][1] = y;
+ ctx_matrix_multiply (matrix, &transform, matrix);
}
-void ctx_gray (Ctx *ctx, float gray)
+void
+ctx_matrix_scale (CtxMatrix *matrix, float x, float y)
{
- CtxEntry command[3]=
- {
- ctx_f (CTX_COLOR, CTX_GRAY, gray),
- ctx_f (CTX_CONT, 1.0f, 0.0f),
- ctx_f (CTX_CONT, 0.0f, 0.0f)
- };
- ctx_process (ctx, command);
+ CtxMatrix transform;
+ transform.m[0][0] = x;
+ transform.m[0][1] = 0.0f;
+ transform.m[1][0] = 0.0f;
+ transform.m[1][1] = y;
+ transform.m[2][0] = 0.0f;
+ transform.m[2][1] = 0.0f;
+ ctx_matrix_multiply (matrix, &transform, matrix);
}
-#if CTX_ENABLE_CMYK
-void ctx_cmyk (Ctx *ctx, float c, float m, float y, float k)
+void
+ctx_matrix_rotate (CtxMatrix *matrix, float angle)
{
- CtxEntry command[3]=
- {
- ctx_f (CTX_COLOR, CTX_CMYKA, c),
- ctx_f (CTX_CONT, m, y),
- ctx_f (CTX_CONT, k, 1.0f)
- };
- ctx_process (ctx, command);
+ CtxMatrix transform;
+ float val_sin = ctx_sinf (angle);
+ float val_cos = ctx_cosf (angle);
+ transform.m[0][0] = val_cos;
+ transform.m[0][1] = val_sin;
+ transform.m[1][0] = -val_sin;
+ transform.m[1][1] = val_cos;
+ transform.m[2][0] = 0.0f;
+ transform.m[2][1] = 0.0f;
+ ctx_matrix_multiply (matrix, &transform, matrix);
}
-void ctx_cmyka (Ctx *ctx, float c, float m, float y, float k, float a)
+#if 0
+static void
+ctx_matrix_skew_x (CtxMatrix *matrix, float angle)
{
- CtxEntry command[3]=
- {
- ctx_f (CTX_COLOR, CTX_CMYKA, c),
- ctx_f (CTX_CONT, m, y),
- ctx_f (CTX_CONT, k, a)
- };
- ctx_process (ctx, command);
+ CtxMatrix transform;
+ float val_tan = ctx_tanf (angle);
+ transform.m[0][0] = 1.0f;
+ transform.m[0][1] = 0.0f;
+ transform.m[1][0] = val_tan;
+ transform.m[1][1] = 1.0f;
+ transform.m[2][0] = 0.0f;
+ transform.m[2][1] = 0.0f;
+ ctx_matrix_multiply (matrix, &transform, matrix);
}
-void ctx_dcmyk (Ctx *ctx, float c, float m, float y, float k)
+static void
+ctx_matrix_skew_y (CtxMatrix *matrix, float angle)
{
- CtxEntry command[3]=
- {
- ctx_f (CTX_COLOR, CTX_DCMYKA, c),
- ctx_f (CTX_CONT, m, y),
- ctx_f (CTX_CONT, k, 1.0f)
- };
- ctx_process (ctx, command);
+ CtxMatrix transform;
+ float val_tan = ctx_tanf (angle);
+ transform.m[0][0] = 1.0f;
+ transform.m[0][1] = val_tan;
+ transform.m[1][0] = 0.0f;
+ transform.m[1][1] = 1.0f;
+ transform.m[2][0] = 0.0f;
+ transform.m[2][1] = 0.0f;
+ ctx_matrix_multiply (matrix, &transform, matrix);
}
+#endif
-void ctx_dcmyka (Ctx *ctx, float c, float m, float y, float k, float a)
+
+void
+ctx_identity (Ctx *ctx)
+{
+ CTX_PROCESS_VOID (CTX_IDENTITY);
+}
+
+void
+ctx_apply_transform (Ctx *ctx, float a, float b, // hscale, hskew
+ float c, float d, // vskew, vscale
+ float e, float f) // htran, vtran
{
CtxEntry command[3]=
{
- ctx_f (CTX_COLOR, CTX_DCMYKA, c),
- ctx_f (CTX_CONT, m, y),
- ctx_f (CTX_CONT, k, a)
+ ctx_f (CTX_APPLY_TRANSFORM, a, b),
+ ctx_f (CTX_CONT, c, d),
+ ctx_f (CTX_CONT, e, f)
};
ctx_process (ctx, command);
}
-#endif
-
-/* XXX: missing CSS1:
- *
- * EM { color: rgb(110%, 0%, 0%) } // clipped to 100%
- *
- *
- * :first-letter
- * :first-list
- * :link :visited :active
- *
- */
+void
+ctx_get_transform (Ctx *ctx, float *a, float *b,
+ float *c, float *d,
+ float *e, float *f)
+{
+ if (a) { *a = ctx->state.gstate.transform.m[0][0]; }
+ if (b) { *b = ctx->state.gstate.transform.m[0][1]; }
+ if (c) { *c = ctx->state.gstate.transform.m[1][0]; }
+ if (d) { *d = ctx->state.gstate.transform.m[1][1]; }
+ if (e) { *e = ctx->state.gstate.transform.m[2][0]; }
+ if (f) { *f = ctx->state.gstate.transform.m[2][1]; }
+}
-typedef struct ColorDef {
- uint32_t name;
- float r;
- float g;
- float b;
- float a;
-} ColorDef;
+void ctx_apply_matrix (Ctx *ctx, CtxMatrix *matrix)
+{
+ ctx_apply_transform (ctx,
+ matrix->m[0][0], matrix->m[0][1],
+ matrix->m[1][0], matrix->m[1][1],
+ matrix->m[2][0], matrix->m[2][1]);
+}
-#define CTX_silver CTX_STRH('s','i','l','v','e','r',0,0,0,0,0,0,0,0)
-#define CTX_fuchsia CTX_STRH('f','u','c','h','s','i','a',0,0,0,0,0,0,0)
-#define CTX_gray CTX_STRH('g','r','a','y',0,0,0,0,0,0,0,0,0,0)
-#define CTX_yellow CTX_STRH('y','e','l','l','o','w',0,0,0,0,0,0,0,0)
-#define CTX_white CTX_STRH('w','h','i','t','e',0,0,0,0,0,0,0,0,0)
-#define CTX_maroon CTX_STRH('m','a','r','o','o','n',0,0,0,0,0,0,0,0)
-#define CTX_magenta CTX_STRH('m','a','g','e','n','t','a',0,0,0,0,0,0,0)
-#define CTX_blue CTX_STRH('b','l','u','e',0,0,0,0,0,0,0,0,0,0)
-#define CTX_green CTX_STRH('g','r','e','e','n',0,0,0,0,0,0,0,0,0)
-#define CTX_red CTX_STRH('r','e','d',0,0,0,0,0,0,0,0,0,0,0)
-#define CTX_purple CTX_STRH('p','u','r','p','l','e',0,0,0,0,0,0,0,0)
-#define CTX_olive CTX_STRH('o','l','i','v','e',0,0,0,0,0,0,0,0,0)
-#define CTX_teal CTX_STRH('t','e','a','l',0,0,0,0,0,0,0,0,0,0)
-#define CTX_black CTX_STRH('b','l','a','c','k',0,0,0,0,0,0,0,0,0)
-#define CTX_cyan CTX_STRH('c','y','a','n',0,0,0,0,0,0,0,0,0,0)
-#define CTX_navy CTX_STRH('n','a','v','y',0,0,0,0,0,0,0,0,0,0)
-#define CTX_lime CTX_STRH('l','i','m','e',0,0,0,0,0,0,0,0,0,0)
-#define CTX_aqua CTX_STRH('a','q','u','a',0,0,0,0,0,0,0,0,0,0)
-#define CTX_transparent CTX_STRH('t','r','a','n','s','p','a','r','e','n','t',0,0,0)
+void ctx_get_matrix (Ctx *ctx, CtxMatrix *matrix)
+{
+ *matrix = ctx->state.gstate.transform;
+}
-static ColorDef colors[]={
- {CTX_black, 0, 0, 0, 1},
- {CTX_red, 1, 0, 0, 1},
- {CTX_green, 0, 1, 0, 1},
- {CTX_yellow, 1, 1, 0, 1},
- {CTX_blue, 0, 0, 1, 1},
- {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_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_aqua, 0, 1, 1, 1},
- {CTX_transparent, 0, 0, 0, 0},
- {CTX_none, 0, 0, 0, 0},
-};
+void ctx_set_matrix (Ctx *ctx, CtxMatrix *matrix)
+{
+ ctx_identity (ctx);
+ ctx_apply_matrix (ctx, matrix);
+}
-static int xdigit_value(const char xdigit)
+void ctx_rotate (Ctx *ctx, float x)
{
- if (xdigit >= '0' && xdigit <= '9')
- return xdigit - '0';
- switch (xdigit)
- {
- case 'A':case 'a': return 10;
- case 'B':case 'b': return 11;
- case 'C':case 'c': return 12;
- case 'D':case 'd': return 13;
- case 'E':case 'e': return 14;
- case 'F':case 'f': return 15;
- }
- return 0;
+ if (x == 0.0f)
+ return;
+ CTX_PROCESS_F1 (CTX_ROTATE, x);
+ if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
+ { ctx->drawlist.count--; }
}
-static int
-ctx_color_parse_rgb (CtxState *ctxstate, CtxColor *color, const char *color_string)
+void ctx_scale (Ctx *ctx, float x, float y)
{
- float dcolor[4] = {0,0,0,1};
- while (*color_string && *color_string != '(')
- color_string++;
- if (*color_string) color_string++;
+ if (x == 1.0f && y == 1.0f)
+ return;
+ CTX_PROCESS_F (CTX_SCALE, x, y);
+ if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
+ { ctx->drawlist.count--; }
+}
- {
- int n_floats = 0;
- char *p = (char*)color_string;
- char *prev = (char*)NULL;
- for (; p && n_floats < 4 && p != prev && *p; )
- {
- float val;
- prev = p;
- val = _ctx_parse_float (p, &p);
- if (p != prev)
- {
- if (n_floats < 3)
- dcolor[n_floats++] = val/255.0;
- else
- dcolor[n_floats++] = val;
-
- while (*p == ' ' || *p == ',')
- {
- p++;
- prev++;
- }
- }
- }
- }
- ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
- return 0;
-}
-
-static int ctx_isxdigit (uint8_t ch)
+void ctx_translate (Ctx *ctx, float x, float y)
{
- if (ch >= '0' && ch <= '9') return 1;
- if (ch >= 'a' && ch <= 'f') return 1;
- if (ch >= 'A' && ch <= 'F') return 1;
- return 0;
+ if (x == 0.0f && y == 0.0f)
+ return;
+ CTX_PROCESS_F (CTX_TRANSLATE, x, y);
+ if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
+ { ctx->drawlist.count--; }
}
-static int
-mrg_color_parse_hex (CtxState *ctxstate, CtxColor *color, const char *color_string)
+void
+ctx_matrix_invert (CtxMatrix *m)
{
- float dcolor[4]={0,0,0,1};
- int string_length = strlen (color_string);
- int i;
- dcolor[3] = 1.0;
-
- if (string_length == 7 || /* #rrggbb */
- string_length == 9) /* #rrggbbaa */
- {
- int num_iterations = (string_length - 1) / 2;
-
- for (i = 0; i < num_iterations; ++i)
- {
- if (ctx_isxdigit (color_string[2 * i + 1]) &&
- ctx_isxdigit (color_string[2 * i + 2]))
- {
- dcolor[i] = (xdigit_value (color_string[2 * i + 1]) << 4 |
- xdigit_value (color_string[2 * i + 2])) / 255.f;
- }
- else
- {
- return 0;
- }
- }
- /* Successful #rrggbb(aa) parsing! */
- ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
- return 1;
- }
- else if (string_length == 4 || /* #rgb */
- string_length == 5) /* #rgba */
+ CtxMatrix t = *m;
+ float invdet, det = m->m[0][0] * m->m[1][1] -
+ m->m[1][0] * m->m[0][1];
+ if (det > -0.0000001f && det < 0.0000001f)
{
- int num_iterations = string_length - 1;
- for (i = 0; i < num_iterations; ++i)
- {
- if (ctx_isxdigit (color_string[i + 1]))
- {
- dcolor[i] = (xdigit_value (color_string[i + 1]) << 4 |
- xdigit_value (color_string[i + 1])) / 255.f;
- }
- else
- {
- return 0;
- }
- }
- ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
- /* Successful #rgb(a) parsing! */
- return 0;
+ m->m[0][0] = m->m[0][1] =
+ m->m[1][0] = m->m[1][1] =
+ m->m[2][0] = m->m[2][1] = 0.0;
+ return;
}
- /* String was of unsupported length. */
- return 1;
+ invdet = 1.0f / det;
+ m->m[0][0] = t.m[1][1] * invdet;
+ m->m[1][0] = -t.m[1][0] * invdet;
+ m->m[2][0] = (t.m[1][0] * t.m[2][1] - t.m[1][1] * t.m[2][0]) * invdet;
+ m->m[0][1] = -t.m[0][1] * invdet;
+ m->m[1][1] = t.m[0][0] * invdet;
+ m->m[2][1] = (t.m[0][1] * t.m[2][0] - t.m[0][0] * t.m[2][1]) * invdet ;
}
-#define CTX_currentColor CTX_STRH('c','u','r','r','e','n','t','C','o','l','o','r',0,0)
-
-int ctx_color_set_from_string (Ctx *ctx, CtxColor *color, const char *string)
+void
+ctx_matrix_apply_transform (const CtxMatrix *m, float *x, float *y)
{
- int i;
- uint32_t hash = ctx_strhash (string, 0);
-// ctx_color_set_rgba (&(ctx->state), color, 0.4,0.1,0.9,1.0);
-// return 0;
- //rgba[0], rgba[1], rgba[2], rgba[3]);
+ float x_in = *x;
+ float y_in = *y;
+ *x = ( (x_in * m->m[0][0]) + (y_in * m->m[1][0]) + m->m[2][0]);
+ *y = ( (y_in * m->m[1][1]) + (x_in * m->m[0][1]) + m->m[2][1]);
+}
- if (hash == CTX_currentColor)
- {
- float rgba[4];
- CtxColor ccolor;
- ctx_get_color (ctx, CTX_color, &ccolor);
- ctx_color_get_rgba (&(ctx->state), &ccolor, rgba);
- ctx_color_set_rgba (&(ctx->state), color, rgba[0], rgba[1], rgba[2], rgba[3]);
- return 0;
- }
- for (i = (sizeof(colors)/sizeof(colors[0]))-1; i>=0; i--)
- {
- if (hash == colors[i].name)
+#endif
+#ifndef __CTX_COLOR
+#define __CTX_COLOR
+
+int ctx_color_model_get_components (CtxColorModel model)
+{
+ switch (model)
{
- ctx_color_set_rgba (&(ctx->state), color,
- colors[i].r, colors[i].g, colors[i].b, colors[i].a);
- return 0;
+ case CTX_GRAY:
+ return 1;
+ case CTX_GRAYA:
+ case CTX_GRAYA_A:
+ return 1;
+ case CTX_RGB:
+ case CTX_LAB:
+ case CTX_LCH:
+ case CTX_DRGB:
+ return 3;
+ case CTX_CMYK:
+ case CTX_DCMYK:
+ case CTX_LABA:
+ case CTX_LCHA:
+ case CTX_RGBA:
+ case CTX_DRGBA:
+ case CTX_RGBA_A:
+ case CTX_RGBA_A_DEVICE:
+ return 4;
+ case CTX_DCMYKA:
+ case CTX_CMYKA:
+ case CTX_CMYKA_A:
+ case CTX_DCMYKA_A:
+ return 5;
}
- }
-
- if (string[0] == '#')
- mrg_color_parse_hex (&(ctx->state), color, string);
- else if (string[0] == 'r' &&
- string[1] == 'g' &&
- string[2] == 'b'
- )
- ctx_color_parse_rgb (&(ctx->state), color, string);
-
return 0;
}
-int ctx_color (Ctx *ctx, const char *string)
+#if 0
+inline static float ctx_u8_to_float (uint8_t val_u8)
{
- CtxColor color = {0,};
- ctx_color_set_from_string (ctx, &color, string);
- float rgba[4];
- ctx_color_get_rgba (&(ctx->state), &color, rgba);
- ctx_rgba (ctx, rgba[0],rgba[1],rgba[2],rgba[3]);
- return 0;
+ float val_f = val_u8 / 255.0;
+ return val_f;
}
-
-void
-ctx_rgba8 (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
-{
-#if 0
- CtxEntry command = ctx_u8 (CTX_SET_RGBA_U8, r, g, b, a, 0, 0, 0, 0);
-
- uint8_t rgba[4];
- ctx_color_get_rgba8 (&ctx->state, &ctx->state.gstate.source.color, rgba);
- if (rgba[0] == r && rgba[1] == g && rgba[2] == b && rgba[3] == a)
- return;
-
- ctx_process (ctx, &command);
#else
- ctx_rgba (ctx, r/255.0f, g/255.0f, b/255.0f, a/255.0f);
+float ctx_u8_float[256];
#endif
-}
-#endif
+CtxColor *ctx_color_new ()
+{
+ CtxColor *color = (CtxColor*)ctx_calloc (sizeof (CtxColor), 1);
+ return color;
+}
-#if CTX_BABL
-void ctx_rasterizer_colorspace_babl (CtxState *state,
- CtxColorSpace space_slot,
- const Babl *space)
+int ctx_color_is_transparent (CtxColor *color)
{
- switch (space_slot)
- {
- case CTX_COLOR_SPACE_DEVICE_RGB:
- state->gstate.device_space = space;
- break;
- case CTX_COLOR_SPACE_DEVICE_CMYK:
- state->gstate.device_space = space;
- break;
- case CTX_COLOR_SPACE_USER_RGB:
- state->gstate.rgb_space = space;
- break;
- case CTX_COLOR_SPACE_USER_CMYK:
- state->gstate.cmyk_space = space;
- break;
- }
+ return color->alpha <= 0.001f;
+}
- if (!state->gstate.device_space)
- state->gstate.device_space = babl_space ("sRGB");
- if (!state->gstate.rgb_space)
- state->gstate.rgb_space = babl_space ("sRGB");
+void ctx_color_free (CtxColor *color)
+{
+ free (color);
+}
- //fprintf (stderr, "%s\n", babl_get_name (state->gstate.device_space));
+static void ctx_color_set_RGBA8 (CtxState *state, CtxColor *color, uint8_t r, uint8_t g, uint8_t b, uint8_t
a)
+{
+ color->original = color->valid = CTX_VALID_RGBA_U8;
+ color->rgba[0] = r;
+ color->rgba[1] = g;
+ color->rgba[2] = b;
+ color->rgba[3] = a;
+#if CTX_ENABLE_CM
+ color->space = state->gstate.device_space;
+#endif
+}
- state->gstate.fish_rgbaf_device_to_user = babl_fish (
- babl_format_with_space ("R'G'B'A float", state->gstate.device_space),
- babl_format_with_space ("R'G'B'A float", state->gstate.rgb_space));
- state->gstate.fish_rgbaf_user_to_device = babl_fish (
- babl_format_with_space ("R'G'B'A float", state->gstate.rgb_space),
- babl_format_with_space ("R'G'B'A float", state->gstate.device_space));
+#if 0
+static void ctx_color_set_RGBA8_ (CtxColor *color, const uint8_t *in)
+{
+ ctx_color_set_RGBA8 (color, in[0], in[1], in[2], in[3]);
}
#endif
-void ctx_rasterizer_colorspace_icc (CtxState *state,
- CtxColorSpace space_slot,
- char *icc_data,
- int icc_length)
+static void ctx_color_set_graya (CtxState *state, CtxColor *color, float gray, float alpha)
{
-#if CTX_BABL
- const char *error = NULL;
- const Babl *space = NULL;
- if (icc_data == NULL) space = babl_space ("sRGB");
- if (!space && !strcmp (icc_data, "sRGB")) space = babl_space ("sRGB");
- if (!space && !strcmp (icc_data, "ACEScg")) space = babl_space ("ACEScg");
- if (!space && !strcmp (icc_data, "Adobish")) space = babl_space ("Adobish");
- if (!space && !strcmp (icc_data, "Apple")) space = babl_space ("Apple");
- if (!space && !strcmp (icc_data, "Rec2020")) space = babl_space ("Rec2020");
- if (!space && !strcmp (icc_data, "ACES2065-1")) space = babl_space ("ACES2065-1");
-
- if (!space)
- {
- space = babl_space_from_icc (icc_data, icc_length, BABL_ICC_INTENT_RELATIVE_COLORIMETRIC, &error);
- }
- if (space)
- {
- ctx_rasterizer_colorspace_babl (state, space_slot, space);
- }
-#endif
+ color->original = color->valid = CTX_VALID_GRAYA;
+ color->l = gray;
+ color->alpha = alpha;
}
-
-void ctx_colorspace (Ctx *ctx,
- CtxColorSpace space_slot,
- unsigned char *data,
- int data_length)
+#if 0
+static void ctx_color_set_graya_ (CtxColor *color, const float *in)
{
- if (data)
- {
- ctx_process_cmd_str_with_len (ctx, CTX_COLOR_SPACE, (char*)data, space_slot, 0, data_length);
- }
- else
- {
- ctx_process_cmd_str_with_len (ctx, CTX_COLOR_SPACE, "sRGB", space_slot, 0, 4);
- }
+ return ctx_color_set_graya (color, in[0], in[1]);
}
+#endif
-// deviceRGB .. settable when creating an RGB image surface..
-// queryable when running in terminal - is it really needed?
-// though it is also settable..
-//
-// userRGB - settable at any time, stored in save|restore
-
-float ctx_state_get (CtxState *state, uint32_t hash)
+void ctx_color_set_rgba (CtxState *state, CtxColor *color, float r, float g, float b, float a)
{
- for (int i = state->gstate.keydb_pos-1; i>=0; i--)
- {
- if (state->keydb[i].key == hash)
- { return state->keydb[i].value; }
- }
- return -0.0;
+#if CTX_ENABLE_CM
+ color->original = color->valid = CTX_VALID_RGBA;
+ color->red = r;
+ color->green = g;
+ color->blue = b;
+ color->space = state->gstate.rgb_space;
+#else
+ color->original = color->valid = CTX_VALID_RGBA_DEVICE;
+ color->device_red = r;
+ color->device_green = g;
+ color->device_blue = b;
+#endif
+ color->alpha = a;
}
-void ctx_state_set (CtxState *state, uint32_t key, float value)
+static void ctx_color_set_drgba (CtxState *state, CtxColor *color, float r, float g, float b, float a)
{
- if (key != CTX_new_state)
- {
- if (ctx_state_get (state, key) == value)
- { return; }
- for (int i = state->gstate.keydb_pos-1;
- state->keydb[i].key != CTX_new_state && i >=0;
- i--)
- {
- if (state->keydb[i].key == key)
- {
- state->keydb[i].value = value;
- return;
- }
- }
- }
- if (state->gstate.keydb_pos >= CTX_MAX_KEYDB)
- { return; }
- state->keydb[state->gstate.keydb_pos].key = key;
- state->keydb[state->gstate.keydb_pos].value = value;
- state->gstate.keydb_pos++;
+#if CTX_ENABLE_CM
+ color->original = color->valid = CTX_VALID_RGBA_DEVICE;
+ color->device_red = r;
+ color->device_green = g;
+ color->device_blue = b;
+ color->alpha = a;
+ color->space = state->gstate.device_space;
+#else
+ ctx_color_set_rgba (state, color, r, g, b, a);
+#endif
}
-
-#define CTX_KEYDB_STRING_START (-90000.0)
-#define CTX_KEYDB_STRING_END (CTX_KEYDB_STRING_START + CTX_STRINGPOOL_SIZE)
-
-static int ctx_float_is_string (float val)
+#if 0
+static void ctx_color_set_rgba_ (CtxState *state, CtxColor *color, const float *in)
{
- return val >= CTX_KEYDB_STRING_START && val <= CTX_KEYDB_STRING_END;
+ ctx_color_set_rgba (color, in[0], in[1], in[2], in[3]);
}
+#endif
-static int ctx_float_to_string_index (float val)
+/* the baseline conversions we have whether CMYK support is enabled or not,
+ * providing an effort at right rendering
+ */
+static void ctx_cmyk_to_rgb (float c, float m, float y, float k, float *r, float *g, float *b)
{
- int idx = -1;
- if (ctx_float_is_string (val))
- {
- idx = val - CTX_KEYDB_STRING_START;
- }
- return idx;
+ *r = (1.0f-c) * (1.0f-k);
+ *g = (1.0f-m) * (1.0f-k);
+ *b = (1.0f-y) * (1.0f-k);
}
-static float ctx_string_index_to_float (int index)
+void ctx_rgb_to_cmyk (float r, float g, float b,
+ float *c_out, float *m_out, float *y_out, float *k_out)
{
- return CTX_KEYDB_STRING_START + index;
+ float c = 1.0f - r;
+ float m = 1.0f - g;
+ float y = 1.0f - b;
+ float k = ctx_minf (c, ctx_minf (y, m) );
+ if (k < 1.0f)
+ {
+ c = (c - k) / (1.0f - k);
+ m = (m - k) / (1.0f - k);
+ y = (y - k) / (1.0f - k);
+ }
+ else
+ {
+ c = m = y = 0.0f;
+ }
+ *c_out = c;
+ *m_out = m;
+ *y_out = y;
+ *k_out = k;
}
-void *ctx_state_get_blob (CtxState *state, uint32_t key)
+#if CTX_ENABLE_CMYK
+static void ctx_color_set_cmyka (CtxState *state, CtxColor *color, float c, float m, float y, float k, float
a)
{
- float stored = ctx_state_get (state, key);
- int idx = ctx_float_to_string_index (stored);
- if (idx >= 0)
- {
- // can we know length?
- return &state->stringpool[idx];
- }
-
- // format number as string?
- return NULL;
+ color->original = color->valid = CTX_VALID_CMYKA;
+ color->cyan = c;
+ color->magenta = m;
+ color->yellow = y;
+ color->key = k;
+ color->alpha = a;
+#if CTX_ENABLE_CM
+ color->space = state->gstate.cmyk_space;
+#endif
}
-const char *ctx_state_get_string (CtxState *state, uint32_t key)
+static void ctx_color_set_dcmyka (CtxState *state, CtxColor *color, float c, float m, float y, float k,
float a)
{
- const char *ret = (char*)ctx_state_get_blob (state, key);
- if (ret && ret[0] == 127)
- return NULL;
- return ret;
+ color->original = color->valid = CTX_VALID_DCMYKA;
+ color->device_cyan = c;
+ color->device_magenta = m;
+ color->device_yellow = y;
+ color->device_key = k;
+ color->alpha = a;
+#if CTX_ENABLE_CM
+ color->space = state->gstate.device_space;
+#endif
}
+#endif
-static void ctx_state_set_blob (CtxState *state, uint32_t key, uint8_t *data, int len)
-{
- int idx = state->gstate.stringpool_pos;
+#if CTX_ENABLE_CM
- if (idx + len > CTX_STRINGPOOL_SIZE)
- {
- ctx_log ("blowing varpool size [%c..]\n", data[0]);
- //fprintf (stderr, "blowing varpool size [%c%c%c..]\n", data[0],data[1], data[1]?data[2]:0);
+static void ctx_rgb_user_to_device (CtxState *state, float rin, float gin, float bin,
+ float *rout, float *gout, float *bout)
+{
+#if CTX_BABL
#if 0
- for (int i = 0; i< CTX_STRINGPOOL_SIZE; i++)
- {
- if (i==0) fprintf (stderr, "\n%i ", i);
- else fprintf (stderr, "%c", state->stringpool[i]);
- }
+ fprintf (stderr, "-[%p %p\n",
+ state->gstate.fish_rgbaf_user_to_device,
+ state->gstate.fish_rgbaf_device_to_user);
#endif
+ if (state->gstate.fish_rgbaf_user_to_device)
+ {
+ float rgbaf[4]={rin,gin,bin,1.0};
+ float rgbafo[4];
+ babl_process (state->gstate.fish_rgbaf_user_to_device,
+ rgbaf, rgbafo, 1);
+
+ *rout = rgbafo[0];
+ *gout = rgbafo[1];
+ *bout = rgbafo[2];
return;
}
-
- memcpy (&state->stringpool[idx], data, len);
- state->gstate.stringpool_pos+=len;
- state->stringpool[state->gstate.stringpool_pos++]=0;
- ctx_state_set (state, key, ctx_string_index_to_float (idx));
+#endif
+ *rout = rin;
+ *gout = gin;
+ *bout = bin;
}
-static void ctx_state_set_string (CtxState *state, uint32_t key, const char *string)
+static void ctx_rgb_device_to_user (CtxState *state, float rin, float gin, float bin,
+ float *rout, float *gout, float *bout)
{
- float old_val = ctx_state_get (state, key);
- int old_idx = ctx_float_to_string_index (old_val);
-
- if (old_idx >= 0)
+#if CTX_BABL
+#if 0
+ fprintf (stderr, "=[%p %p\n",
+ state->gstate.fish_rgbaf_user_to_device,
+ state->gstate.fish_rgbaf_device_to_user);
+#endif
+ if (state->gstate.fish_rgbaf_device_to_user)
{
- const char *old_string = ctx_state_get_string (state, key);
- if (old_string && !strcmp (old_string, string))
- return;
- }
+ float rgbaf[4]={rin,gin,bin,1.0};
+ float rgbafo[4];
+ babl_process (state->gstate.fish_rgbaf_device_to_user,
+ rgbaf, rgbafo, 1);
- if (ctx_str_is_number (string))
- {
- ctx_state_set (state, key, strtod (string, NULL));
+ *rout = rgbafo[0];
+ *gout = rgbafo[1];
+ *bout = rgbafo[2];
return;
}
- // should do same with color
-
- // XXX should special case when the string modified is at the
- // end of the stringpool.
- //
- // 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));
+#endif
+ *rout = rin;
+ *gout = gin;
+ *bout = bin;
}
+#endif
-static int ctx_state_get_color (CtxState *state, uint32_t key, CtxColor *color)
+static void ctx_color_get_drgba (CtxState *state, CtxColor *color, float *out)
{
- CtxColor *stored = (CtxColor*)ctx_state_get_blob (state, key);
- if (stored)
- {
- if (stored->magic == 127)
+ if (! (color->valid & CTX_VALID_RGBA_DEVICE) )
{
- *color = *stored;
- return 0;
+#if CTX_ENABLE_CM
+ if (color->valid & CTX_VALID_RGBA)
+ {
+ ctx_rgb_user_to_device (state, color->red, color->green, color->blue,
+ & (color->device_red), & (color->device_green), & (color->device_blue) );
+ }
+ else
+#endif
+ if (color->valid & CTX_VALID_RGBA_U8)
+ {
+ float red = ctx_u8_to_float (color->rgba[0]);
+ float green = ctx_u8_to_float (color->rgba[1]);
+ float blue = ctx_u8_to_float (color->rgba[2]);
+#if CTX_ENABLE_CM
+ ctx_rgb_user_to_device (state, red, green, blue,
+ & (color->device_red), & (color->device_green), & (color->device_blue) );
+#else
+ color->device_red = red;
+ color->device_green = green;
+ color->device_blue = blue;
+#endif
+ color->alpha = ctx_u8_to_float (color->rgba[3]);
+ }
+#if CTX_ENABLE_CMYK
+ else if (color->valid & CTX_VALID_CMYKA)
+ {
+ ctx_cmyk_to_rgb (color->cyan, color->magenta, color->yellow, color->key,
+ &color->device_red,
+ &color->device_green,
+ &color->device_blue);
+ }
+#endif
+ else if (color->valid & CTX_VALID_GRAYA)
+ {
+ color->device_red =
+ color->device_green =
+ color->device_blue = color->l;
+ }
+ color->valid |= CTX_VALID_RGBA_DEVICE;
}
- }
- return -1;
+ out[0] = color->device_red;
+ out[1] = color->device_green;
+ out[2] = color->device_blue;
+ out[3] = color->alpha;
}
-static void ctx_state_set_color (CtxState *state, uint32_t key, CtxColor *color)
+void ctx_color_get_rgba (CtxState *state, CtxColor *color, float *out)
{
- CtxColor mod_color;
- CtxColor old_color;
- mod_color = *color;
- mod_color.magic = 127;
- if (ctx_state_get_color (state, key, &old_color)==0)
- {
- if (!memcmp (&mod_color, &old_color, sizeof (mod_color)))
- return;
- }
- ctx_state_set_blob (state, key, (uint8_t*)&mod_color, sizeof (CtxColor));
+#if CTX_ENABLE_CM
+ if (! (color->valid & CTX_VALID_RGBA) )
+ {
+ ctx_color_get_drgba (state, color, out);
+ if (color->valid & CTX_VALID_RGBA_DEVICE)
+ {
+ ctx_rgb_device_to_user (state, color->device_red, color->device_green, color->device_blue,
+ & (color->red), & (color->green), & (color->blue) );
+ }
+ color->valid |= CTX_VALID_RGBA;
+ }
+ out[0] = color->red;
+ out[1] = color->green;
+ out[2] = color->blue;
+ out[3] = color->alpha;
+#else
+ ctx_color_get_drgba (state, color, out);
+#endif
}
-const char *ctx_get_string (Ctx *ctx, uint32_t hash)
+
+float ctx_float_color_rgb_to_gray (CtxState *state, const float *rgb)
{
- return ctx_state_get_string (&ctx->state, hash);
+ // XXX todo replace with correct according to primaries
+ return CTX_CSS_RGB_TO_LUMINANCE(rgb);
}
-float ctx_get_float (Ctx *ctx, uint32_t hash)
+uint8_t ctx_u8_color_rgb_to_gray (CtxState *state, const uint8_t *rgb)
{
- return ctx_state_get (&ctx->state, hash);
+ // XXX todo replace with correct according to primaries
+ return CTX_CSS_RGB_TO_LUMINANCE(rgb);
}
-int ctx_get_int (Ctx *ctx, uint32_t hash)
+
+void ctx_color_get_graya (CtxState *state, CtxColor *color, float *out)
{
- return ctx_state_get (&ctx->state, hash);
+ if (! (color->valid & CTX_VALID_GRAYA) )
+ {
+ float rgba[4];
+ ctx_color_get_drgba (state, color, rgba);
+ color->l = ctx_float_color_rgb_to_gray (state, rgba);
+ color->valid |= CTX_VALID_GRAYA;
+ }
+ out[0] = color->l;
+ out[1] = color->alpha;
}
-void ctx_set_float (Ctx *ctx, uint32_t hash, float value)
+
+#if CTX_ENABLE_CMYK
+void ctx_color_get_cmyka (CtxState *state, CtxColor *color, float *out)
{
- ctx_state_set (&ctx->state, hash, value);
+ if (! (color->valid & CTX_VALID_CMYKA) )
+ {
+ if (color->valid & CTX_VALID_GRAYA)
+ {
+ color->cyan = color->magenta = color->yellow = 0.0;
+ color->key = color->l;
+ }
+ else
+ {
+ float rgba[4];
+ ctx_color_get_rgba (state, color, rgba);
+ ctx_rgb_to_cmyk (rgba[0], rgba[1], rgba[2],
+ &color->cyan, &color->magenta, &color->yellow, &color->key);
+ color->alpha = rgba[3];
+ }
+ color->valid |= CTX_VALID_CMYKA;
+ }
+ out[0] = color->cyan;
+ out[1] = color->magenta;
+ out[2] = color->yellow;
+ out[3] = color->key;
+ out[4] = color->alpha;
}
-void ctx_set_string (Ctx *ctx, uint32_t hash, const char *value)
+
+#if 0
+static void ctx_color_get_cmyka_u8 (CtxState *state, CtxColor *color, uint8_t *out)
{
- ctx_state_set_string (&ctx->state, hash, value);
+ if (! (color->valid & CTX_VALID_CMYKA_U8) )
+ {
+ float cmyka[5];
+ ctx_color_get_cmyka (color, cmyka);
+ for (int i = 0; i < 5; i ++)
+ { color->cmyka[i] = ctx_float_to_u8 (cmyka[i]); }
+ color->valid |= CTX_VALID_CMYKA_U8;
+ }
+ out[0] = color->cmyka[0];
+ out[1] = color->cmyka[1];
+ out[2] = color->cmyka[2];
+ out[3] = color->cmyka[3];
}
-void ctx_set_color (Ctx *ctx, uint32_t hash, CtxColor *color)
+#endif
+#endif
+
+void
+ctx_color_get_rgba8 (CtxState *state, CtxColor *color, uint8_t *out)
{
- ctx_state_set_color (&ctx->state, hash, color);
+ if (! (color->valid & CTX_VALID_RGBA_U8) )
+ {
+ float rgba[4];
+ ctx_color_get_drgba (state, color, rgba);
+ for (int i = 0; i < 4; i ++)
+ { color->rgba[i] = ctx_float_to_u8 (rgba[i]); }
+ color->valid |= CTX_VALID_RGBA_U8;
+ }
+ out[0] = color->rgba[0];
+ out[1] = color->rgba[1];
+ out[2] = color->rgba[2];
+ out[3] = color->rgba[3];
}
-int ctx_get_color (Ctx *ctx, uint32_t hash, CtxColor *color)
+
+void ctx_color_get_graya_u8 (CtxState *state, CtxColor *color, uint8_t *out)
{
- return ctx_state_get_color (&ctx->state, hash, color);
+ if (! (color->valid & CTX_VALID_GRAYA_U8) )
+ {
+ float graya[2];
+ ctx_color_get_graya (state, color, graya);
+ color->l_u8 = ctx_float_to_u8 (graya[0]);
+ color->rgba[3] = ctx_float_to_u8 (graya[1]);
+ color->valid |= CTX_VALID_GRAYA_U8;
+ }
+ out[0] = color->l_u8;
+ out[1] = color->rgba[3];
}
-int ctx_is_set (Ctx *ctx, uint32_t hash)
+
+#if 0
+void
+ctx_get_rgba (Ctx *ctx, float *rgba)
{
- return ctx_get_float (ctx, hash) != -0.0f;
+ ctx_color_get_rgba (& (ctx->state), &ctx->state.gstate.source.color, rgba);
}
-int ctx_is_set_now (Ctx *ctx, uint32_t hash)
+
+void
+ctx_get_drgba (Ctx *ctx, float *rgba)
{
- return ctx_is_set (ctx, hash);
+ ctx_color_get_drgba (& (ctx->state), &ctx->state.gstate.source.color, rgba);
}
-#if CTX_RASTERIZER
-
-void ctx_compositor_setup_default (CtxRasterizer *rasterizer);
+#endif
-inline static void
-ctx_rasterizer_apply_coverage (CtxRasterizer *rasterizer,
- uint8_t * __restrict__ dst,
- int x,
- uint8_t * __restrict__ coverage,
- int count)
+int ctx_in_fill (Ctx *ctx, float x, float y)
{
- if (rasterizer->format->apply_coverage)
- rasterizer->format->apply_coverage(rasterizer, dst, rasterizer->color, x, coverage, count);
- else
- rasterizer->comp_op (rasterizer, dst, rasterizer->color, x, coverage, count);
+ float x1, y1, x2, y2;
+ ctx_path_extents (ctx, &x1, &y1, &x2, &y2);
+
+ if (x1 <= x && x <= x2 && // XXX - just bounding box for now
+ y1 <= y && y <= y2) //
+ return 1;
+ return 0;
}
-static void
-ctx_rasterizer_gradient_add_stop (CtxRasterizer *rasterizer, float pos, float *rgba)
+
+#if CTX_ENABLE_CMYK
+#if 0
+void
+ctx_get_cmyka (Ctx *ctx, float *cmyka)
{
- CtxGradient *gradient = &rasterizer->state->gradient;
- 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
- { gradient->n_stops++; }
+ ctx_color_get_cmyka (& (ctx->state), &ctx->state.gstate.source.color, cmyka);
}
-
-static int ctx_rasterizer_add_point (CtxRasterizer *rasterizer, int x1, int y1)
+#endif
+#endif
+#if 0
+void
+ctx_get_graya (Ctx *ctx, float *ya)
{
- CtxEntry entry = {CTX_EDGE, {{0},}};
- if (y1 < rasterizer->scan_min)
- { rasterizer->scan_min = y1; }
- if (y1 > rasterizer->scan_max)
- { rasterizer->scan_max = y1; }
+ ctx_color_get_graya (& (ctx->state), &ctx->state.gstate.source.color, ya);
+}
+#endif
- if (x1 < rasterizer->col_min)
- { rasterizer->col_min = x1; }
- if (x1 > rasterizer->col_max)
- { rasterizer->col_max = x1; }
+void ctx_color_raw (Ctx *ctx, CtxColorModel model, float *components, int stroke)
+{
+ if (model == CTX_RGB || model == CTX_RGBA)
+ {
+ float rgba[4];
+ // XXX it should be possible to disable this, to get a more accurate record
+ // when it is intentional
+ float a = 1.0f;
+ if (model == CTX_RGBA) a = components[3];
+ if (stroke)
+ ctx_color_get_rgba (&ctx->state, &ctx->state.gstate.source_stroke.color, rgba);
+ else
+ ctx_color_get_rgba (&ctx->state, &ctx->state.gstate.source_fill.color, rgba);
+ if (rgba[0] == components[0] && rgba[1] == components[1] && rgba[2] == components[2] && rgba[3] == a)
+ return;
+ }
- entry.data.s16[2]=x1;
- entry.data.s16[3]=y1;
- return ctx_drawlist_add_single (&rasterizer->edge_list, &entry);
+ CtxEntry command[3]= {
+ ctx_f (CTX_COLOR, model + stroke * 512, 0)
+ };
+ switch (model)
+ {
+ case CTX_RGBA:
+ case CTX_RGBA_A:
+ case CTX_RGBA_A_DEVICE:
+ case CTX_DRGBA:
+ case CTX_LABA:
+ case CTX_LCHA:
+ command[2].data.f[0]=components[3];
+ /*FALLTHROUGH*/
+ case CTX_RGB:
+ case CTX_LAB:
+ case CTX_LCH:
+ case CTX_DRGB:
+ command[0].data.f[1]=components[0];
+ command[1].data.f[0]=components[1];
+ command[1].data.f[1]=components[2];
+ break;
+ case CTX_DCMYKA:
+ case CTX_CMYKA:
+ case CTX_DCMYKA_A:
+ case CTX_CMYKA_A:
+ command[2].data.f[1]=components[4];
+ /*FALLTHROUGH*/
+ case CTX_CMYK:
+ case CTX_DCMYK:
+ command[0].data.f[1]=components[0];
+ command[1].data.f[0]=components[1];
+ command[1].data.f[1]=components[2];
+ command[2].data.f[0]=components[3];
+ break;
+ case CTX_GRAYA:
+ case CTX_GRAYA_A:
+ command[1].data.f[0]=components[1];
+ /*FALLTHROUGH*/
+ case CTX_GRAY:
+ command[0].data.f[1]=components[0];
+ break;
+ }
+ ctx_process (ctx, command);
}
-#if 0
-#define CTX_SHAPE_CACHE_PRIME1 7853
-#define CTX_SHAPE_CACHE_PRIME2 4129
-#define CTX_SHAPE_CACHE_PRIME3 3371
-#define CTX_SHAPE_CACHE_PRIME4 4221
-#else
-#define CTX_SHAPE_CACHE_PRIME1 283
-#define CTX_SHAPE_CACHE_PRIME2 599
-#define CTX_SHAPE_CACHE_PRIME3 101
-#define CTX_SHAPE_CACHE_PRIME4 661
-#endif
-
-float ctx_shape_cache_rate = 0.0;
-#if CTX_SHAPE_CACHE
-
-//static CtxShapeCache ctx_cache = {{NULL,}, 0};
-
-static long hits = 0;
-static long misses = 0;
-
-
-/* this returns the buffer to use for rendering, it always
- succeeds..
- */
-static CtxShapeEntry *ctx_shape_entry_find (CtxRasterizer *rasterizer, uint32_t hash, int width, int height)
+void ctx_rgba (Ctx *ctx, float r, float g, float b, float a)
{
- /* use both some high and some low bits */
- int entry_no = ( (hash >> 10) ^ (hash & 1023) ) % CTX_SHAPE_CACHE_ENTRIES;
- int i;
- {
- static int i = 0;
- i++;
- if (i>1000)
- {
- ctx_shape_cache_rate = hits * 100.0 / (hits+misses);
- i = 0;
- hits = 0;
- misses = 0;
- }
- }
-// XXX : this 1 one is needed to silence a false positive:
-// ==90718== Invalid write of size 1
-// ==90718== at 0x1189EF: ctx_rasterizer_generate_coverage (ctx.h:4786)
-// ==90718== by 0x118E57: ctx_rasterizer_rasterize_edges (ctx.h:4907)
-//
- int size = sizeof (CtxShapeEntry) + width * height + 1;
-
- i = entry_no;
- if (rasterizer->shape_cache.entries[i])
- {
- CtxShapeEntry *entry = rasterizer->shape_cache.entries[i];
- int old_size = sizeof (CtxShapeEntry) + width + height + 1;
- if (entry->hash == hash &&
- entry->width == width &&
- entry->height == height)
- {
- if (entry->uses < 1<<30)
- { entry->uses++; }
- hits ++;
- return entry;
- }
-
- if (old_size >= size)
- {
- }
- else
- {
- rasterizer->shape_cache.entries[i] = NULL;
- rasterizer->shape_cache.size -= entry->width * entry->height;
- rasterizer->shape_cache.size -= sizeof (CtxShapeEntry);
- free (entry);
- rasterizer->shape_cache.entries[i] =(CtxShapeEntry *) calloc (size, 1);
- }
- }
- else
- {
- rasterizer->shape_cache.entries[i] =(CtxShapeEntry *) calloc (size, 1);
- }
+ float components[4]={r,g,b,a};
+ ctx_color_raw (ctx, CTX_RGBA, components, 0);
+}
- misses ++;
-
- rasterizer->shape_cache.size += size;
- rasterizer->shape_cache.entries[i]->hash=hash;
- rasterizer->shape_cache.entries[i]->width=width;
- rasterizer->shape_cache.entries[i]->height=height;
- rasterizer->shape_cache.entries[i]->uses = 0;
- return rasterizer->shape_cache.entries[i];
+void ctx_rgba_stroke (Ctx *ctx, float r, float g, float b, float a)
+{
+ float components[4]={r,g,b,a};
+ ctx_color_raw (ctx, CTX_RGBA, components, 1);
}
-#endif
+void ctx_rgb (Ctx *ctx, float r, float g, float b)
+{
+ ctx_rgba (ctx, r, g, b, 1.0f);
+}
-static uint32_t ctx_rasterizer_poly_to_hash (CtxRasterizer *rasterizer)
+void ctx_rgb_stroke (Ctx *ctx, float r, float g, float b)
{
- int16_t x = 0;
- int16_t y = 0;
+ ctx_rgba_stroke (ctx, r, g, b, 1.0f);
+}
- CtxEntry *entry = &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 (int i = 0; i < rasterizer->edge_list.count; i++)
- {
- CtxEntry *entry = &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;
+void ctx_gray_stroke (Ctx *ctx, float gray)
+{
+ ctx_color_raw (ctx, CTX_GRAY, &gray, 1);
+}
+void ctx_gray (Ctx *ctx, float gray)
+{
+ ctx_color_raw (ctx, CTX_GRAY, &gray, 0);
}
-static uint32_t ctx_rasterizer_poly_to_edges (CtxRasterizer *rasterizer)
+void ctx_drgba_stroke (Ctx *ctx, float r, float g, float b, float a)
{
- int16_t x = 0;
- int16_t y = 0;
- if (rasterizer->edge_list.count == 0)
- return 0;
-#if CTX_SHAPE_CACHE
- int aa = rasterizer->aa;
- CtxEntry *entry = &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 % CTX_SUBDIV);
- hash *= CTX_SHAPE_CACHE_PRIME1;
- hash += (oy % aa);
-#endif
- for (int i = 0; i < rasterizer->edge_list.count; i++)
- {
- CtxEntry *entry = &rasterizer->edge_list.entries[i];
- if (entry->code == CTX_NEW_EDGE)
- {
- entry->code = CTX_EDGE;
-#if CTX_SHAPE_CACHE
- hash *= CTX_SHAPE_CACHE_PRIME2;
-#endif
- }
- else
- {
- entry->data.s16[0] = x;
- entry->data.s16[1] = y;
- }
- x = entry->data.s16[2];
- y = entry->data.s16[3];
-#if CTX_SHAPE_CACHE
- 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;
-#endif
- if (entry->data.s16[3] < entry->data.s16[1])
- {
- *entry = ctx_s16 (CTX_EDGE_FLIPPED,
- entry->data.s16[2], entry->data.s16[3],
- entry->data.s16[0], entry->data.s16[1]);
- }
- }
-#if CTX_SHAPE_CACHE
- return hash;
-#else
- return 0;
-#endif
+ float components[4]={r,g,b,a};
+ ctx_color_raw (ctx, CTX_DRGBA, components, 1);
+}
+void ctx_drgba (Ctx *ctx, float r, float g, float b, float a)
+{
+ float components[4]={r,g,b,a};
+ ctx_color_raw (ctx, CTX_DRGBA, components, 0);
}
-static void ctx_rasterizer_line_to (CtxRasterizer *rasterizer, float x, float y);
+#if CTX_ENABLE_CMYK
-static void ctx_rasterizer_finish_shape (CtxRasterizer *rasterizer)
+void ctx_cmyka_stroke (Ctx *ctx, float c, float m, float y, float k, float a)
{
- if (rasterizer->has_shape && rasterizer->has_prev)
- {
- ctx_rasterizer_line_to (rasterizer, rasterizer->first_x, rasterizer->first_y);
- rasterizer->has_prev = 0;
- }
+ float components[5]={c,m,y,k,a};
+ ctx_color_raw (ctx, CTX_CMYKA, components, 1);
+}
+void ctx_cmyka (Ctx *ctx, float c, float m, float y, float k, float a)
+{
+ float components[5]={c,m,y,k,a};
+ ctx_color_raw (ctx, CTX_CMYKA, components, 0);
+}
+void ctx_cmyk_stroke (Ctx *ctx, float c, float m, float y, float k)
+{
+ float components[4]={c,m,y,k};
+ ctx_color_raw (ctx, CTX_CMYK, components, 1);
+}
+void ctx_cmyk (Ctx *ctx, float c, float m, float y, float k)
+{
+ float components[4]={c,m,y,k};
+ ctx_color_raw (ctx, CTX_CMYK, components, 0);
}
-static void ctx_rasterizer_move_to (CtxRasterizer *rasterizer, float x, float y)
+static void ctx_dcmyk_raw (Ctx *ctx, float c, float m, float y, float k, int stroke)
{
- float tx = x; float ty = y;
- int aa = rasterizer->aa;
- 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);
- }
+ float components[5]={c,m,y,k,1.0f};
+ ctx_color_raw (ctx, CTX_DCMYKA, components, stroke);
+}
- tx = (tx - rasterizer->blit_x) * CTX_SUBDIV;
- ty = ty * aa;
+static void ctx_dcmyka_raw (Ctx *ctx, float c, float m, float y, float k, float a, int stroke)
+{
+ CtxEntry command[3]=
+ {
+ ctx_f (CTX_COLOR, CTX_DCMYKA + 512 * stroke, c),
+ ctx_f (CTX_CONT, m, y),
+ ctx_f (CTX_CONT, k, a)
+ };
+ ctx_process (ctx, command);
+}
- if (ty < rasterizer->scan_min)
- { rasterizer->scan_min = ty; }
- if (ty > rasterizer->scan_max)
- { rasterizer->scan_max = ty; }
- if (tx < rasterizer->col_min)
- { rasterizer->col_min = tx; }
- if (tx > rasterizer->col_max)
- { rasterizer->col_max = tx; }
+void ctx_dcmyk_stroke (Ctx *ctx, float c, float m, float y, float k)
+{
+ float components[5]={c,m,y,k,1.0f};
+ ctx_color_raw (ctx, CTX_DCMYK, components, 1);
+}
+void ctx_dcmyk (Ctx *ctx, float c, float m, float y, float k)
+{
+ float components[5]={c,m,y,k,1.0f};
+ ctx_color_raw (ctx, CTX_DCMYK, components, 0);
}
-static void ctx_rasterizer_line_to (CtxRasterizer *rasterizer, float x, float y)
+void ctx_dcmyka_stroke (Ctx *ctx, float c, float m, float y, float k, float a)
{
- 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;
-#define MIN_Y -1000
-#define MAX_Y 1400
+ float components[5]={c,m,y,k,a};
+ ctx_color_raw (ctx, CTX_DCMYKA, components, 1);
+}
+void ctx_dcmyka (Ctx *ctx, float c, float m, float y, float k, float a)
+{
+ float components[5]={c,m,y,k,a};
+ ctx_color_raw (ctx, CTX_DCMYKA, components, 0);
+}
+#endif
- if (ty < MIN_Y) ty = MIN_Y;
- if (ty > MAX_Y) ty = MAX_Y;
- ctx_rasterizer_add_point (rasterizer, tx * CTX_SUBDIV, ty * rasterizer->aa);
- if (rasterizer->has_prev<=0)
- {
- if (rasterizer->uses_transforms)
- {
- // storing transformed would save some processing for a tiny
- // amount of runtime RAM XXX
- _ctx_user_to_device (rasterizer->state, &ox, &oy);
- }
- ox -= rasterizer->blit_x;
-
- if (oy < MIN_Y) oy = MIN_Y;
- if (oy > MAX_Y) oy = MAX_Y;
+/* XXX: missing CSS1:
+ *
+ * EM { color: rgb(110%, 0%, 0%) } // clipped to 100%
+ *
+ *
+ * :first-letter
+ * :first-list
+ * :link :visited :active
+ *
+ */
- rasterizer->edge_list.entries[rasterizer->edge_list.count-1].data.s16[0] = ox * CTX_SUBDIV;
- rasterizer->edge_list.entries[rasterizer->edge_list.count-1].data.s16[1] = oy * rasterizer->aa;
- rasterizer->edge_list.entries[rasterizer->edge_list.count-1].code = CTX_NEW_EDGE;
- rasterizer->has_prev = 1;
- }
- rasterizer->has_shape = 1;
- rasterizer->y = y;
- rasterizer->x = x;
-}
+typedef struct ColorDef {
+ uint64_t name;
+ float r;
+ float g;
+ float b;
+ float a;
+} ColorDef;
+#if 0
+#define CTX_silver CTX_STRH('s','i','l','v','e','r',0,0,0,0,0,0,0,0)
+#define CTX_fuchsia CTX_STRH('f','u','c','h','s','i','a',0,0,0,0,0,0,0)
+#define CTX_gray CTX_STRH('g','r','a','y',0,0,0,0,0,0,0,0,0,0)
+#define CTX_yellow CTX_STRH('y','e','l','l','o','w',0,0,0,0,0,0,0,0)
+#define CTX_white CTX_STRH('w','h','i','t','e',0,0,0,0,0,0,0,0,0)
+#define CTX_maroon CTX_STRH('m','a','r','o','o','n',0,0,0,0,0,0,0,0)
+#define CTX_magenta CTX_STRH('m','a','g','e','n','t','a',0,0,0,0,0,0,0)
+#define CTX_blue CTX_STRH('b','l','u','e',0,0,0,0,0,0,0,0,0,0)
+#define CTX_green CTX_STRH('g','r','e','e','n',0,0,0,0,0,0,0,0,0)
+#define CTX_red CTX_STRH('r','e','d',0,0,0,0,0,0,0,0,0,0,0)
+#define CTX_purple CTX_STRH('p','u','r','p','l','e',0,0,0,0,0,0,0,0)
+#define CTX_olive CTX_STRH('o','l','i','v','e',0,0,0,0,0,0,0,0,0)
+#define CTX_teal CTX_STRH('t','e','a','l',0,0,0,0,0,0,0,0,0,0)
+#define CTX_black CTX_STRH('b','l','a','c','k',0,0,0,0,0,0,0,0,0)
+#define CTX_cyan CTX_STRH('c','y','a','n',0,0,0,0,0,0,0,0,0,0)
+#define CTX_navy CTX_STRH('n','a','v','y',0,0,0,0,0,0,0,0,0,0)
+#define CTX_lime CTX_STRH('l','i','m','e',0,0,0,0,0,0,0,0,0,0)
+#define CTX_aqua CTX_STRH('a','q','u','a',0,0,0,0,0,0,0,0,0,0)
+#define CTX_transparent CTX_STRH('t','r','a','n','s','p','a','r','e','n','t',0,0,0)
+#endif
-CTX_INLINE static float
-ctx_bezier_sample_1d (float x0, float x1, float x2, float x3, float dt)
-{
- float ab = ctx_lerpf (x0, x1, dt);
- float bc = ctx_lerpf (x1, x2, dt);
- float cd = ctx_lerpf (x2, x3, dt);
- float abbc = ctx_lerpf (ab, bc, dt);
- float bccd = ctx_lerpf (bc, cd, dt);
- return ctx_lerpf (abbc, bccd, dt);
-}
+static ColorDef colors[]={
+ {CTX_black, 0, 0, 0, 1},
+ {CTX_red, 1, 0, 0, 1},
+ {CTX_green, 0, 1, 0, 1},
+ {CTX_yellow, 1, 1, 0, 1},
+ {CTX_blue, 0, 0, 1, 1},
+ {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_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_aqua, 0, 1, 1, 1},
+ {CTX_transparent, 0, 0, 0, 0},
+ {CTX_none, 0, 0, 0, 0},
+};
-inline static void
-ctx_bezier_sample (float x0, float y0,
- float x1, float y1,
- float x2, float y2,
- float x3, float y3,
- float dt, float *x, float *y)
+static int xdigit_value(const char xdigit)
{
- *x = ctx_bezier_sample_1d (x0, x1, x2, x3, dt);
- *y = ctx_bezier_sample_1d (y0, y1, y2, y3, dt);
+ if (xdigit >= '0' && xdigit <= '9')
+ return xdigit - '0';
+ switch (xdigit)
+ {
+ case 'A':case 'a': return 10;
+ case 'B':case 'b': return 11;
+ case 'C':case 'c': return 12;
+ case 'D':case 'd': return 13;
+ case 'E':case 'e': return 14;
+ case 'F':case 'f': return 15;
+ }
+ return 0;
}
-static void
-ctx_rasterizer_bezier_divide (CtxRasterizer *rasterizer,
- float ox, float oy,
- float x0, float y0,
- float x1, float y1,
- float x2, float y2,
- float sx, float sy,
- float ex, float ey,
- float s,
- float e,
- int iteration,
- float tolerance)
+static int
+ctx_color_parse_rgb (CtxState *ctxstate, CtxColor *color, const char *color_string)
{
- if (iteration > 8)
- { return; }
- float t = (s + e) * 0.5f;
- float x, y, lx, ly, dx, dy;
- ctx_bezier_sample (ox, oy, x0, y0, x1, y1, x2, y2, t, &x, &y);
- if (iteration)
- {
- lx = ctx_lerpf (sx, ex, t);
- ly = ctx_lerpf (sy, ey, t);
- dx = lx - x;
- dy = ly - y;
- if ( (dx*dx+dy*dy) < tolerance)
- /* bailing - because for the mid-point straight line difference is
- tiny */
- { return; }
- dx = sx - ex;
- dy = ey - ey;
- if ( (dx*dx+dy*dy) < tolerance)
- /* bailing on tiny segments */
- { return; }
- }
- ctx_rasterizer_bezier_divide (rasterizer, ox, oy, x0, y0, x1, y1, x2, y2,
- sx, sy, x, y, s, t, iteration + 1,
- tolerance);
- ctx_rasterizer_line_to (rasterizer, x, y);
- ctx_rasterizer_bezier_divide (rasterizer, ox, oy, x0, y0, x1, y1, x2, y2,
- x, y, ex, ey, t, e, iteration + 1,
- tolerance);
-}
+ float dcolor[4] = {0,0,0,1};
+ while (*color_string && *color_string != '(')
+ color_string++;
+ if (*color_string) color_string++;
-static void
-ctx_rasterizer_curve_to (CtxRasterizer *rasterizer,
- float x0, float y0,
- float x1, float y1,
- float x2, float y2)
-{
- float tolerance =
- ctx_pow2 (rasterizer->state->gstate.transform.m[0][0]) +
- ctx_pow2 (rasterizer->state->gstate.transform.m[1][1]);
- float ox = rasterizer->x;
- float oy = rasterizer->y;
- ox = rasterizer->state->x;
- oy = rasterizer->state->y;
- tolerance = 1.0f/tolerance * 2;
-#if 1 // skipping this to preserve hash integrity
- if (tolerance == 1.0f || 1)
{
- float maxx = ctx_maxf (x1,x2);
- maxx = ctx_maxf (maxx, ox);
- maxx = ctx_maxf (maxx, x0);
- float maxy = ctx_maxf (y1,y2);
- maxy = ctx_maxf (maxy, oy);
- maxy = ctx_maxf (maxy, y0);
- float minx = ctx_minf (x1,x2);
- minx = ctx_minf (minx, ox);
- minx = ctx_minf (minx, x0);
- float miny = ctx_minf (y1,y2);
- miny = ctx_minf (miny, oy);
- miny = ctx_minf (miny, y0);
-
- _ctx_user_to_device (rasterizer->state, &minx, &miny);
- _ctx_user_to_device (rasterizer->state, &maxx, &maxy);
-
- if(
- (minx > rasterizer->blit_x + rasterizer->blit_width) ||
- (miny > rasterizer->blit_y + rasterizer->blit_height) ||
- (maxx < rasterizer->blit_x) ||
- (maxy < rasterizer->blit_y) )
- {
- }
- else
+ int n_floats = 0;
+ char *p = (char*)color_string;
+ char *prev = (char*)NULL;
+ for (; p && n_floats < 4 && p != prev && *p; )
{
- ctx_rasterizer_bezier_divide (rasterizer,
- ox, oy, x0, y0,
- x1, y1, x2, y2,
- ox, oy, x2, y2,
- 0.0f, 1.0f, 0.0f, tolerance);
+ float val;
+ prev = p;
+ val = _ctx_parse_float (p, &p);
+ if (p != prev)
+ {
+ if (n_floats < 3)
+ dcolor[n_floats++] = val/255.0;
+ else
+ dcolor[n_floats++] = val;
+
+ while (*p == ' ' || *p == ',')
+ {
+ p++;
+ prev++;
+ }
+ }
}
}
- else
-#endif
- {
- ctx_rasterizer_bezier_divide (rasterizer,
- ox, oy, x0, y0,
- x1, y1, x2, y2,
- ox, oy, x2, y2,
- 0.0f, 1.0f, 0.0f, tolerance);
- }
- ctx_rasterizer_line_to (rasterizer, x2, y2);
+ ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
+ return 0;
}
-static void
-ctx_rasterizer_rel_move_to (CtxRasterizer *rasterizer, float x, float y)
+static int ctx_isxdigit (uint8_t ch)
{
- if (x == 0.f && y == 0.f)
- { return; }
- x += rasterizer->x;
- y += rasterizer->y;
- ctx_rasterizer_move_to (rasterizer, x, y);
+ if (ch >= '0' && ch <= '9') return 1;
+ if (ch >= 'a' && ch <= 'f') return 1;
+ if (ch >= 'A' && ch <= 'F') return 1;
+ return 0;
}
-static void
-ctx_rasterizer_rel_line_to (CtxRasterizer *rasterizer, float x, float y)
+static int
+mrg_color_parse_hex (CtxState *ctxstate, CtxColor *color, const char *color_string)
{
- if (x== 0.f && y==0.f)
- { return; }
- x += rasterizer->x;
- y += rasterizer->y;
- ctx_rasterizer_line_to (rasterizer, x, y);
-}
+ float dcolor[4]={0,0,0,1};
+ int string_length = strlen (color_string);
+ int i;
+ dcolor[3] = 1.0;
-static void
-ctx_rasterizer_rel_curve_to (CtxRasterizer *rasterizer,
- float x0, float y0, float x1, float y1, float x2, float y2)
-{
- x0 += rasterizer->x;
- y0 += rasterizer->y;
- x1 += rasterizer->x;
- y1 += rasterizer->y;
- x2 += rasterizer->x;
- y2 += rasterizer->y;
- ctx_rasterizer_curve_to (rasterizer, x0, y0, x1, y1, x2, y2);
-}
-
-CTX_INLINE static int ctx_compare_edges (const void *ap, const void *bp)
-{
- const CtxEntry *a = (const CtxEntry *) ap;
- const CtxEntry *b = (const CtxEntry *) bp;
- int ycompare = a->data.s16[1] - b->data.s16[1];
- if (ycompare)
- { return ycompare; }
- int xcompare = a->data.s16[0] - b->data.s16[0];
- return xcompare;
-}
-
-CTX_INLINE static int ctx_edge_qsort_partition (CtxEntry *A, int low, int high)
-{
- CtxEntry pivot = A[ (high+low) /2];
- int i = low;
- int j = high;
- while (i <= j)
+ if (string_length == 7 || /* #rrggbb */
+ string_length == 9) /* #rrggbbaa */
{
- while (ctx_compare_edges (&A[i], &pivot) <0) { i ++; }
- while (ctx_compare_edges (&pivot, &A[j]) <0) { j --; }
- if (i <= j)
+ int num_iterations = (string_length - 1) / 2;
+
+ for (i = 0; i < num_iterations; ++i)
{
- CtxEntry tmp = A[i];
- A[i] = A[j];
- A[j] = tmp;
- i++;
- j--;
+ if (ctx_isxdigit (color_string[2 * i + 1]) &&
+ ctx_isxdigit (color_string[2 * i + 2]))
+ {
+ dcolor[i] = (xdigit_value (color_string[2 * i + 1]) << 4 |
+ xdigit_value (color_string[2 * i + 2])) / 255.f;
+ }
+ else
+ {
+ return 0;
+ }
}
+ /* Successful #rrggbb(aa) parsing! */
+ ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
+ return 1;
}
- return i;
+ else if (string_length == 4 || /* #rgb */
+ string_length == 5) /* #rgba */
+ {
+ int num_iterations = string_length - 1;
+ for (i = 0; i < num_iterations; ++i)
+ {
+ if (ctx_isxdigit (color_string[i + 1]))
+ {
+ dcolor[i] = (xdigit_value (color_string[i + 1]) << 4 |
+ xdigit_value (color_string[i + 1])) / 255.f;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
+ /* Successful #rgb(a) parsing! */
+ return 0;
+ }
+ /* String was of unsupported length. */
+ return 1;
}
-static void ctx_edge_qsort (CtxEntry *entries, int low, int high)
+//#define CTX_currentColor CTX_STRH('c','u','r','r','e','n','t','C','o','l','o','r',0,0)
+
+int ctx_color_set_from_string (Ctx *ctx, CtxColor *color, const char *string)
{
+ int i;
+ uint64_t hash = ctx_strhash (string, 0);
+// ctx_color_set_rgba (&(ctx->state), color, 0.4,0.1,0.9,1.0);
+// return 0;
+ //rgba[0], rgba[1], rgba[2], rgba[3]);
+
+ if (hash == CTX_currentColor)
{
- int p = ctx_edge_qsort_partition (entries, low, high);
- if (low < p -1 )
- { ctx_edge_qsort (entries, low, p - 1); }
- if (low < high)
- { ctx_edge_qsort (entries, p, high); }
+ float rgba[4];
+ CtxColor ccolor;
+ ctx_get_color (ctx, CTX_color, &ccolor);
+ ctx_color_get_rgba (&(ctx->state), &ccolor, rgba);
+ ctx_color_set_rgba (&(ctx->state), color, rgba[0], rgba[1], rgba[2], rgba[3]);
+ return 0;
}
-}
-static void ctx_rasterizer_sort_edges (CtxRasterizer *rasterizer)
-{
- if (rasterizer->edge_list.count > 1)
+ for (i = (sizeof(colors)/sizeof(colors[0]))-1; i>=0; i--)
+ {
+ if (hash == colors[i].name)
{
- ctx_edge_qsort (& (rasterizer->edge_list.entries[0]), 0, rasterizer->edge_list.count-1);
+ ctx_color_set_rgba (&(ctx->state), color,
+ colors[i].r, colors[i].g, colors[i].b, colors[i].a);
+ return 0;
}
+ }
+
+ if (string[0] == '#')
+ mrg_color_parse_hex (&(ctx->state), color, string);
+ else if (string[0] == 'r' &&
+ string[1] == 'g' &&
+ string[2] == 'b'
+ )
+ ctx_color_parse_rgb (&(ctx->state), color, string);
+
+ return 0;
}
-static void ctx_rasterizer_discard_edges (CtxRasterizer *rasterizer)
+int ctx_color_fill (Ctx *ctx, const char *string)
{
-#if CTX_RASTERIZER_FORCE_AA==0
- rasterizer->ending_edges = 0;
-#endif
- for (int i = 0; i < rasterizer->active_edges; i++)
- {
- int edge_end =rasterizer->edge_list.entries[rasterizer->edges[i].index].data.s16[3];
- if (edge_end < rasterizer->scanline)
- {
- int dx_dy = rasterizer->edges[i].dx;
- if (abs(dx_dy)> CTX_RASTERIZER_AA_SLOPE_LIMIT)
- { rasterizer->needs_aa --; }
- rasterizer->edges[i] = rasterizer->edges[rasterizer->active_edges-1];
- rasterizer->active_edges--;
- i--;
- }
-#if CTX_RASTERIZER_FORCE_AA==0
- else if (edge_end < rasterizer->scanline + rasterizer->aa)
- rasterizer->ending_edges = 1;
-#endif
- }
+ CtxColor color = {0,};
+ ctx_color_set_from_string (ctx, &color, string);
+ float rgba[4];
+ ctx_color_get_rgba (&(ctx->state), &color, rgba);
+ ctx_color_raw (ctx, CTX_RGBA, rgba, 0);
+ return 0;
}
-static void ctx_rasterizer_increment_edges (CtxRasterizer *rasterizer, int count)
+int ctx_color_stroke (Ctx *ctx, const char *string)
{
- for (int i = 0; i < rasterizer->active_edges; i++)
- {
- rasterizer->edges[i].x += rasterizer->edges[i].dx * count;
- }
-#if CTX_RASTERIZER_FORCE_AA==0
- for (int i = 0; i < rasterizer->pending_edges; i++)
- {
- rasterizer->edges[CTX_MAX_EDGES-1-i].x += rasterizer->edges[CTX_MAX_EDGES-1-i].dx * count;
- }
-#endif
+ CtxColor color = {0,};
+ ctx_color_set_from_string (ctx, &color, string);
+ float rgba[4];
+ ctx_color_get_rgba (&(ctx->state), &color, rgba);
+ ctx_color_raw (ctx, CTX_RGBA, rgba, 1);
+ return 0;
}
-/* feeds up to rasterizer->scanline,
- keeps a pending buffer of edges - that encompass
- the full incoming scanline,
- feed until the start of the scanline and check for need for aa
- in all of pending + active edges, then
- again feed_edges until middle of scanline if doing non-AA
- or directly render when doing AA
-*/
-inline static void ctx_rasterizer_feed_edges (CtxRasterizer *rasterizer)
+void
+ctx_rgba8 (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
- int miny;
- CtxEntry *entries = rasterizer->edge_list.entries;
-#if CTX_RASTERIZER_FORCE_AA==0
- for (int i = 0; i < rasterizer->pending_edges; i++)
- {
- if (entries[rasterizer->edges[CTX_MAX_EDGES-1-i].index].data.s16[1] <= rasterizer->scanline)
- {
- if (rasterizer->active_edges < CTX_MAX_EDGES-2)
- {
- int no = rasterizer->active_edges;
- rasterizer->active_edges++;
- rasterizer->edges[no] = rasterizer->edges[CTX_MAX_EDGES-1-i];
- rasterizer->edges[CTX_MAX_EDGES-1-i] =
- rasterizer->edges[CTX_MAX_EDGES-1-rasterizer->pending_edges + 1];
- rasterizer->pending_edges--;
- i--;
- }
- }
- }
-#endif
- while (rasterizer->edge_pos < rasterizer->edge_list.count &&
- (miny=entries[rasterizer->edge_pos].data.s16[1]) <= rasterizer->scanline
-#if CTX_RASTERIZER_FORCE_AA==0
- + rasterizer->aa
-#endif
-
- )
- {
- if (rasterizer->active_edges < CTX_MAX_EDGES-2)
- {
- int dy = (entries[rasterizer->edge_pos].data.s16[3] -
- miny);
- if (dy) /* skipping horizontal edges */
- {
- int yd = rasterizer->scanline - miny;
- int no = rasterizer->active_edges;
- rasterizer->active_edges++;
- rasterizer->edges[no].index = rasterizer->edge_pos;
- int index = rasterizer->edges[no].index;
- int x0 = entries[index].data.s16[0];
- int x1 = entries[index].data.s16[2];
- rasterizer->edges[no].x = x0 * CTX_RASTERIZER_EDGE_MULTIPLIER;
- int dx_dy;
- // if (dy)
- dx_dy = CTX_RASTERIZER_EDGE_MULTIPLIER * (x1 - x0) / dy;
- // else
- // dx_dy = 0;
- rasterizer->edges[no].dx = dx_dy;
- rasterizer->edges[no].x += (yd * dx_dy);
- // XXX : even better minx and maxx can
- // be derived using y0 and y1 for scaling dx_dy
- // when ydelta to these are smaller than
- // ydelta to scanline
#if 0
- if (dx_dy < 0)
- {
- rasterizer->edges[no].minx =
- rasterizer->edges[no].x + dx_dy/2;
- rasterizer->edges[no].maxx =
- rasterizer->edges[no].x - dx_dy/2;
- }
- else
- {
- rasterizer->edges[no].minx =
- rasterizer->edges[no].x - dx_dy/2;
- rasterizer->edges[no].maxx =
- rasterizer->edges[no].x + dx_dy/2;
- }
+ CtxEntry command = ctx_u8 (CTX_SET_RGBA_U8, r, g, b, a, 0, 0, 0, 0);
+
+ uint8_t rgba[4];
+ ctx_color_get_rgba8 (&ctx->state, &ctx->state.gstate.source.color, rgba);
+ if (rgba[0] == r && rgba[1] == g && rgba[2] == b && rgba[3] == a)
+ return;
+
+ ctx_process (ctx, &command);
+#else
+ ctx_rgba (ctx, r/255.0f, g/255.0f, b/255.0f, a/255.0f);
#endif
-#if CTX_RASTERIZER_FORCE_AA==0
- if (abs(dx_dy)> CTX_RASTERIZER_AA_SLOPE_LIMIT)
- { rasterizer->needs_aa ++; }
+}
- if ((miny > rasterizer->scanline) )
- {
- /* it is a pending edge - we add it to the end of the array
- and keep a different count for items stored here, like
- a heap and stack growing against each other
- */
- if (rasterizer->pending_edges < CTX_MAX_PENDING-1)
- {
- rasterizer->edges[CTX_MAX_EDGES-1-rasterizer->pending_edges] =
- rasterizer->edges[no];
- rasterizer->pending_edges++;
- rasterizer->active_edges--;
- }
- }
-#endif
- }
- }
- rasterizer->edge_pos++;
- }
-}
-
-CTX_INLINE static int ctx_compare_edges2 (const void *ap, const void *bp)
-{
- const CtxEdge *a = (const CtxEdge *) ap;
- const CtxEdge *b = (const CtxEdge *) bp;
- return a->x - b->x;
-}
-
-CTX_INLINE static int ctx_edge2_qsort_partition (CtxEdge *A, int low, int high)
+void ctx_rgba8_stroke (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
- CtxEdge pivot = A[ (high+low) /2];
- int i = low;
- int j = high;
- while (i <= j)
- {
- while (ctx_compare_edges2 (&A[i], &pivot) <0) { i ++; }
- while (ctx_compare_edges2 (&pivot, &A[j]) <0) { j --; }
- if (i <= j)
- {
- CtxEdge tmp = A[i];
- A[i] = A[j];
- A[j] = tmp;
- i++;
- j--;
- }
- }
- return i;
+ ctx_rgba_stroke (ctx, r/255.0f, g/255.0f, b/255.0f, a/255.0f);
}
-static void ctx_edge2_qsort (CtxEdge *entries, int low, int high)
-{
- {
- int p = ctx_edge2_qsort_partition (entries, low, high);
- if (low < p -1 )
- { ctx_edge2_qsort (entries, low, p - 1); }
- if (low < high)
- { ctx_edge2_qsort (entries, p, high); }
- }
-}
+#endif
-static void ctx_rasterizer_sort_active_edges (CtxRasterizer *rasterizer)
+#if CTX_BABL
+void ctx_rasterizer_colorspace_babl (CtxState *state,
+ CtxColorSpace space_slot,
+ const Babl *space)
{
- CtxEdge *edges = rasterizer->edges;
- /* we use sort networks for the very frequent cases of few active edges
- * the built in qsort is fast, but sort networks are even faster
- */
- switch (rasterizer->active_edges)
+ switch (space_slot)
{
- case 0:
- case 1: break;
-#if CTX_BLOATY_FAST_PATHS
- case 2:
-#define COMPARE(a,b) \
- if (ctx_compare_edges2 (&edges[a], &edges[b])>0)\
- {\
- CtxEdge tmp = edges[a];\
- edges[a] = edges[b];\
- edges[b] = tmp;\
- }
- COMPARE(0,1);
- break;
- case 3:
- COMPARE(0,1); COMPARE(0,2); COMPARE(1,2);
+ case CTX_COLOR_SPACE_DEVICE_RGB:
+ state->gstate.device_space = space;
break;
- case 4:
- COMPARE(0,1); COMPARE(2,3); COMPARE(0,2); COMPARE(1,3); COMPARE(1,2);
+ case CTX_COLOR_SPACE_DEVICE_CMYK:
+ state->gstate.device_space = space;
break;
- case 5:
- COMPARE(1,2); COMPARE(0,2); COMPARE(0,1); COMPARE(3,4); COMPARE(0,3);
- COMPARE(1,4); COMPARE(2,4); COMPARE(1,3); COMPARE(2,3);
+ case CTX_COLOR_SPACE_USER_RGB:
+ state->gstate.rgb_space = space;
break;
- case 6:
- COMPARE(1,2); COMPARE(0,2); COMPARE(0,1); COMPARE(4,5);
- COMPARE(3,5); COMPARE(3,4); COMPARE(0,3); COMPARE(1,4);
- COMPARE(2,5); COMPARE(2,4); COMPARE(1,3); COMPARE(2,3);
+ case CTX_COLOR_SPACE_USER_CMYK:
+ state->gstate.cmyk_space = space;
break;
-#endif
- default:
- ctx_edge2_qsort (&edges[0], 0, rasterizer->active_edges-1);
+ case CTX_COLOR_SPACE_TEXTURE:
+ state->gstate.texture_space = space;
break;
}
+
+ const Babl *srgb = babl_space ("sRGB");
+ if (!state->gstate.texture_space)
+ state->gstate.texture_space = srgb;
+ if (!state->gstate.device_space)
+ state->gstate.device_space = srgb;
+ if (!state->gstate.rgb_space)
+ state->gstate.rgb_space = srgb;
+
+ //fprintf (stderr, "%s\n", babl_get_name (state->gstate.device_space));
+
+ state->gstate.fish_rgbaf_device_to_user = babl_fish (
+ babl_format_with_space ("R'G'B'A float", state->gstate.device_space),
+ babl_format_with_space ("R'G'B'A float", state->gstate.rgb_space));
+ state->gstate.fish_rgbaf_user_to_device = babl_fish (
+ babl_format_with_space ("R'G'B'A float", state->gstate.rgb_space),
+ babl_format_with_space ("R'G'B'A float", state->gstate.device_space));
+ state->gstate.fish_rgbaf_texture_to_device = babl_fish (
+ babl_format_with_space ("R'G'B'A float", state->gstate.texture_space),
+ babl_format_with_space ("R'G'B'A float", state->gstate.device_space));
}
+#endif
-inline static void
-ctx_rasterizer_generate_coverage (CtxRasterizer *rasterizer,
- int minx,
- int maxx,
- uint8_t *coverage,
- int winding,
- int aa_factor)
+void ctx_rasterizer_colorspace_icc (CtxState *state,
+ CtxColorSpace space_slot,
+ char *icc_data,
+ int icc_length)
{
- CtxEntry *entries = rasterizer->edge_list.entries;;
- CtxEdge *edges = rasterizer->edges;
- int scanline = rasterizer->scanline;
- int active_edges = rasterizer->active_edges;
- int parity = 0;
- int fraction = 255/aa_factor;
- coverage -= minx;
-#define CTX_EDGE(no) entries[edges[no].index]
-#define CTX_EDGE_YMIN(no) CTX_EDGE(no).data.s16[1]
-#define CTX_EDGE_X(no) (rasterizer->edges[no].x)
- for (int t = 0; t < active_edges -1;)
- {
- int ymin = CTX_EDGE_YMIN (t);
- int next_t = t + 1;
- if (scanline != ymin)
- {
- if (winding)
- { parity += ( (CTX_EDGE (t).code == CTX_EDGE_FLIPPED) ?1:-1); }
- else
- { parity = 1 - parity; }
- }
- if (parity)
- {
- int x0 = CTX_EDGE_X (t) / CTX_SUBDIV ;
- int x1 = CTX_EDGE_X (next_t) / CTX_SUBDIV ;
- int first = x0 / CTX_RASTERIZER_EDGE_MULTIPLIER;
- int last = x1 / CTX_RASTERIZER_EDGE_MULTIPLIER;
-
- int graystart = 255 - ( (x0 * 256/CTX_RASTERIZER_EDGE_MULTIPLIER) & 0xff);
- int grayend = (x1 * 256/CTX_RASTERIZER_EDGE_MULTIPLIER) & 0xff;
+#if CTX_BABL
+ const char *error = NULL;
+ const Babl *space = NULL;
- if (first < minx)
- { first = minx;
- graystart=255;
- }
- if (last > maxx)
- { last = maxx;
- grayend=255;
- }
- if (first == last)
- {
- coverage[first] += (graystart-(255-grayend))/ aa_factor;
- }
- else if (first < last)
- {
- /*
- if (aa_factor == 1)
- {
- coverage[first] += graystart;
- for (int x = first + 1; x < last; x++)
- coverage[x] = 255;
- coverage[last] = grayend;
- }
- else
- */
- {
- coverage[first] += graystart/ aa_factor;
- for (int x = first + 1; x < last; x++)
- coverage[x] += fraction;
- coverage[last] += grayend/ aa_factor;
- }
- }
- }
- t = next_t;
- }
+ if (icc_data == NULL) space = babl_space ("sRGB");
+ else if (icc_length < 16)
+ {
+ char tmp[24];
+ int i;
+ 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_ENABLE_SHADOW_BLUR
- if (rasterizer->in_shadow)
- {
- float radius = rasterizer->state->gstate.shadow_blur;
- int dim = 2 * radius + 1;
- if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
- dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
- {
- uint16_t temp[maxx-minx+1];
- memset (temp, 0, sizeof (temp));
- for (int x = dim/2; x < maxx-minx + 1 - dim/2; x ++)
- for (int u = 0; u < dim; u ++)
- {
- temp[x] += coverage[minx+x+u-dim/2] * rasterizer->kernel[u] * 256;
- }
- for (int x = 0; x < maxx-minx + 1; x ++)
- coverage[minx+x] = temp[x] >> 8;
- }
- }
+ if (!space)
+ {
+ space = babl_space_from_icc (icc_data, icc_length, BABL_ICC_INTENT_RELATIVE_COLORIMETRIC, &error);
+ }
+ if (space)
+ {
+ ctx_rasterizer_colorspace_babl (state, space_slot, space);
+ }
#endif
+}
-#if CTX_ENABLE_CLIP
- if (rasterizer->clip_buffer)
+void ctx_colorspace (Ctx *ctx,
+ CtxColorSpace space_slot,
+ unsigned char *data,
+ int data_length)
+{
+ if (data)
{
- /* perhaps not working right for clear? */
- int y = scanline / rasterizer->aa;
- uint8_t *clip_line = &((uint8_t*)(rasterizer->clip_buffer->data))[rasterizer->blit_width*y];
- // XXX SIMD candidate
- for (int x = minx; x <= maxx; x ++)
- {
-#if CTX_1BIT_CLIP
- coverage[x] = (coverage[x] * ((clip_line[x/8]&(1<<(x%8)))?255:0))/255;
-#else
- coverage[x] = (coverage[x] * clip_line[x])/255;
-#endif
- }
+ if (data_length <= 0) data_length = (int)strlen ((char*)data);
+ ctx_process_cmd_str_with_len (ctx, CTX_COLOR_SPACE, (char*)data, space_slot, 0, data_length);
}
- if (rasterizer->aa == 1)
+ else
{
- for (int x = minx; x <= maxx; x ++)
- coverage[x] = coverage[x] > 127?255:0;
+ ctx_process_cmd_str_with_len (ctx, CTX_COLOR_SPACE, "sRGB", space_slot, 0, 4);
}
-#endif
}
-#undef CTX_EDGE_Y0
-#undef CTX_EDGE
-
-static void
-ctx_rasterizer_reset (CtxRasterizer *rasterizer)
+void ctx_gradient_add_stop_u8
+(Ctx *ctx, float pos, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
-#if CTX_RASTERIZER_FORCE_AA==0
- rasterizer->pending_edges = 0;
-#endif
- rasterizer->active_edges = 0;
- rasterizer->has_shape = 0;
- rasterizer->has_prev = 0;
- rasterizer->edge_list.count = 0; // ready for new edges
- rasterizer->edge_pos = 0;
- rasterizer->needs_aa = 0;
- rasterizer->scanline = 0;
- if (!rasterizer->preserve)
- {
- rasterizer->scan_min = 5000;
- rasterizer->scan_max = -5000;
- rasterizer->col_min = 5000;
- rasterizer->col_max = -5000;
- }
- //rasterizer->comp_op = NULL;
+ CtxEntry entry = ctx_f (CTX_GRADIENT_STOP, pos, 0);
+ entry.data.u8[4+0] = r;
+ entry.data.u8[4+1] = g;
+ entry.data.u8[4+2] = b;
+ entry.data.u8[4+3] = a;
+ ctx_process (ctx, &entry);
}
-static void
-ctx_rasterizer_rasterize_edges (CtxRasterizer *rasterizer, int winding
-#if CTX_SHAPE_CACHE
- ,CtxShapeEntry *shape
-#endif
- )
+void ctx_gradient_add_stop
+(Ctx *ctx, float pos, float r, float g, float b, float a)
{
- uint8_t *dst = ( (uint8_t *) rasterizer->buf);
- int aa = rasterizer->aa;
-
- int scan_start = rasterizer->blit_y * aa;
- int scan_end = scan_start + rasterizer->blit_height * aa;
- int blit_width = rasterizer->blit_width;
- int blit_max_x = rasterizer->blit_x + blit_width;
- int minx = rasterizer->col_min / CTX_SUBDIV - rasterizer->blit_x;
- int maxx = (rasterizer->col_max + CTX_SUBDIV-1) / CTX_SUBDIV - rasterizer->blit_x;
+ int ir = r * 255;
+ int ig = g * 255;
+ int ib = b * 255;
+ int ia = a * 255;
+ ir = CTX_CLAMP (ir, 0,255);
+ ig = CTX_CLAMP (ig, 0,255);
+ ib = CTX_CLAMP (ib, 0,255);
+ ia = CTX_CLAMP (ia, 0,255);
+ ctx_gradient_add_stop_u8 (ctx, pos, ir, ig, ib, ia);
+}
-#if 1
- if (
-#if CTX_SHAPE_CACHE
- !shape &&
-#endif
- maxx > blit_max_x - 1)
- { maxx = blit_max_x - 1; }
-#endif
-#if 1
- if (rasterizer->state->gstate.clip_min_x>
- minx)
- { minx = rasterizer->state->gstate.clip_min_x; }
- if (rasterizer->state->gstate.clip_max_x <
- maxx)
- { maxx = rasterizer->state->gstate.clip_max_x; }
-#endif
- if (minx < 0)
- { minx = 0; }
- if (minx >= maxx)
- {
- ctx_rasterizer_reset (rasterizer);
- return;
- }
-#if CTX_SHAPE_CACHE
- uint8_t _coverage[shape?2:maxx-minx+1];
-#else
- uint8_t _coverage[maxx-minx+1];
-#endif
- uint8_t *coverage = &_coverage[0];
+void ctx_gradient_add_stop_string
+(Ctx *ctx, float pos, const char *string)
+{
+ CtxColor color = {0,};
+ ctx_color_set_from_string (ctx, &color, string);
+ float rgba[4];
+ ctx_color_get_rgba (&(ctx->state), &color, rgba);
+ ctx_gradient_add_stop (ctx, pos, rgba[0], rgba[1], rgba[2], rgba[3]);
+}
- ctx_compositor_setup_default (rasterizer);
+// deviceRGB .. settable when creating an RGB image surface..
+// queryable when running in terminal - is it really needed?
+// though it is settable ; and functional for changing this state at runtime..
+//
+// userRGB - settable at any time, stored in save|restore
+// texture - set as the space of data on subsequent
-#if CTX_SHAPE_CACHE
- if (shape)
- {
- coverage = &shape->data[0];
- }
-#endif
- ctx_assert (coverage);
- rasterizer->scan_min -= (rasterizer->scan_min % aa);
-#if CTX_SHAPE_CACHE
- if (shape)
- {
- scan_start = rasterizer->scan_min;
- scan_end = rasterizer->scan_max;
- }
- else
-#endif
+float ctx_state_get (CtxState *state, uint64_t hash)
+{
+ for (int i = state->gstate.keydb_pos-1; i>=0; i--)
{
- if (rasterizer->scan_min > scan_start)
- {
- dst += (rasterizer->blit_stride * (rasterizer->scan_min-scan_start) / aa);
- scan_start = rasterizer->scan_min;
- }
- if (rasterizer->scan_max < scan_end)
- { scan_end = rasterizer->scan_max; }
- }
- if (rasterizer->state->gstate.clip_min_y * aa > scan_start )
- {
- dst += (rasterizer->blit_stride * (rasterizer->state->gstate.clip_min_y * aa -scan_start) / aa);
- scan_start = rasterizer->state->gstate.clip_min_y * aa;
+ if (state->keydb[i].key == hash)
+ { return state->keydb[i].value; }
}
- if (rasterizer->state->gstate.clip_max_y * aa < scan_end)
- { scan_end = rasterizer->state->gstate.clip_max_y * aa; }
- if (scan_start > scan_end ||
- (scan_start > (rasterizer->blit_y + rasterizer->blit_height) * aa) ||
- (scan_end < (rasterizer->blit_y) * aa))
- {
- /* not affecting this rasterizers scanlines */
- ctx_rasterizer_reset (rasterizer);
- return;
- }
- ctx_rasterizer_sort_edges (rasterizer);
- if (maxx>minx)
- {
-#if CTX_RASTERIZER_FORCE_AA==0
- int halfstep2 = aa/2;
- int halfstep = aa/2 + 1;
-#endif
- rasterizer->needs_aa = 0;
- rasterizer->scanline = scan_start-aa*200;
- ctx_rasterizer_feed_edges (rasterizer);
- ctx_rasterizer_discard_edges (rasterizer);
- ctx_rasterizer_increment_edges (rasterizer, aa * 200);
- rasterizer->scanline = scan_start;
- ctx_rasterizer_feed_edges (rasterizer);
- ctx_rasterizer_discard_edges (rasterizer);
+ return -0.0;
+}
- for (rasterizer->scanline = scan_start; rasterizer->scanline <= scan_end;)
+void ctx_state_set (CtxState *state, uint64_t key, float value)
+{
+ if (key != CTX_new_state)
{
- ctx_memset (coverage, 0,
-#if CTX_SHAPE_CACHE
- shape?shape->width:
-#endif
- sizeof (_coverage) );
-#if CTX_RASTERIZER_FORCE_AA==1
- rasterizer->needs_aa = 1;
-#endif
-
-#if CTX_RASTERIZER_FORCE_AA==0
- if (rasterizer->needs_aa
- || rasterizer->pending_edges
- || rasterizer->ending_edges
- || rasterizer->force_aa
- || aa == 1
- )
-#endif
- {
- for (int i = 0; i < rasterizer->aa; i++)
- {
- ctx_rasterizer_sort_active_edges (rasterizer);
- ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, winding, aa);
- rasterizer->scanline ++;
- ctx_rasterizer_increment_edges (rasterizer, 1);
- ctx_rasterizer_feed_edges (rasterizer);
- ctx_rasterizer_discard_edges (rasterizer);
- }
- }
-#if CTX_RASTERIZER_FORCE_AA==0
- else
- {
- ctx_rasterizer_increment_edges (rasterizer, halfstep);
- ctx_rasterizer_sort_active_edges (rasterizer);
- ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, winding, 1);
- ctx_rasterizer_increment_edges (rasterizer, halfstep2);
- rasterizer->scanline += rasterizer->aa;
- ctx_rasterizer_feed_edges (rasterizer);
- ctx_rasterizer_discard_edges (rasterizer);
- }
-#endif
+ if (ctx_state_get (state, key) == value)
+ { return; }
+ for (int i = state->gstate.keydb_pos-1;
+ state->keydb[i].key != CTX_new_state && i >=0;
+ i--)
{
-#if CTX_SHAPE_CACHE
- if (shape == NULL)
-#endif
+ if (state->keydb[i].key == key)
{
-#if 0
- if (aa==1)
- {
- for (int x = 0; x < maxx-minx; x++)
- coverage
- }
-#endif
- ctx_rasterizer_apply_coverage (rasterizer,
- &dst[(minx * rasterizer->format->bpp) /8],
- minx,
- coverage, maxx-minx + 1);
+ state->keydb[i].value = value;
+ return;
}
}
-#if CTX_SHAPE_CACHE
- if (shape)
- {
- coverage += shape->width;
- }
-#endif
- dst += rasterizer->blit_stride;
}
- }
+ if (state->gstate.keydb_pos >= CTX_MAX_KEYDB)
+ { return; }
+ state->keydb[state->gstate.keydb_pos].key = key;
+ state->keydb[state->gstate.keydb_pos].value = value;
+ state->gstate.keydb_pos++;
+}
- if (rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_OUT ||
- rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_IN ||
- rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_DESTINATION_IN ||
- rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_COPY ||
- rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_DESTINATION_ATOP ||
- rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_CLEAR)
+
+#define CTX_KEYDB_STRING_START (-90000.0)
+#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;
+}
+
+static int ctx_float_to_string_index (float val)
+{
+ int idx = -1;
+ if (ctx_float_is_string (val))
{
- /* fill in the rest of the blitrect when compositing mode permits it */
- uint8_t nocoverage[rasterizer->blit_width];
- //int gscan_start = rasterizer->state->gstate.clip_min_y * aa;
- int gscan_start = rasterizer->state->gstate.clip_min_y * aa;
- int gscan_end = rasterizer->state->gstate.clip_max_y * aa;
- memset (nocoverage, 0, sizeof(nocoverage));
- int startx = rasterizer->state->gstate.clip_min_x;
- int endx = rasterizer->state->gstate.clip_max_x;
- int clipw = endx-startx + 1;
- uint8_t *dst = ( (uint8_t *) rasterizer->buf);
+ idx = val - CTX_KEYDB_STRING_START;
+ }
+ return idx;
+}
- dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (gscan_start / aa);
- for (rasterizer->scanline = gscan_start; rasterizer->scanline < scan_start;)
- {
- ctx_rasterizer_apply_coverage (rasterizer,
- &dst[ (startx * rasterizer->format->bpp) /8],
- 0,
- nocoverage, clipw);
- rasterizer->scanline += aa;
- dst += rasterizer->blit_stride;
- }
- if (minx < startx)
- {
- dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_start / aa);
- for (rasterizer->scanline = scan_start; rasterizer->scanline < scan_end;)
- {
- ctx_rasterizer_apply_coverage (rasterizer,
- &dst[ (startx * rasterizer->format->bpp) /8],
- 0,
- nocoverage, minx-startx);
- dst += rasterizer->blit_stride;
- }
- }
- if (endx > maxx)
- {
- dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_start / aa);
- for (rasterizer->scanline = scan_start; rasterizer->scanline < scan_end;)
- {
- ctx_rasterizer_apply_coverage (rasterizer,
- &dst[ (maxx * rasterizer->format->bpp) /8],
- 0,
- nocoverage, endx-maxx);
-
- rasterizer->scanline += aa;
- dst += rasterizer->blit_stride;
- }
- }
- dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_end / aa);
- // XXX valgrind/asan this
- if(0)for (rasterizer->scanline = scan_end; rasterizer->scanline/aa < gscan_end-1;)
- {
- ctx_rasterizer_apply_coverage (rasterizer,
- &dst[ (startx * rasterizer->format->bpp) /8],
- 0,
- nocoverage, clipw-1);
+static float ctx_string_index_to_float (int index)
+{
+ return CTX_KEYDB_STRING_START + index;
+}
- rasterizer->scanline += aa;
- dst += rasterizer->blit_stride;
- }
+void *ctx_state_get_blob (CtxState *state, uint64_t key)
+{
+ float stored = ctx_state_get (state, key);
+ int idx = ctx_float_to_string_index (stored);
+ if (idx >= 0)
+ {
+ // can we know length?
+ return &state->stringpool[idx];
}
- ctx_rasterizer_reset (rasterizer);
+
+ // format number as string?
+ return NULL;
+}
+
+const char *ctx_state_get_string (CtxState *state, uint64_t key)
+{
+ const char *ret = (char*)ctx_state_get_blob (state, key);
+ if (ret && ret[0] == 127)
+ return NULL;
+ return ret;
}
-static int
-ctx_rasterizer_fill_rect (CtxRasterizer *rasterizer,
- int x0,
- int y0,
- int x1,
- int y1)
+static void ctx_state_set_blob (CtxState *state, uint64_t key, uint8_t *data, int len)
{
- int aa = rasterizer->aa;
- if (x0>x1) { // && y0>y1) {
- int tmp = x1;
- x1 = x0;
- x0 = tmp;
- tmp = y1;
- y1 = y0;
- y0 = tmp;
- }
- if (x1 % CTX_SUBDIV ||
- x0 % CTX_SUBDIV ||
- y1 % aa ||
- y0 % aa)
- { return 0; }
- x1 /= CTX_SUBDIV;
- x0 /= CTX_SUBDIV;
- y1 /= aa;
- y0 /= aa;
- uint8_t coverage[x1-x0 + 1];
- uint8_t *dst = ( (uint8_t *) rasterizer->buf);
- ctx_compositor_setup_default (rasterizer);
- ctx_memset (coverage, 0xff, sizeof (coverage) );
- if (x0 < rasterizer->blit_x)
- { x0 = rasterizer->blit_x; }
- if (y0 < rasterizer->blit_y)
- { y0 = rasterizer->blit_y; }
- if (y1 > rasterizer->blit_y + rasterizer->blit_height)
- { y1 = rasterizer->blit_y + rasterizer->blit_height; }
- if (x1 > rasterizer->blit_x + rasterizer->blit_width)
- { x1 = rasterizer->blit_x + rasterizer->blit_width; }
- dst += (y0 - rasterizer->blit_y) * rasterizer->blit_stride;
- int width = x1 - x0;
- if (width > 0)
+ int idx = state->gstate.stringpool_pos;
+
+ if (idx + len > CTX_STRINGPOOL_SIZE)
+ {
+ ctx_log ("blowing varpool size [%c..]\n", data[0]);
+ //fprintf (stderr, "blowing varpool size [%c%c%c..]\n", data[0],data[1], data[1]?data[2]:0);
+#if 0
+ for (int i = 0; i< CTX_STRINGPOOL_SIZE; i++)
{
- rasterizer->scanline = y0 * aa;
- for (int y = y0; y < y1; y++)
- {
- rasterizer->scanline += aa;
- ctx_rasterizer_apply_coverage (rasterizer,
- &dst[ (x0) * rasterizer->format->bpp/8],
- x0,
- coverage, width);
- dst += rasterizer->blit_stride;
- }
+ if (i==0) fprintf (stderr, "\n%i ", i);
+ else fprintf (stderr, "%c", state->stringpool[i]);
}
- return 1;
+#endif
+ return;
+ }
+
+ memcpy (&state->stringpool[idx], data, len);
+ state->gstate.stringpool_pos+=len;
+ state->stringpool[state->gstate.stringpool_pos++]=0;
+ ctx_state_set (state, key, ctx_string_index_to_float (idx));
}
-inline static int
-ctx_is_transparent (CtxRasterizer *rasterizer)
+static void ctx_state_set_string (CtxState *state, uint64_t key, const char *string)
{
- CtxGState *gstate = &rasterizer->state->gstate;
- if (gstate->global_alpha_u8 == 0)
- return 1;
- if (gstate->source.type == CTX_SOURCE_COLOR)
+ float old_val = ctx_state_get (state, key);
+ int old_idx = ctx_float_to_string_index (old_val);
+
+ if (old_idx >= 0)
{
- uint8_t ga[2];
- ctx_color_get_graya_u8 (rasterizer->state, &gstate->source.color, ga);
- if (ga[1] == 0)
- return 1;
+ const char *old_string = ctx_state_get_string (state, key);
+ if (old_string && !strcmp (old_string, string))
+ return;
}
- return 0;
+
+ if (ctx_str_is_number (string))
+ {
+ ctx_state_set (state, key, strtod (string, NULL));
+ return;
+ }
+ // should do same with color
+
+ // XXX should special case when the string modified is at the
+ // end of the stringpool.
+ //
+ // 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));
}
-static void
-ctx_rasterizer_fill (CtxRasterizer *rasterizer)
+static int ctx_state_get_color (CtxState *state, uint64_t key, CtxColor *color)
{
- int count = rasterizer->preserve?rasterizer->edge_list.count:0;
- int aa = rasterizer->aa;
-
- CtxEntry temp[count]; /* copy of already built up path's poly line
- XXX - by building a large enough path
- the stack can be smashed!
- */
- if (rasterizer->preserve)
- { memcpy (temp, rasterizer->edge_list.entries, sizeof (temp) ); }
-
-#if CTX_ENABLE_SHADOW_BLUR
- if (rasterizer->in_shadow)
+ CtxColor *stored = (CtxColor*)ctx_state_get_blob (state, key);
+ if (stored)
{
- for (int i = 0; i < rasterizer->edge_list.count; i++)
+ if (stored->magic == 127)
{
- CtxEntry *entry = &rasterizer->edge_list.entries[i];
- entry->data.s16[2] += rasterizer->shadow_x * CTX_SUBDIV;
- entry->data.s16[3] += rasterizer->shadow_y * aa;
+ *color = *stored;
+ return 0;
}
- rasterizer->scan_min += rasterizer->shadow_y * aa;
- rasterizer->scan_max += rasterizer->shadow_y * aa;
- rasterizer->col_min += (rasterizer->shadow_x - rasterizer->state->gstate.shadow_blur * 3 + 1) *
CTX_SUBDIV;
- rasterizer->col_max += (rasterizer->shadow_x + rasterizer->state->gstate.shadow_blur * 3 + 1) *
CTX_SUBDIV;
}
-#endif
+ return -1;
+}
- if (ctx_is_transparent (rasterizer) ||
- rasterizer->scan_min / aa > rasterizer->blit_y + rasterizer->blit_height ||
- rasterizer->scan_max / aa < rasterizer->blit_y ||
- rasterizer->col_min / CTX_SUBDIV > rasterizer->blit_x + rasterizer->blit_width ||
- rasterizer->col_max / CTX_SUBDIV < rasterizer->blit_x)
- {
- ctx_rasterizer_reset (rasterizer);
- }
- else
+static void ctx_state_set_color (CtxState *state, uint64_t key, CtxColor *color)
+{
+ CtxColor mod_color;
+ CtxColor old_color;
+ mod_color = *color;
+ mod_color.magic = 127;
+ if (ctx_state_get_color (state, key, &old_color)==0)
{
- ctx_compositor_setup_default (rasterizer);
-
- rasterizer->state->min_x =
- ctx_mini (rasterizer->state->min_x, rasterizer->col_min / CTX_SUBDIV);
- rasterizer->state->max_x =
- ctx_maxi (rasterizer->state->max_x, rasterizer->col_max / CTX_SUBDIV);
- rasterizer->state->min_y =
- ctx_mini (rasterizer->state->min_y, rasterizer->scan_min / aa);
- rasterizer->state->max_y =
- ctx_maxi (rasterizer->state->max_y, rasterizer->scan_max / aa);
- if (rasterizer->edge_list.count == 6)
- {
- CtxEntry *entry0 = &rasterizer->edge_list.entries[0];
- CtxEntry *entry1 = &rasterizer->edge_list.entries[1];
- CtxEntry *entry2 = &rasterizer->edge_list.entries[2];
- CtxEntry *entry3 = &rasterizer->edge_list.entries[3];
- if (!rasterizer->state->gstate.clipped &&
- (entry0->data.s16[2] == entry1->data.s16[2]) &&
- (entry0->data.s16[3] == entry3->data.s16[3]) &&
- (entry1->data.s16[3] == entry2->data.s16[3]) &&
- (entry2->data.s16[2] == entry3->data.s16[2]) &&
- ((entry3->data.s16[2] & (CTX_SUBDIV-1)) == 0) &&
- ((entry3->data.s16[3] & (aa-1)) == 0)
-#if CTX_ENABLE_SHADOW_BLUR
- && !rasterizer->in_shadow
-#endif
- )
- if (ctx_rasterizer_fill_rect (rasterizer,
- entry3->data.s16[2],
- entry3->data.s16[3],
- entry1->data.s16[2],
- entry1->data.s16[3]) )
- {
- ctx_rasterizer_reset (rasterizer);
- goto done;
- }
- }
- ctx_rasterizer_finish_shape (rasterizer);
-
- uint32_t hash = ctx_rasterizer_poly_to_edges (rasterizer);
+ if (!memcmp (&mod_color, &old_color, sizeof (mod_color)))
+ return;
+ }
+ ctx_state_set_blob (state, key, (uint8_t*)&mod_color, sizeof (CtxColor));
+}
-#if CTX_SHAPE_CACHE
- int width = (rasterizer->col_max + (CTX_SUBDIV-1) ) / CTX_SUBDIV - rasterizer->col_min/CTX_SUBDIV + 1;
- int height = (rasterizer->scan_max + (aa-1) ) / aa - rasterizer->scan_min / aa + 1;
- if (width * height < CTX_SHAPE_CACHE_DIM && width >=1 && height >= 1
- && width < CTX_SHAPE_CACHE_MAX_DIM
- && height < CTX_SHAPE_CACHE_MAX_DIM
- && !rasterizer->state->gstate.clipped // XXX - this causes any clipping, also rectangular -
- // to disable caching
-#if CTX_ENABLE_SHADOW_BLUR
- && !rasterizer->in_shadow
-#endif
- )
- {
- int scan_min = rasterizer->scan_min;
- int col_min = rasterizer->col_min;
- scan_min -= (scan_min % aa);
- int y0 = scan_min / aa;
- int y1 = y0 + height;
- int x0 = col_min / CTX_SUBDIV;
- int ymin = y0;
- int x1 = x0 + width;
- int clip_x_min = rasterizer->blit_x;
- int clip_x_max = rasterizer->blit_x + rasterizer->blit_width - 1;
- int clip_y_min = rasterizer->blit_y;
- int clip_y_max = rasterizer->blit_y + rasterizer->blit_height - 1;
-
- int dont_cache = 0;
- if (x1 >= clip_x_max)
- { x1 = clip_x_max;
- dont_cache = 1;
- }
- int xo = 0;
- if (x0 < clip_x_min)
- {
- xo = clip_x_min - x0;
- x0 = clip_x_min;
- dont_cache = 1;
- }
- if (y0 < clip_y_min || y1 >= clip_y_max)
- dont_cache = 1;
- if (dont_cache)
- {
- ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule
-#if CTX_SHAPE_CACHE
- , NULL
-#endif
- );
- }
- else
- {
-
- rasterizer->scanline = scan_min;
- CtxShapeEntry *shape = ctx_shape_entry_find (rasterizer, hash, width, height);
-
- if (shape->uses == 0)
- {
- ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule, shape);
- }
- rasterizer->scanline = scan_min;
-
- int ewidth = x1 - x0;
- if (ewidth>0)
- for (int y = y0; y < y1; y++)
- {
- if ( (y >= clip_y_min) && (y <= clip_y_max) )
- {
- ctx_rasterizer_apply_coverage (rasterizer,
- ( (uint8_t *) rasterizer->buf) + (y-rasterizer->blit_y) *
rasterizer->blit_stride + (int) (x0) * rasterizer->format->bpp/8,
- x0,
- &shape->data[shape->width * (int) (y-ymin) + xo],
- ewidth );
- }
- rasterizer->scanline += aa;
- }
- if (shape->uses != 0)
- {
- ctx_rasterizer_reset (rasterizer);
- }
- }
- }
- else
-#endif
- ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule
-#if CTX_SHAPE_CACHE
- , NULL
-#endif
- );
- }
- done:
- if (rasterizer->preserve)
- {
- memcpy (rasterizer->edge_list.entries, temp, sizeof (temp) );
- rasterizer->edge_list.count = count;
- }
-#if CTX_ENABLE_SHADOW_BLUR
- if (rasterizer->in_shadow)
- {
- rasterizer->scan_min -= rasterizer->shadow_y * aa;
- rasterizer->scan_max -= rasterizer->shadow_y * aa;
- rasterizer->col_min -= (rasterizer->shadow_x - rasterizer->state->gstate.shadow_blur * 3 + 1) *
CTX_SUBDIV;
- rasterizer->col_max -= (rasterizer->shadow_x + rasterizer->state->gstate.shadow_blur * 3 + 1) *
CTX_SUBDIV;
- }
-#endif
- rasterizer->preserve = 0;
+const char *ctx_get_string (Ctx *ctx, uint64_t hash)
+{
+ return ctx_state_get_string (&ctx->state, hash);
}
-
-#if 0
-static void
-ctx_rasterizer_triangle (CtxRasterizer *rasterizer,
- int x0, int y0,
- int x1, int y1,
- int x2, int y2,
- int r0, int g0, int b0, int a0,
- int r1, int g1, int b1, int a1,
- int r2, int g2, int b2, int a2,
- int u0, int v0,
- int u1, int v1)
+float ctx_get_float (Ctx *ctx, uint64_t hash)
{
-
+ return ctx_state_get (&ctx->state, hash);
}
-#endif
-
-static int _ctx_glyph (Ctx *ctx, uint32_t unichar, int stroke);
-static void
-ctx_rasterizer_glyph (CtxRasterizer *rasterizer, uint32_t unichar, int stroke)
+int ctx_get_int (Ctx *ctx, uint64_t hash)
{
- float tx = rasterizer->state->x;
- float ty = rasterizer->state->y - rasterizer->state->gstate.font_size;
- float tx2 = rasterizer->state->x + rasterizer->state->gstate.font_size;
- float ty2 = rasterizer->state->y + rasterizer->state->gstate.font_size;
- _ctx_user_to_device (rasterizer->state, &tx, &ty);
- _ctx_user_to_device (rasterizer->state, &tx2, &ty2);
-
- if (tx2 < rasterizer->blit_x || ty2 < rasterizer->blit_y) return;
- if (tx > rasterizer->blit_x + rasterizer->blit_width ||
- ty > rasterizer->blit_y + rasterizer->blit_height)
- return;
- _ctx_glyph (rasterizer->ctx, unichar, stroke);
+ return ctx_state_get (&ctx->state, hash);
}
-
-typedef struct _CtxTermGlyph CtxTermGlyph;
-
-struct _CtxTermGlyph
+void ctx_set_float (Ctx *ctx, uint64_t hash, float value)
{
- uint32_t unichar;
- int col;
- int row;
- uint8_t rgba_bg[4];
- uint8_t rgba_fg[4];
-};
+ ctx_state_set (&ctx->state, hash, value);
+}
+void ctx_set_string (Ctx *ctx, uint64_t hash, const char *value)
+{
+ ctx_state_set_string (&ctx->state, hash, value);
+}
+void ctx_set_color (Ctx *ctx, uint64_t hash, CtxColor *color)
+{
+ ctx_state_set_color (&ctx->state, hash, color);
+}
+int ctx_get_color (Ctx *ctx, uint64_t hash, CtxColor *color)
+{
+ return ctx_state_get_color (&ctx->state, hash, color);
+}
+int ctx_is_set (Ctx *ctx, uint64_t hash)
+{
+ return ctx_get_float (ctx, hash) != -0.0f;
+}
+int ctx_is_set_now (Ctx *ctx, uint64_t hash)
+{
+ return ctx_is_set (ctx, hash);
+}
+#if CTX_RASTERIZER
-static void
-_ctx_text (Ctx *ctx,
- const char *string,
- int stroke,
- int visible);
-static void
-ctx_rasterizer_text (CtxRasterizer *rasterizer, const char *string, int stroke)
+void ctx_compositor_setup_default (CtxRasterizer *rasterizer);
+
+inline static void
+ctx_rasterizer_apply_coverage (CtxRasterizer *rasterizer,
+ uint8_t * __restrict__ dst,
+ int x,
+ uint8_t * __restrict__ coverage,
+ int count)
{
-#if CTX_BRAILLE_TEXT
- if (rasterizer->term_glyphs && !stroke)
- {
- int col = rasterizer->x / 2 + 1;
- int row = rasterizer->y / 4 + 1;
- for (int i = 0; string[i]; i++, col++)
- {
- CtxTermGlyph *glyph = ctx_calloc (sizeof (CtxTermGlyph), 1);
- ctx_list_prepend (&rasterizer->glyphs, glyph);
- glyph->unichar = string[i];
- glyph->col = col;
- glyph->row = row;
- ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source.color,
- glyph->rgba_fg);
- }
- //_ctx_text (rasterizer->ctx, string, stroke, 1);
- }
+ if (rasterizer->format->apply_coverage)
+ rasterizer->format->apply_coverage(rasterizer, dst, rasterizer->color, x, coverage, count);
else
-#endif
- {
- _ctx_text (rasterizer->ctx, string, stroke, 1);
- }
+ rasterizer->comp_op (rasterizer, dst, rasterizer->color, x, coverage, count);
}
-void
-_ctx_font (Ctx *ctx, const char *name);
static void
-ctx_rasterizer_set_font (CtxRasterizer *rasterizer, const char *font_name)
+ctx_rasterizer_gradient_add_stop (CtxRasterizer *rasterizer, float pos, float *rgba)
{
- _ctx_font (rasterizer->ctx, font_name);
+ CtxGradient *gradient = &rasterizer->state->gradient;
+ 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
+ { gradient->n_stops++; }
}
-static void
-ctx_rasterizer_arc (CtxRasterizer *rasterizer,
- float x,
- float y,
- float radius,
- float start_angle,
- float end_angle,
- int anticlockwise)
+static int ctx_rasterizer_add_point (CtxRasterizer *rasterizer, int x1, int y1)
{
- int full_segments = CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS;
- full_segments = radius * CTX_PI;
- if (full_segments > CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS)
- { full_segments = CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS; }
- float step = CTX_PI*2.0/full_segments;
- int steps;
+ CtxEntry entry = {CTX_EDGE, {{0},}};
+ if (y1 < rasterizer->scan_min)
+ { rasterizer->scan_min = y1; }
+ if (y1 > rasterizer->scan_max)
+ { rasterizer->scan_max = y1; }
- if (end_angle < -10.0)
- end_angle = -10.0;
- if (start_angle < -10.0)
- start_angle = -10.0;
- if (end_angle > 10.0)
- end_angle = 10.0;
- if (start_angle > 10.0)
- start_angle = 10.0;
+ if (x1 < rasterizer->col_min)
+ { rasterizer->col_min = x1; }
+ if (x1 > rasterizer->col_max)
+ { rasterizer->col_max = x1; }
- if (radius <= 0.0001)
- return;
+ entry.data.s16[2]=x1;
+ entry.data.s16[3]=y1;
+ return ctx_drawlist_add_single (&rasterizer->edge_list, &entry);
+}
- if (end_angle == start_angle)
- // XXX also detect arcs fully outside render view
- {
- if (rasterizer->has_prev!=0)
- ctx_rasterizer_line_to (rasterizer, x + ctx_cosf (end_angle) * radius,
- y + ctx_sinf (end_angle) * radius);
- else
- ctx_rasterizer_move_to (rasterizer, x + ctx_cosf (end_angle) * radius,
- y + ctx_sinf (end_angle) * radius);
- return;
- }
#if 0
- if ( (!anticlockwise && (end_angle - start_angle >= CTX_PI*2) ) ||
- ( (anticlockwise && (start_angle - end_angle >= CTX_PI*2) ) ) )
- {
- end_angle = start_angle;
- steps = full_segments - 1;
- }
- else
+#define CTX_SHAPE_CACHE_PRIME1 7853
+#define CTX_SHAPE_CACHE_PRIME2 4129
+#define CTX_SHAPE_CACHE_PRIME3 3371
+#define CTX_SHAPE_CACHE_PRIME4 4221
+#else
+#define CTX_SHAPE_CACHE_PRIME1 283
+#define CTX_SHAPE_CACHE_PRIME2 599
+#define CTX_SHAPE_CACHE_PRIME3 101
+#define CTX_SHAPE_CACHE_PRIME4 661
#endif
+
+float ctx_shape_cache_rate = 0.0;
+#if CTX_SHAPE_CACHE
+
+//static CtxShapeCache ctx_cache = {{NULL,}, 0};
+
+static long hits = 0;
+static long misses = 0;
+
+
+/* this returns the buffer to use for rendering, it always
+ succeeds..
+ */
+static CtxShapeEntry *ctx_shape_entry_find (CtxRasterizer *rasterizer, uint32_t hash, int width, int height)
+{
+ /* use both some high and some low bits */
+ int entry_no = ( (hash >> 10) ^ (hash & 1023) ) % CTX_SHAPE_CACHE_ENTRIES;
+ int i;
+ {
+ static int i = 0;
+ i++;
+ if (i>1000)
+ {
+ ctx_shape_cache_rate = hits * 100.0 / (hits+misses);
+ i = 0;
+ hits = 0;
+ misses = 0;
+ }
+ }
+// XXX : this 1 one is needed to silence a false positive:
+// ==90718== Invalid write of size 1
+// ==90718== at 0x1189EF: ctx_rasterizer_generate_coverage (ctx.h:4786)
+// ==90718== by 0x118E57: ctx_rasterizer_rasterize_edges (ctx.h:4907)
+//
+ int size = sizeof (CtxShapeEntry) + width * height + 1;
+
+ i = entry_no;
+ if (rasterizer->shape_cache.entries[i])
{
- steps = (end_angle - start_angle) / (CTX_PI*2) * full_segments;
- if (steps > full_segments)
- steps = full_segments;
- if (anticlockwise)
- { steps = full_segments - steps; };
- }
- if (anticlockwise) { step = step * -1; }
- int first = 1;
- if (steps == 0 /* || steps==full_segments -1 || (anticlockwise && steps == full_segments) */)
- {
- float xv = x + ctx_cosf (start_angle) * radius;
- float yv = y + ctx_sinf (start_angle) * radius;
- if (!rasterizer->has_prev)
- { ctx_rasterizer_move_to (rasterizer, xv, yv); }
- first = 0;
+ CtxShapeEntry *entry = rasterizer->shape_cache.entries[i];
+ int old_size = sizeof (CtxShapeEntry) + width + height + 1;
+ if (entry->hash == hash &&
+ entry->width == width &&
+ entry->height == height)
+ {
+ if (entry->uses < 1<<30)
+ { entry->uses++; }
+ hits ++;
+ return entry;
+ }
+
+ if (old_size >= size)
+ {
+ }
+ else
+ {
+ rasterizer->shape_cache.entries[i] = NULL;
+ rasterizer->shape_cache.size -= entry->width * entry->height;
+ rasterizer->shape_cache.size -= sizeof (CtxShapeEntry);
+ free (entry);
+ rasterizer->shape_cache.entries[i] =(CtxShapeEntry *) calloc (size, 1);
+ }
}
else
{
- for (float angle = start_angle, i = 0; i < steps; angle += step, i++)
- {
- float xv = x + ctx_cosf (angle) * radius;
- float yv = y + ctx_sinf (angle) * radius;
- if (first && !rasterizer->has_prev)
- { ctx_rasterizer_move_to (rasterizer, xv, yv); }
- else
- { ctx_rasterizer_line_to (rasterizer, xv, yv); }
- first = 0;
- }
+ rasterizer->shape_cache.entries[i] =(CtxShapeEntry *) calloc (size, 1);
}
- ctx_rasterizer_line_to (rasterizer, x + ctx_cosf (end_angle) * radius,
- y + ctx_sinf (end_angle) * radius);
-}
-static void
-ctx_rasterizer_quad_to (CtxRasterizer *rasterizer,
- float cx,
- float cy,
- float x,
- float y)
-{
- /* XXX : it is probably cheaper/faster to do quad interpolation directly -
- * though it will increase the code-size, an
- * alternative is to turn everything into cubic
- * and deal with cubics more directly during
- * rasterization
- */
- ctx_rasterizer_curve_to (rasterizer,
- (cx * 2 + rasterizer->x) / 3.0f, (cy * 2 + rasterizer->y) / 3.0f,
- (cx * 2 + x) / 3.0f, (cy * 2 + y) / 3.0f,
- x, y);
+ misses ++;
+
+ rasterizer->shape_cache.size += size;
+ rasterizer->shape_cache.entries[i]->hash=hash;
+ rasterizer->shape_cache.entries[i]->width=width;
+ rasterizer->shape_cache.entries[i]->height=height;
+ rasterizer->shape_cache.entries[i]->uses = 0;
+ return rasterizer->shape_cache.entries[i];
}
-static void
-ctx_rasterizer_rel_quad_to (CtxRasterizer *rasterizer,
- float cx, float cy,
- float x, float y)
+#endif
+
+static uint32_t ctx_rasterizer_poly_to_hash (CtxRasterizer *rasterizer)
{
- ctx_rasterizer_quad_to (rasterizer, cx + rasterizer->x, cy + rasterizer->y,
- x + rasterizer->x, y + rasterizer->y);
+ int16_t x = 0;
+ int16_t y = 0;
+
+ CtxEntry *entry = &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 (int i = 0; i < rasterizer->edge_list.count; i++)
+ {
+ CtxEntry *entry = &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;
}
-#define LENGTH_OVERSAMPLE 1
-static void
-ctx_rasterizer_pset (CtxRasterizer *rasterizer, int x, int y, uint8_t cov)
+static uint32_t ctx_rasterizer_poly_to_edges (CtxRasterizer *rasterizer)
{
- // XXX - we avoid rendering here x==0 - to keep with
- // an off-by one elsewhere
- //
- // XXX onlt works in rgba8 formats
- if (x <= 0 || y < 0 || x >= rasterizer->blit_width ||
- y >= rasterizer->blit_height)
- { return; }
- uint8_t fg_color[4];
- ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source.color, fg_color);
- uint8_t pixel[4];
- uint8_t *dst = ( (uint8_t *) rasterizer->buf);
- dst += y * rasterizer->blit_stride;
- dst += x * rasterizer->format->bpp / 8;
- if (!rasterizer->format->to_comp ||
- !rasterizer->format->from_comp)
- { return; }
- if (cov == 255)
+ int16_t x = 0;
+ int16_t y = 0;
+ if (rasterizer->edge_list.count == 0)
+ return 0;
+#if CTX_SHAPE_CACHE
+ int aa = rasterizer->aa;
+ CtxEntry *entry = &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 % CTX_SUBDIV);
+ hash *= CTX_SHAPE_CACHE_PRIME1;
+ hash += (oy % aa);
+#endif
+ for (int i = 0; i < rasterizer->edge_list.count; i++)
{
- for (int c = 0; c < 4; c++)
+ CtxEntry *entry = &rasterizer->edge_list.entries[i];
+ if (entry->code == CTX_NEW_EDGE)
{
- pixel[c] = fg_color[c];
+ entry->code = CTX_EDGE;
+#if CTX_SHAPE_CACHE
+ hash *= CTX_SHAPE_CACHE_PRIME2;
+#endif
}
- }
- else
- {
- rasterizer->format->to_comp (rasterizer, x, dst, &pixel[0], 1);
- for (int c = 0; c < 4; c++)
+ else
{
- pixel[c] = ctx_lerp_u8 (pixel[c], fg_color[c], cov);
+ entry->data.s16[0] = x;
+ entry->data.s16[1] = y;
+ }
+ x = entry->data.s16[2];
+ y = entry->data.s16[3];
+#if CTX_SHAPE_CACHE
+ 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;
+#endif
+ if (entry->data.s16[3] < entry->data.s16[1])
+ {
+ *entry = ctx_s16 (CTX_EDGE_FLIPPED,
+ entry->data.s16[2], entry->data.s16[3],
+ entry->data.s16[0], entry->data.s16[1]);
}
}
- rasterizer->format->from_comp (rasterizer, x, &pixel[0], dst, 1);
+#if CTX_SHAPE_CACHE
+ return hash;
+#else
+ return 0;
+#endif
}
-static void
-ctx_rasterizer_stroke_1px (CtxRasterizer *rasterizer)
+static void ctx_rasterizer_line_to (CtxRasterizer *rasterizer, float x, float y);
+
+static void ctx_rasterizer_finish_shape (CtxRasterizer *rasterizer)
{
- int count = rasterizer->edge_list.count;
- CtxEntry *temp = rasterizer->edge_list.entries;
- float prev_x = 0.0f;
- float prev_y = 0.0f;
- int aa = rasterizer->aa;
- int start = 0;
- int end = 0;
-#if 0
- float factor =
- ctx_maxf (ctx_maxf (ctx_fabsf (state->gstate.transform.m[0][0]),
- ctx_fabsf (state->gstate.transform.m[0][1]) ),
- ctx_maxf (ctx_fabsf (state->gstate.transform.m[1][0]),
- ctx_fabsf (state->gstate.transform.m[1][1]) ) );
-#endif
+ if (rasterizer->has_shape && rasterizer->has_prev)
+ {
+ ctx_rasterizer_line_to (rasterizer, rasterizer->first_x, rasterizer->first_y);
+ rasterizer->has_prev = 0;
+ }
+}
- while (start < count)
+static void ctx_rasterizer_move_to (CtxRasterizer *rasterizer, float x, float y)
+{
+ float tx = x; float ty = y;
+ int aa = rasterizer->aa;
+ rasterizer->x = x;
+ rasterizer->y = y;
+ rasterizer->first_x = x;
+ rasterizer->first_y = y;
+ rasterizer->has_prev = -1;
+ if (rasterizer->uses_transforms)
{
- int started = 0;
- int i;
- for (i = start; i < count; i++)
- {
- CtxEntry *entry = &temp[i];
- float x, y;
- if (entry->code == CTX_NEW_EDGE)
- {
- if (started)
- {
- end = i - 1;
- goto foo;
- }
- prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
- prev_y = entry->data.s16[1] * 1.0f / aa;
- started = 1;
- start = i;
- }
- x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[3] * 1.0f / aa;
- int dx = x - prev_x;
- int dy = y - prev_y;
- int length = ctx_maxf (abs (dx), abs (dy) );
- if (length)
- {
- length *= LENGTH_OVERSAMPLE;
- int len = length;
- int tx = prev_x * 256;
- int ty = prev_y * 256;
- dx *= 256;
- dy *= 256;
- dx /= length;
- dy /= length;
- for (int i = 0; i < len; i++)
- {
- ctx_rasterizer_pset (rasterizer, tx/256, ty/256, 255);
- tx += dx;
- ty += dy;
- ctx_rasterizer_pset (rasterizer, tx/256, ty/256, 255);
- }
- }
- prev_x = x;
- prev_y = y;
- }
- end = i-1;
-foo:
- start = end+1;
+ _ctx_user_to_device (rasterizer->state, &tx, &ty);
}
- ctx_rasterizer_reset (rasterizer);
+
+ tx = (tx - rasterizer->blit_x) * CTX_SUBDIV;
+ ty = ty * aa;
+
+ if (ty < rasterizer->scan_min)
+ { rasterizer->scan_min = ty; }
+ if (ty > rasterizer->scan_max)
+ { rasterizer->scan_max = ty; }
+ if (tx < rasterizer->col_min)
+ { rasterizer->col_min = tx; }
+ if (tx > rasterizer->col_max)
+ { rasterizer->col_max = tx; }
+}
+
+static void ctx_rasterizer_line_to (CtxRasterizer *rasterizer, float x, float y)
+{
+ 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;
+#define MIN_Y -1000
+#define MAX_Y 1400
+
+ if (ty < MIN_Y) ty = MIN_Y;
+ if (ty > MAX_Y) ty = MAX_Y;
+ ctx_rasterizer_add_point (rasterizer, tx * CTX_SUBDIV, ty * rasterizer->aa);
+ if (rasterizer->has_prev<=0)
+ {
+ if (rasterizer->uses_transforms)
+ {
+ // storing transformed would save some processing for a tiny
+ // amount of runtime RAM XXX
+ _ctx_user_to_device (rasterizer->state, &ox, &oy);
+ }
+ ox -= rasterizer->blit_x;
+
+ if (oy < MIN_Y) oy = MIN_Y;
+ if (oy > MAX_Y) oy = MAX_Y;
+
+ rasterizer->edge_list.entries[rasterizer->edge_list.count-1].data.s16[0] = ox * CTX_SUBDIV;
+ rasterizer->edge_list.entries[rasterizer->edge_list.count-1].data.s16[1] = oy * rasterizer->aa;
+ rasterizer->edge_list.entries[rasterizer->edge_list.count-1].code = CTX_NEW_EDGE;
+ rasterizer->has_prev = 1;
+ }
+ rasterizer->has_shape = 1;
+ rasterizer->y = y;
+ rasterizer->x = x;
+}
+
+
+CTX_INLINE static float
+ctx_bezier_sample_1d (float x0, float x1, float x2, float x3, float dt)
+{
+ float ab = ctx_lerpf (x0, x1, dt);
+ float bc = ctx_lerpf (x1, x2, dt);
+ float cd = ctx_lerpf (x2, x3, dt);
+ float abbc = ctx_lerpf (ab, bc, dt);
+ float bccd = ctx_lerpf (bc, cd, dt);
+ return ctx_lerpf (abbc, bccd, dt);
+}
+
+inline static void
+ctx_bezier_sample (float x0, float y0,
+ float x1, float y1,
+ float x2, float y2,
+ float x3, float y3,
+ float dt, float *x, float *y)
+{
+ *x = ctx_bezier_sample_1d (x0, x1, x2, x3, dt);
+ *y = ctx_bezier_sample_1d (y0, y1, y2, y3, dt);
}
static void
-ctx_rasterizer_stroke (CtxRasterizer *rasterizer)
+ctx_rasterizer_bezier_divide (CtxRasterizer *rasterizer,
+ float ox, float oy,
+ float x0, float y0,
+ float x1, float y1,
+ float x2, float y2,
+ float sx, float sy,
+ float ex, float ey,
+ float s,
+ float e,
+ int iteration,
+ float tolerance)
{
- CtxState *state = rasterizer->state;
- int count = rasterizer->edge_list.count;
- int preserved = rasterizer->preserve;
- // YYY
- float factor = ctx_maxf (ctx_maxf (ctx_fabsf (state->gstate.transform.m[0][0]),
- ctx_fabsf (state->gstate.transform.m[0][1]) ),
- ctx_maxf (ctx_fabsf (state->gstate.transform.m[1][0]),
- ctx_fabsf (state->gstate.transform.m[1][1]) ) );
- int aa = rasterizer->aa;
- CtxEntry temp[count]; /* copy of already built up path's poly line */
- memcpy (temp, rasterizer->edge_list.entries, sizeof (temp) );
-#if 1
- if (rasterizer->state->gstate.line_width * factor <= 0.0f &&
- rasterizer->state->gstate.line_width * factor > -10.0f)
+ if (iteration > 8)
+ { return; }
+ float t = (s + e) * 0.5f;
+ float x, y, lx, ly, dx, dy;
+ ctx_bezier_sample (ox, oy, x0, y0, x1, y1, x2, y2, t, &x, &y);
+ if (iteration)
{
- ctx_rasterizer_stroke_1px (rasterizer);
+ lx = ctx_lerpf (sx, ex, t);
+ ly = ctx_lerpf (sy, ey, t);
+ dx = lx - x;
+ dy = ly - y;
+ if ( (dx*dx+dy*dy) < tolerance)
+ /* bailing - because for the mid-point straight line difference is
+ tiny */
+ { return; }
+ dx = sx - ex;
+ dy = ey - ey;
+ if ( (dx*dx+dy*dy) < tolerance)
+ /* bailing on tiny segments */
+ { return; }
+ }
+ ctx_rasterizer_bezier_divide (rasterizer, ox, oy, x0, y0, x1, y1, x2, y2,
+ sx, sy, x, y, s, t, iteration + 1,
+ tolerance);
+ ctx_rasterizer_line_to (rasterizer, x, y);
+ ctx_rasterizer_bezier_divide (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)
+{
+ float tolerance =
+ ctx_pow2 (rasterizer->state->gstate.transform.m[0][0]) +
+ ctx_pow2 (rasterizer->state->gstate.transform.m[1][1]);
+ float ox = rasterizer->x;
+ float oy = rasterizer->y;
+ ox = rasterizer->state->x;
+ oy = rasterizer->state->y;
+ tolerance = 1.0f/tolerance * 2;
+#if 1 // skipping this to preserve hash integrity
+ if (tolerance == 1.0f || 1)
+ {
+ float maxx = ctx_maxf (x1,x2);
+ maxx = ctx_maxf (maxx, ox);
+ maxx = ctx_maxf (maxx, x0);
+ float maxy = ctx_maxf (y1,y2);
+ maxy = ctx_maxf (maxy, oy);
+ maxy = ctx_maxf (maxy, y0);
+ float minx = ctx_minf (x1,x2);
+ minx = ctx_minf (minx, ox);
+ minx = ctx_minf (minx, x0);
+ float miny = ctx_minf (y1,y2);
+ miny = ctx_minf (miny, oy);
+ miny = ctx_minf (miny, y0);
+
+ _ctx_user_to_device (rasterizer->state, &minx, &miny);
+ _ctx_user_to_device (rasterizer->state, &maxx, &maxy);
+
+ if(
+ (minx > rasterizer->blit_x + rasterizer->blit_width) ||
+ (miny > rasterizer->blit_y + rasterizer->blit_height) ||
+ (maxx < rasterizer->blit_x) ||
+ (maxy < rasterizer->blit_y) )
+ {
+ }
+ else
+ {
+ ctx_rasterizer_bezier_divide (rasterizer,
+ ox, oy, x0, y0,
+ x1, y1, x2, y2,
+ ox, oy, x2, y2,
+ 0.0f, 1.0f, 0.0f, tolerance);
}
+ }
else
#endif
{
- ctx_rasterizer_reset (rasterizer); /* then start afresh with our stroked shape */
- CtxMatrix transform_backup = rasterizer->state->gstate.transform;
- ctx_matrix_identity (&rasterizer->state->gstate.transform);
- float prev_x = 0.0f;
- float prev_y = 0.0f;
- float half_width_x = rasterizer->state->gstate.line_width * factor/2;
- float half_width_y = rasterizer->state->gstate.line_width * factor/2;
- if (rasterizer->state->gstate.line_width <= 0.0f)
- {
- half_width_x = .5;
- half_width_y = .5;
- }
- int start = 0;
- int end = 0;
- while (start < count)
- {
- int started = 0;
- int i;
- for (i = start; i < count; i++)
- {
- CtxEntry *entry = &temp[i];
- float x, y;
- if (entry->code == CTX_NEW_EDGE)
- {
- if (started)
- {
- end = i - 1;
- goto foo;
- }
- prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
- prev_y = entry->data.s16[1] * 1.0f / aa;
- started = 1;
- start = i;
- }
- x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[3] * 1.0f / aa;
- float dx = x - prev_x;
- float dy = y - prev_y;
- float length = ctx_fast_hypotf (dx, dy);
- if (length>0.001f)
- {
- dx = dx/length * half_width_x;
- dy = dy/length * half_width_y;
- if (entry->code == CTX_NEW_EDGE)
- {
- ctx_rasterizer_finish_shape (rasterizer);
- ctx_rasterizer_move_to (rasterizer, prev_x+dy, prev_y-dx);
- }
- ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
- // XXX possible miter line-to
- ctx_rasterizer_line_to (rasterizer, x-dy, y+dx);
- }
- prev_x = x;
- prev_y = y;
- }
- end = i-1;
-foo:
- for (int i = end; i >= start; i--)
- {
- CtxEntry *entry = &temp[i];
- float x, y, dx, dy;
- x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[3] * 1.0f / aa;
- dx = x - prev_x;
- dy = y - prev_y;
- float length = ctx_fast_hypotf (dx, dy);
- dx = dx/length * half_width_x;
- dy = dy/length * half_width_y;
- if (length>0.001f)
- {
- ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
- // XXX possible miter line-to
- ctx_rasterizer_line_to (rasterizer, x-dy, y+dx);
- }
- prev_x = x;
- prev_y = y;
- if (entry->code == CTX_NEW_EDGE)
- {
- x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[1] * 1.0f / aa;
- dx = x - prev_x;
- dy = y - prev_y;
- length = ctx_fast_hypotf (dx, dy);
- if (length>0.001f)
- {
- dx = dx / length * half_width_x;
- dy = dy / length * half_width_y;
- ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
- ctx_rasterizer_line_to (rasterizer, x-dy, y+dx);
- }
- }
- if ( (prev_x != x) && (prev_y != y) )
- {
- prev_x = x;
- prev_y = y;
- }
- }
- start = end+1;
- }
- ctx_rasterizer_finish_shape (rasterizer);
- switch (rasterizer->state->gstate.line_cap)
- {
- case CTX_CAP_SQUARE: // XXX:NYI
- case CTX_CAP_NONE: /* nothing to do */
- break;
- case CTX_CAP_ROUND:
- {
- float x = 0, y = 0;
- int has_prev = 0;
- for (int i = 0; i < count; i++)
- {
- CtxEntry *entry = &temp[i];
- if (entry->code == CTX_NEW_EDGE)
- {
- if (has_prev)
- {
- ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
- ctx_rasterizer_finish_shape (rasterizer);
- }
- x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[1] * 1.0f / aa;
- ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
- ctx_rasterizer_finish_shape (rasterizer);
- }
- x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[3] * 1.0f / aa;
- has_prev = 1;
- }
- ctx_rasterizer_move_to (rasterizer, x, y);
- ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
- ctx_rasterizer_finish_shape (rasterizer);
- break;
- }
- }
- switch (rasterizer->state->gstate.line_join)
- {
- case CTX_JOIN_BEVEL:
- case CTX_JOIN_MITER:
- break;
- case CTX_JOIN_ROUND:
- {
- float x = 0, y = 0;
- for (int i = 0; i < count-1; i++)
- {
- CtxEntry *entry = &temp[i];
- x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[3] * 1.0f / aa;
- if (entry[1].code == CTX_EDGE)
- {
- ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*2, 0, 1);
- ctx_rasterizer_finish_shape (rasterizer);
- }
- }
- break;
- }
- }
- CtxFillRule rule_backup = rasterizer->state->gstate.fill_rule;
- rasterizer->state->gstate.fill_rule = CTX_FILL_RULE_WINDING;
- rasterizer->preserve = 0; // so fill isn't tripped
- ctx_rasterizer_fill (rasterizer);
- rasterizer->state->gstate.fill_rule = rule_backup;
- //rasterizer->state->gstate.source = source_backup;
- rasterizer->state->gstate.transform = transform_backup;
- }
- if (preserved)
- {
- memcpy (rasterizer->edge_list.entries, temp, sizeof (temp) );
- rasterizer->edge_list.count = count;
- rasterizer->preserve = 0;
+ ctx_rasterizer_bezier_divide (rasterizer,
+ ox, oy, x0, y0,
+ x1, y1, x2, y2,
+ ox, oy, x2, y2,
+ 0.0f, 1.0f, 0.0f, tolerance);
}
+ ctx_rasterizer_line_to (rasterizer, x2, y2);
}
-#if CTX_1BIT_CLIP
-#define CTX_CLIP_FORMAT CTX_FORMAT_GRAY1
-#else
-#define CTX_CLIP_FORMAT CTX_FORMAT_GRAY8
-#endif
-
-
static void
-ctx_rasterizer_clip_reset (CtxRasterizer *rasterizer)
+ctx_rasterizer_rel_move_to (CtxRasterizer *rasterizer, float x, float y)
{
-#if CTX_ENABLE_CLIP
- if (rasterizer->clip_buffer)
- ctx_buffer_free (rasterizer->clip_buffer);
- rasterizer->clip_buffer = NULL;
-#endif
- rasterizer->state->gstate.clip_min_x = rasterizer->blit_x;
- rasterizer->state->gstate.clip_min_y = rasterizer->blit_y;
+ if (x == 0.f && y == 0.f)
+ { return; }
+ x += rasterizer->x;
+ y += rasterizer->y;
+ ctx_rasterizer_move_to (rasterizer, x, y);
+}
- rasterizer->state->gstate.clip_max_x = rasterizer->blit_x + rasterizer->blit_width - 1;
- rasterizer->state->gstate.clip_max_y = rasterizer->blit_y + rasterizer->blit_height - 1;
+static void
+ctx_rasterizer_rel_line_to (CtxRasterizer *rasterizer, float x, float y)
+{
+ if (x== 0.f && y==0.f)
+ { return; }
+ x += rasterizer->x;
+ y += rasterizer->y;
+ ctx_rasterizer_line_to (rasterizer, x, y);
}
static void
-ctx_rasterizer_clip_apply (CtxRasterizer *rasterizer,
- CtxEntry *edges)
+ctx_rasterizer_rel_curve_to (CtxRasterizer *rasterizer,
+ float x0, float y0, float x1, float y1, float x2, float y2)
{
- int count = edges[0].data.u32[0];
- int aa = rasterizer->aa;
+ x0 += rasterizer->x;
+ y0 += rasterizer->y;
+ x1 += rasterizer->x;
+ y1 += rasterizer->y;
+ x2 += rasterizer->x;
+ y2 += rasterizer->y;
+ ctx_rasterizer_curve_to (rasterizer, x0, y0, x1, y1, x2, y2);
+}
- int minx = 5000;
- int miny = 5000;
- int maxx = -5000;
- int maxy = -5000;
- int prev_x = 0;
- int prev_y = 0;
- for (int i = 0; i < count; i++)
- {
- CtxEntry *entry = &edges[i+1];
- 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 / aa;
- if (prev_x < minx) { minx = prev_x; }
- if (prev_y < miny) { miny = prev_y; }
- if (prev_x > maxx) { maxx = prev_x; }
- if (prev_y > maxy) { maxy = prev_y; }
- }
- x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[3] * 1.0f / aa;
- if (x < minx) { minx = x; }
- if (y < miny) { miny = y; }
- if (x > maxx) { maxx = x; }
- if (y > maxy) { maxy = y; }
- }
-#if CTX_ENABLE_CLIP
- if ((minx == maxx) || (miny == maxy)) // XXX : reset hack
+static int
+ctx_rasterizer_find_texture (CtxRasterizer *rasterizer,
+ const char *eid)
+{
+ int no;
+ for (no = 0; no < CTX_MAX_TEXTURES; no++)
{
- ctx_rasterizer_clip_reset (rasterizer);
- return;//goto done;
+ if (rasterizer->texture_source->texture[no].data &&
+ rasterizer->texture_source->texture[no].eid &&
+ !strcmp (rasterizer->texture_source->texture[no].eid, eid))
+ return no;
}
+ return -1;
+}
- int we_made_it = 0;
- CtxBuffer *clip_buffer;
-
-
- if (!rasterizer->clip_buffer)
- {
- rasterizer->clip_buffer = ctx_buffer_new (rasterizer->blit_width,
- rasterizer->blit_height,
- CTX_CLIP_FORMAT);
- clip_buffer = rasterizer->clip_buffer;
- we_made_it = 1;
- if (CTX_CLIP_FORMAT == CTX_FORMAT_GRAY1)
- memset (rasterizer->clip_buffer->data, 0, rasterizer->blit_width * rasterizer->blit_height/8);
- else
- memset (rasterizer->clip_buffer->data, 0, rasterizer->blit_width * rasterizer->blit_height);
- }
+static void
+ctx_rasterizer_set_texture (CtxRasterizer *rasterizer,
+ const char *eid,
+ float x,
+ float y)
+{
+ int no = ctx_rasterizer_find_texture (rasterizer, eid);
+ 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);
+ return;
+ }
else
{
- clip_buffer = ctx_buffer_new (rasterizer->blit_width,
- rasterizer->blit_height,
- CTX_CLIP_FORMAT);
+ rasterizer->texture_source->texture[no].frame = rasterizer->texture_source->frame;
}
+ rasterizer->state->gstate.source_fill.type = CTX_SOURCE_TEXTURE;
+ rasterizer->state->gstate.source_fill.texture.buffer = &rasterizer->texture_source->texture[no];
+ //ctx_user_to_device (rasterizer->state, &x, &y);
+ rasterizer->state->gstate.source_fill.texture.x0 = 0;
+ rasterizer->state->gstate.source_fill.texture.y0 = 0;
+ rasterizer->state->gstate.source_fill.transform = rasterizer->state->gstate.transform;
+ ctx_matrix_translate (&rasterizer->state->gstate.source_fill.transform, x, y);
+ ctx_matrix_invert (&rasterizer->state->gstate.source_fill.transform);
+}
+
+
+static void ctx_rasterizer_define_texture (CtxRasterizer *rasterizer,
+ const char *eid,
+ int width,
+ int height,
+ int format,
+ char unsigned *data)
+{
+ _ctx_texture_lock (); // we're using the same texture_source from all threads, keeping allocaitons down
+ // need synchronizing (it could be better to do a pre-pass)
+ ctx_texture_init (rasterizer->texture_source,
+ eid,
+ width,
+ height,
+ ctx_pixel_format_get_stride ((CtxPixelFormat)format, width),
+ (CtxPixelFormat)format,
+#if CTX_ENABLE_CM
+ (void*)rasterizer->state->gstate.texture_space,
+#else
+ NULL,
+#endif
+ data,
+ ctx_buffer_pixels_free, (void*)23);
+ /* when userdata for ctx_buffer_pixels_free is 23, texture_init dups the data on
+ * use
+ */
- // for now only one level of clipping is supported
- {
+ _ctx_texture_unlock ();
+ ctx_rasterizer_set_texture (rasterizer, eid, 0.0, 0.0);
+}
- int prev_x = 0;
- int prev_y = 0;
- Ctx *ctx = ctx_new_for_framebuffer (clip_buffer->data, rasterizer->blit_width, rasterizer->blit_height,
- rasterizer->blit_width,
- CTX_CLIP_FORMAT);
+CTX_INLINE static int ctx_compare_edges (const void *ap, const void *bp)
+{
+ const CtxEntry *a = (const CtxEntry *) ap;
+ const CtxEntry *b = (const CtxEntry *) bp;
+ int ycompare = a->data.s16[1] - b->data.s16[1];
+ if (ycompare)
+ { return ycompare; }
+ int xcompare = a->data.s16[0] - b->data.s16[0];
+ return xcompare;
+}
- for (int i = 0; i < count; i++)
+CTX_INLINE static int ctx_edge_qsort_partition (CtxEntry *A, int low, int high)
+{
+ CtxEntry pivot = A[ (high+low) /2];
+ int i = low;
+ int j = high;
+ while (i <= j)
{
- CtxEntry *entry = &edges[i+1];
- float x, y;
- if (entry->code == CTX_NEW_EDGE)
+ while (ctx_compare_edges (&A[i], &pivot) <0) { i ++; }
+ while (ctx_compare_edges (&pivot, &A[j]) <0) { j --; }
+ if (i <= j)
{
- prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
- prev_y = entry->data.s16[1] * 1.0f / aa;
- ctx_move_to (ctx, prev_x, prev_y);
+ CtxEntry tmp = A[i];
+ A[i] = A[j];
+ A[j] = tmp;
+ i++;
+ j--;
}
- x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[3] * 1.0f / aa;
- ctx_line_to (ctx, x, y);
}
- ctx_gray (ctx, 1.0f);
- ctx_fill (ctx);
- ctx_free (ctx);
- }
+ return i;
+}
- if (CTX_CLIP_FORMAT == CTX_FORMAT_GRAY1)
- {
- for (int i = 0; i < rasterizer->blit_width * rasterizer->blit_height/8; i++)
- {
- ((uint8_t*)rasterizer->clip_buffer->data)[i] =
- (((uint8_t*)rasterizer->clip_buffer->data)[i] &
- ((uint8_t*)clip_buffer->data)[i]);
- }
- }
- else
+static void ctx_edge_qsort (CtxEntry *entries, int low, int high)
+{
{
- for (int i = 0; i < rasterizer->blit_width * rasterizer->blit_height; i++)
- {
- ((uint8_t*)rasterizer->clip_buffer->data)[i] =
- (((uint8_t*)rasterizer->clip_buffer->data)[i] *
- ((uint8_t*)clip_buffer->data)[i])/255;
- }
+ int p = ctx_edge_qsort_partition (entries, low, high);
+ if (low < p -1 )
+ { ctx_edge_qsort (entries, low, p - 1); }
+ if (low < high)
+ { ctx_edge_qsort (entries, p, high); }
}
- if (!we_made_it)
- ctx_buffer_free (clip_buffer);
-#endif
-
- rasterizer->state->gstate.clip_min_x = ctx_maxi (minx,
- rasterizer->state->gstate.clip_min_x);
- rasterizer->state->gstate.clip_min_y = ctx_maxi (miny,
- rasterizer->state->gstate.clip_min_y);
- rasterizer->state->gstate.clip_max_x = ctx_mini (maxx,
- rasterizer->state->gstate.clip_max_x);
- rasterizer->state->gstate.clip_max_y = ctx_mini (maxy,
- rasterizer->state->gstate.clip_max_y);
-//done:
-
}
-static void
-ctx_rasterizer_clip (CtxRasterizer *rasterizer)
+static void ctx_rasterizer_sort_edges (CtxRasterizer *rasterizer)
{
- int count = rasterizer->edge_list.count;
- CtxEntry temp[count+1]; /* copy of already built up path's poly line */
- rasterizer->state->has_clipped=1;
- rasterizer->state->gstate.clipped=1;
- //if (rasterizer->preserve)
- { memcpy (temp + 1, rasterizer->edge_list.entries, sizeof (temp) - sizeof (temp[0]));
- temp[0].code = CTX_NOP;
- temp[0].data.u32[0] = count;
- ctx_state_set_blob (rasterizer->state, CTX_clip, (uint8_t*)temp, sizeof(temp));
- }
- ctx_rasterizer_clip_apply (rasterizer, temp);
-
- ctx_rasterizer_reset (rasterizer);
- if (rasterizer->preserve)
+ if (rasterizer->edge_list.count > 1)
{
- memcpy (rasterizer->edge_list.entries, temp + 1, sizeof (temp) - sizeof(temp[0]));
- rasterizer->edge_list.count = count;
- rasterizer->preserve = 0;
+ ctx_edge_qsort (& (rasterizer->edge_list.entries[0]), 0, rasterizer->edge_list.count-1);
}
}
-static void
-ctx_rasterizer_set_texture (CtxRasterizer *rasterizer,
- int no,
- float x,
- float y)
-{
- if (no < 0 || no >= CTX_MAX_TEXTURES) { no = 0; }
- if (rasterizer->texture_source->texture[no].data == NULL)
- {
- ctx_log ("failed setting texture %i\n", no);
- return;
- }
- rasterizer->state->gstate.source.type = CTX_SOURCE_IMAGE;
- rasterizer->state->gstate.source.image.buffer = &rasterizer->texture_source->texture[no];
- //ctx_user_to_device (rasterizer->state, &x, &y);
- rasterizer->state->gstate.source.image.x0 = 0;
- rasterizer->state->gstate.source.image.y0 = 0;
- rasterizer->state->gstate.source.transform = rasterizer->state->gstate.transform;
- ctx_matrix_translate (&rasterizer->state->gstate.source.transform, x, y);
- ctx_matrix_invert (&rasterizer->state->gstate.source.transform);
-}
-#if 0
-static void
-ctx_rasterizer_load_image (CtxRasterizer *rasterizer,
- const char *path,
- float x,
- float y)
+static void ctx_rasterizer_discard_edges (CtxRasterizer *rasterizer)
{
- // decode PNG, put it in image is slot 1,
- // magic width height stride format data
- ctx_buffer_load_png (&rasterizer->ctx->texture[0], path);
- ctx_rasterizer_set_texture (rasterizer, 0, x, y);
-}
+ int scanline = rasterizer->scanline;
+ int aa = rasterizer->aa;
+#if CTX_RASTERIZER_FORCE_AA==0
+ rasterizer->ending_edges = 0;
#endif
-
-static void
-ctx_rasterizer_set_pixel (CtxRasterizer *rasterizer,
- uint16_t x,
- uint16_t y,
- uint8_t r,
- uint8_t g,
- uint8_t b,
- uint8_t a)
-{
- rasterizer->state->gstate.source.type = CTX_SOURCE_COLOR;
- ctx_color_set_RGBA8 (rasterizer->state, &rasterizer->state->gstate.source.color, r, g, b, a);
-#if 0
- // XXX : doesn't take transforms into account
- ctx_rasterizer_pset (rasterizer, x, y, 255);
-#else
- ctx_rasterizer_move_to (rasterizer, x, y);
- ctx_rasterizer_rel_line_to (rasterizer, 1, 0);
- ctx_rasterizer_rel_line_to (rasterizer, 0, 1);
- ctx_rasterizer_rel_line_to (rasterizer, -1, 0);
- ctx_rasterizer_fill (rasterizer);
+ for (int i = 0; i < rasterizer->active_edges; i++)
+ {
+ int edge_end =rasterizer->edge_list.entries[rasterizer->edges[i].index].data.s16[3];
+ if (edge_end < scanline)
+ {
+ int dx_dy = rasterizer->edges[i].dx;
+ if (abs(dx_dy)> CTX_RASTERIZER_AA_SLOPE_LIMIT)
+ { rasterizer->needs_aa --; }
+ rasterizer->edges[i] = rasterizer->edges[rasterizer->active_edges-1];
+ rasterizer->active_edges--;
+ i--;
+ }
+#if CTX_RASTERIZER_FORCE_AA==0
+ else if (edge_end < scanline + aa)
+ rasterizer->ending_edges = 1;
#endif
+ }
}
-static void
-ctx_rasterizer_rectangle (CtxRasterizer *rasterizer,
- float x,
- float y,
- float width,
- float height)
-{
- ctx_rasterizer_move_to (rasterizer, x, y);
- ctx_rasterizer_rel_line_to (rasterizer, width, 0);
- ctx_rasterizer_rel_line_to (rasterizer, 0, height);
- ctx_rasterizer_rel_line_to (rasterizer, -width, 0);
- ctx_rasterizer_rel_line_to (rasterizer, 0, -height);
- ctx_rasterizer_rel_line_to (rasterizer, 0.3, 0);
- ctx_rasterizer_finish_shape (rasterizer);
-}
-
-#if CTX_ENABLE_SHADOW_BLUR
-static float
-ctx_gaussian (float x, float mu, float sigma)
-{
- float a = ( x- mu) / sigma;
- return ctx_expf (-0.5 * a * a);
-}
-
-static void
-ctx_compute_gaussian_kernel (int dim, float radius, float *kernel)
+static void ctx_rasterizer_increment_edges (CtxRasterizer *rasterizer, int count)
{
- float sigma = radius / 2;
- float sum = 0.0;
- int i = 0;
- //for (int row = 0; row < dim; row ++)
- for (int col = 0; col < dim; col ++, i++)
+ for (int i = 0; i < rasterizer->active_edges; i++)
{
- float val = //ctx_gaussian (row, radius, sigma) *
- ctx_gaussian (col, radius, sigma);
- kernel[i] = val;
- sum += val;
+ rasterizer->edges[i].x += rasterizer->edges[i].dx * count;
+ }
+#if CTX_RASTERIZER_FORCE_AA==0
+ for (int i = 0; i < rasterizer->pending_edges; i++)
+ {
+ rasterizer->edges[CTX_MAX_EDGES-1-i].x += rasterizer->edges[CTX_MAX_EDGES-1-i].dx * count;
}
- i = 0;
- //for (int row = 0; row < dim; row ++)
- for (int col = 0; col < dim; col ++, i++)
- kernel[i] /= sum;
-}
#endif
-
-static void
-ctx_rasterizer_round_rectangle (CtxRasterizer *rasterizer, float x, float y, float width, float height,
float corner_radius)
-{
- float aspect = 1.0f;
- float radius = corner_radius / aspect;
- float degrees = CTX_PI / 180.0f;
-
- if (radius > width/2) radius = width/2;
- if (radius > height/2) radius = height/2;
-
- ctx_rasterizer_finish_shape (rasterizer);
- ctx_rasterizer_arc (rasterizer, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees, 0);
- ctx_rasterizer_arc (rasterizer, x + width - radius, y + height - radius, radius, 0 * degrees, 90 *
degrees, 0);
- ctx_rasterizer_arc (rasterizer, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees, 0);
- ctx_rasterizer_arc (rasterizer, x + radius, y + radius, radius, 180 * degrees, 270 * degrees, 0);
- ctx_rasterizer_finish_shape (rasterizer);
-}
-
-static void
-ctx_rasterizer_process (void *user_data, CtxCommand *command);
-
-static int
-_ctx_is_rasterizer (Ctx *ctx)
-{
- if (ctx->renderer && ctx->renderer->process == ctx_rasterizer_process)
- return 1;
- return 0;
}
-#if CTX_COMPOSITING_GROUPS
-static void
-ctx_rasterizer_start_group (CtxRasterizer *rasterizer)
+/* feeds up to rasterizer->scanline,
+ keeps a pending buffer of edges - that encompass
+ the full incoming scanline,
+ feed until the start of the scanline and check for need for aa
+ in all of pending + active edges, then
+ again feed_edges until middle of scanline if doing non-AA
+ or directly render when doing AA
+*/
+inline static void ctx_rasterizer_feed_edges (CtxRasterizer *rasterizer)
{
- CtxEntry save_command = ctx_void(CTX_SAVE);
- // allocate buffer, and set it as temporary target
- int no;
- if (rasterizer->group[0] == NULL) // first group
- {
- rasterizer->saved_buf = rasterizer->buf;
- }
- for (no = 0; rasterizer->group[no] && no < CTX_GROUP_MAX; no++);
-
- if (no >= CTX_GROUP_MAX)
- return;
- rasterizer->group[no] = ctx_buffer_new (rasterizer->blit_width,
- rasterizer->blit_height,
- rasterizer->format->composite_format);
- rasterizer->buf = rasterizer->group[no]->data;
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
+ int miny;
+ CtxEntry *entries = rasterizer->edge_list.entries;
+#if CTX_RASTERIZER_FORCE_AA==0
+ for (int i = 0; i < rasterizer->pending_edges; i++)
+ {
+ if (entries[rasterizer->edges[CTX_MAX_EDGES-1-i].index].data.s16[1] <= rasterizer->scanline)
+ {
+ if (rasterizer->active_edges < CTX_MAX_EDGES-2)
+ {
+ int no = rasterizer->active_edges;
+ rasterizer->active_edges++;
+ rasterizer->edges[no] = rasterizer->edges[CTX_MAX_EDGES-1-i];
+ rasterizer->edges[CTX_MAX_EDGES-1-i] =
+ rasterizer->edges[CTX_MAX_EDGES-1-rasterizer->pending_edges + 1];
+ rasterizer->pending_edges--;
+ i--;
+ }
+ }
+ }
+#endif
+ int scanline = rasterizer->scanline;
+#if CTX_RASTERIZER_FORCE_AA==0
+ int aa = rasterizer->aa;
+#endif
+ while (rasterizer->edge_pos < rasterizer->edge_list.count &&
+ (miny=entries[rasterizer->edge_pos].data.s16[1]) <= scanline
+#if CTX_RASTERIZER_FORCE_AA==0
+ + aa
+#endif
+
+ )
+ {
+ if (rasterizer->active_edges < CTX_MAX_EDGES-2)
+ {
+ int dy = (entries[rasterizer->edge_pos].data.s16[3] -
+ miny);
+ if (dy) /* skipping horizontal edges */
+ {
+ int yd = scanline - miny;
+ int no = rasterizer->active_edges;
+ rasterizer->active_edges++;
+ rasterizer->edges[no].index = rasterizer->edge_pos;
+ int index = rasterizer->edges[no].index;
+ int x0 = entries[index].data.s16[0];
+ int x1 = entries[index].data.s16[2];
+ rasterizer->edges[no].x = x0 * CTX_RASTERIZER_EDGE_MULTIPLIER;
+ int dx_dy;
+ // if (dy)
+ dx_dy = CTX_RASTERIZER_EDGE_MULTIPLIER * (x1 - x0) / dy;
+ // else
+ // dx_dy = 0;
+ rasterizer->edges[no].dx = dx_dy;
+ rasterizer->edges[no].x += (yd * dx_dy);
+ // XXX : even better minx and maxx can
+ // be derived using y0 and y1 for scaling dx_dy
+ // when ydelta to these are smaller than
+ // ydelta to scanline
+#if 0
+ if (dx_dy < 0)
+ {
+ rasterizer->edges[no].minx =
+ rasterizer->edges[no].x + dx_dy/2;
+ rasterizer->edges[no].maxx =
+ rasterizer->edges[no].x - dx_dy/2;
+ }
+ else
+ {
+ rasterizer->edges[no].minx =
+ rasterizer->edges[no].x - dx_dy/2;
+ rasterizer->edges[no].maxx =
+ rasterizer->edges[no].x + dx_dy/2;
+ }
+#endif
+#if CTX_RASTERIZER_FORCE_AA==0
+ if (abs(dx_dy)> CTX_RASTERIZER_AA_SLOPE_LIMIT)
+ { rasterizer->needs_aa ++; }
+
+ if ((miny > scanline) )
+ {
+ /* it is a pending edge - we add it to the end of the array
+ and keep a different count for items stored here, like
+ a heap and stack growing against each other
+ */
+ if (rasterizer->pending_edges < CTX_MAX_PENDING-1)
+ {
+ rasterizer->edges[CTX_MAX_EDGES-1-rasterizer->pending_edges] =
+ rasterizer->edges[no];
+ rasterizer->pending_edges++;
+ rasterizer->active_edges--;
+ }
+ }
+#endif
+ }
+ }
+ rasterizer->edge_pos++;
+ }
}
-static void
-ctx_rasterizer_end_group (CtxRasterizer *rasterizer)
+CTX_INLINE static int ctx_compare_edges2 (const void *ap, const void *bp)
{
- CtxEntry restore_command = ctx_void(CTX_RESTORE);
- CtxEntry save_command = ctx_void(CTX_SAVE);
- int no = 0;
- for (no = 0; rasterizer->group[no] && no < CTX_GROUP_MAX; no++);
- no--;
-
- if (no < 0)
- return;
+ const CtxEdge *a = (const CtxEdge *) ap;
+ const CtxEdge *b = (const CtxEdge *) bp;
+ return a->x - b->x;
+}
- CtxCompositingMode comp = rasterizer->state->gstate.compositing_mode;
- CtxBlend blend = rasterizer->state->gstate.blend_mode;
- float global_alpha = rasterizer->state->gstate.global_alpha_f;
- // fetch compositing, blending, global alpha
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
- CtxEntry set_state[3]=
- {
- ctx_u8 (CTX_COMPOSITING_MODE, comp, 0,0,0,0,0,0,0),
- ctx_u8 (CTX_BLEND_MODE, blend, 0,0,0,0,0,0,0),
- ctx_f (CTX_GLOBAL_ALPHA, global_alpha, 0.0)
- };
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[0]);
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[1]);
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[2]);
- if (no == 0)
- {
- rasterizer->buf = rasterizer->saved_buf;
- }
- else
- {
- rasterizer->buf = rasterizer->group[no-1]->data;
- }
- int id = ctx_texture_init (rasterizer->ctx, -1,
- rasterizer->blit_width,
- rasterizer->blit_height,
- rasterizer->blit_width * rasterizer->format->bpp/8,
- rasterizer->format->pixel_format,
- (uint8_t*)rasterizer->group[no]->data,
- NULL, NULL);
- {
- CtxEntry commands[2] =
- {ctx_u32 (CTX_TEXTURE, id, 0),
- ctx_f (CTX_CONT, rasterizer->blit_x, rasterizer->blit_y)};
- ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
- }
- {
- CtxEntry commands[2]=
+CTX_INLINE static int ctx_edge2_qsort_partition (CtxEdge *A, int low, int high)
+{
+ CtxEdge pivot = A[ (high+low) /2];
+ int i = low;
+ int j = high;
+ while (i <= j)
{
- ctx_f (CTX_RECTANGLE, rasterizer->blit_x, rasterizer->blit_y),
- ctx_f (CTX_CONT, rasterizer->blit_width, rasterizer->blit_height)
- };
- ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
- }
- {
- CtxEntry commands[1]= { ctx_void (CTX_FILL) };
- ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
- }
- ctx_texture_release (rasterizer->ctx, id);
- ctx_buffer_free (rasterizer->group[no]);
- rasterizer->group[no] = 0;
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
+ while (ctx_compare_edges2 (&A[i], &pivot) <0) { i ++; }
+ while (ctx_compare_edges2 (&pivot, &A[j]) <0) { j --; }
+ if (i <= j)
+ {
+ CtxEdge tmp = A[i];
+ A[i] = A[j];
+ A[j] = tmp;
+ i++;
+ j--;
+ }
+ }
+ return i;
}
-#endif
-#if CTX_ENABLE_SHADOW_BLUR
-static void
-ctx_rasterizer_shadow_stroke (CtxRasterizer *rasterizer)
+static void ctx_edge2_qsort (CtxEdge *entries, int low, int high)
{
- CtxColor color;
- CtxEntry save_command = ctx_void(CTX_SAVE);
-
- float rgba[4] = {0, 0, 0, 1.0};
- if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
- ctx_color_get_rgba (rasterizer->state, &color, rgba);
-
- CtxEntry set_color_command [3]=
- {
- ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
- ctx_f (CTX_CONT, rgba[1], rgba[2]),
- ctx_f (CTX_CONT, rgba[3], 0)
- };
- CtxEntry restore_command = ctx_void(CTX_RESTORE);
- float radius = rasterizer->state->gstate.shadow_blur;
- int dim = 2 * radius + 1;
- if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
- dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
- ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
{
- int i = 0;
- for (int v = 0; v < dim; v += 1, i++)
- {
- float dy = rasterizer->state->gstate.shadow_offset_y + v - dim/2;
- set_color_command[2].data.f[0] = rasterizer->kernel[i] * rgba[3];
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command[0]);
-#if CTX_ENABLE_SHADOW_BLUR
- rasterizer->in_shadow = 1;
-#endif
- rasterizer->shadow_x = rasterizer->state->gstate.shadow_offset_x;
- rasterizer->shadow_y = dy;
- rasterizer->preserve = 1;
- ctx_rasterizer_stroke (rasterizer);
-#if CTX_ENABLE_SHADOW_BLUR
- rasterizer->in_shadow = 0;
-#endif
- }
+ int p = ctx_edge2_qsort_partition (entries, low, high);
+ if (low < p -1 )
+ { ctx_edge2_qsort (entries, low, p - 1); }
+ if (low < high)
+ { ctx_edge2_qsort (entries, p, high); }
}
- //free (kernel);
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
}
-static void
-ctx_rasterizer_shadow_text (CtxRasterizer *rasterizer, const char *str)
-{
- float x = rasterizer->state->x;
- float y = rasterizer->state->y;
- CtxColor color;
- CtxEntry save_command = ctx_void(CTX_SAVE);
-
- float rgba[4] = {0, 0, 0, 1.0};
- if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
- ctx_color_get_rgba (rasterizer->state, &color, rgba);
-
- CtxEntry set_color_command [3]=
- {
- ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
- ctx_f (CTX_CONT, rgba[1], rgba[2]),
- ctx_f (CTX_CONT, rgba[3], 0)
- };
- CtxEntry move_to_command [1]=
- {
- ctx_f (CTX_MOVE_TO, x, y),
- };
- CtxEntry restore_command = ctx_void(CTX_RESTORE);
- float radius = rasterizer->state->gstate.shadow_blur;
- int dim = 2 * radius + 1;
- if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
- dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
- ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
+static void ctx_rasterizer_sort_active_edges (CtxRasterizer *rasterizer)
+{
+ CtxEdge *edges = rasterizer->edges;
+ /* we use sort networks for the very frequent cases of few active edges
+ * the built in qsort is fast, but sort networks are even faster
+ */
+ switch (rasterizer->active_edges)
{
- {
- move_to_command[0].data.f[0] = x;
- move_to_command[0].data.f[1] = y;
- set_color_command[2].data.f[0] = rgba[3];
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command);
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&move_to_command);
- rasterizer->in_shadow=1;
- ctx_rasterizer_text (rasterizer, str, 0);
- rasterizer->in_shadow=0;
+ case 0:
+ case 1: break;
+#if CTX_BLOATY_FAST_PATHS
+ case 2:
+#define COMPARE(a,b) \
+ if (ctx_compare_edges2 (&edges[a], &edges[b])>0)\
+ {\
+ CtxEdge tmp = edges[a];\
+ edges[a] = edges[b];\
+ edges[b] = tmp;\
}
+ COMPARE(0,1);
+ break;
+ case 3:
+ COMPARE(0,1); COMPARE(0,2); COMPARE(1,2);
+ break;
+ case 4:
+ COMPARE(0,1); COMPARE(2,3); COMPARE(0,2); COMPARE(1,3); COMPARE(1,2);
+ break;
+ case 5:
+ COMPARE(1,2); COMPARE(0,2); COMPARE(0,1); COMPARE(3,4); COMPARE(0,3);
+ COMPARE(1,4); COMPARE(2,4); COMPARE(1,3); COMPARE(2,3);
+ break;
+ case 6:
+ COMPARE(1,2); COMPARE(0,2); COMPARE(0,1); COMPARE(4,5);
+ COMPARE(3,5); COMPARE(3,4); COMPARE(0,3); COMPARE(1,4);
+ COMPARE(2,5); COMPARE(2,4); COMPARE(1,3); COMPARE(2,3);
+ break;
+#endif
+ default:
+ ctx_edge2_qsort (&edges[0], 0, rasterizer->active_edges-1);
+ break;
}
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
- move_to_command[0].data.f[0] = x;
- move_to_command[0].data.f[1] = y;
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&move_to_command);
}
-static void
-ctx_rasterizer_shadow_fill (CtxRasterizer *rasterizer)
+inline static void
+ctx_rasterizer_generate_coverage (CtxRasterizer *rasterizer,
+ int minx,
+ int maxx,
+ uint8_t *coverage,
+ int winding,
+ int aa_factor)
{
- CtxColor color;
- CtxEntry save_command = ctx_void(CTX_SAVE);
+ CtxEntry *entries = rasterizer->edge_list.entries;;
+ CtxEdge *edges = rasterizer->edges;
+ int scanline = rasterizer->scanline;
+ int active_edges = rasterizer->active_edges;
+ int parity = 0;
+ int fraction = 255/aa_factor;
+ coverage -= minx;
+#define CTX_EDGE(no) entries[edges[no].index]
+#define CTX_EDGE_YMIN(no) CTX_EDGE(no).data.s16[1]
+#define CTX_EDGE_X(no) (rasterizer->edges[no].x)
+ for (int t = 0; t < active_edges -1;)
+ {
+ int ymin = CTX_EDGE_YMIN (t);
+ int next_t = t + 1;
+ if (scanline != ymin)
+ {
+ if (winding)
+ { parity += ( (CTX_EDGE (t).code == CTX_EDGE_FLIPPED) ?1:-1); }
+ else
+ { parity = 1 - parity; }
+ }
+ if (parity)
+ {
+ int x0 = CTX_EDGE_X (t) / CTX_SUBDIV ;
+ int x1 = CTX_EDGE_X (next_t) / CTX_SUBDIV ;
+ int first = x0 / CTX_RASTERIZER_EDGE_MULTIPLIER;
+ int last = x1 / CTX_RASTERIZER_EDGE_MULTIPLIER;
- float rgba[4] = {0, 0, 0, 1.0};
- if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
- ctx_color_get_rgba (rasterizer->state, &color, rgba);
+ int graystart = 255 - ( (x0 * 256/CTX_RASTERIZER_EDGE_MULTIPLIER) & 0xff);
+ int grayend = (x1 * 256/CTX_RASTERIZER_EDGE_MULTIPLIER) & 0xff;
- CtxEntry set_color_command [3]=
- {
- ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
- ctx_f (CTX_CONT, rgba[1], rgba[2]),
- ctx_f (CTX_CONT, rgba[3], 0)
- };
- CtxEntry restore_command = ctx_void(CTX_RESTORE);
- float radius = rasterizer->state->gstate.shadow_blur;
- int dim = 2 * radius + 1;
- if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
- dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
- ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
+ if (first < minx)
+ { first = minx;
+ graystart=255;
+ }
+ if (last > maxx)
+ { last = maxx;
+ grayend=255;
+ }
+ if (first == last)
+ {
+ coverage[first] += (graystart-(255-grayend))/ aa_factor;
+ }
+ else if (first < last)
+ {
+ /*
+ if (aa_factor == 1)
+ {
+ coverage[first] += graystart;
+ for (int x = first + 1; x < last; x++)
+ coverage[x] = 255;
+ coverage[last] = grayend;
+ }
+ else
+ */
+ {
+ coverage[first] += graystart/ aa_factor;
+ for (int x = first + 1; x < last; x++)
+ coverage[x] += fraction;
+ coverage[last] += grayend/ aa_factor;
+ }
+ }
+ }
+ t = next_t;
+ }
+#if CTX_ENABLE_SHADOW_BLUR
+ if (rasterizer->in_shadow)
{
- for (int v = 0; v < dim; v ++)
- {
- int i = v;
- float dy = rasterizer->state->gstate.shadow_offset_y + v - dim/2;
- set_color_command[2].data.f[0] = rasterizer->kernel[i] * rgba[3];
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command);
- rasterizer->in_shadow = 1;
- rasterizer->shadow_x = rasterizer->state->gstate.shadow_offset_x;
- rasterizer->shadow_y = dy;
- rasterizer->preserve = 1;
- ctx_rasterizer_fill (rasterizer);
- rasterizer->in_shadow = 0;
- }
+ float radius = rasterizer->state->gstate.shadow_blur;
+ int dim = 2 * radius + 1;
+ if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
+ dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
+ {
+ uint16_t temp[maxx-minx+1];
+ memset (temp, 0, sizeof (temp));
+ for (int x = dim/2; x < maxx-minx + 1 - dim/2; x ++)
+ for (int u = 0; u < dim; u ++)
+ {
+ temp[x] += coverage[minx+x+u-dim/2] * rasterizer->kernel[u] * 256;
+ }
+ for (int x = 0; x < maxx-minx + 1; x ++)
+ coverage[minx+x] = temp[x] >> 8;
+ }
}
- ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
-}
#endif
-static void
-ctx_rasterizer_line_dash (CtxRasterizer *rasterizer, int count, float *dashes)
-{
- if (!dashes)
+#if CTX_ENABLE_CLIP
+ if (rasterizer->clip_buffer)
{
- rasterizer->state->gstate.n_dashes = 0;
- return;
+ /* perhaps not working right for clear? */
+ int y = scanline / rasterizer->aa;
+ uint8_t *clip_line = &((uint8_t*)(rasterizer->clip_buffer->data))[rasterizer->blit_width*y];
+ // XXX SIMD candidate
+ for (int x = minx; x <= maxx; x ++)
+ {
+#if CTX_1BIT_CLIP
+ coverage[x] = (coverage[x] * ((clip_line[x/8]&(1<<(x%8)))?255:0))/255;
+#else
+ coverage[x] = (coverage[x] * clip_line[x])/255;
+#endif
+ }
}
- count = CTX_MIN(count, CTX_PARSER_MAX_ARGS-1);
- rasterizer->state->gstate.n_dashes = count;
- memcpy(&rasterizer->state->gstate.dashes[0], dashes, count * sizeof(float));
- for (int i = 0; i < count; i ++)
+ if (rasterizer->aa == 1)
{
- if (rasterizer->state->gstate.dashes[i] < 0.0001f)
- rasterizer->state->gstate.dashes[i] = 0.0001f; // hang protection
+ for (int x = minx; x <= maxx; x ++)
+ coverage[x] = coverage[x] > 127?255:0;
}
+#endif
}
+#undef CTX_EDGE_Y0
+#undef CTX_EDGE
+
static void
-ctx_rasterizer_process (void *user_data, CtxCommand *command)
+ctx_rasterizer_reset (CtxRasterizer *rasterizer)
{
- CtxEntry *entry = &command->entry;
- CtxRasterizer *rasterizer = (CtxRasterizer *) user_data;
- CtxState *state = rasterizer->state;
- CtxCommand *c = (CtxCommand *) entry;
- int clear_clip = 0;
- switch (c->code)
- {
-#if CTX_ENABLE_SHADOW_BLUR
- case CTX_SHADOW_COLOR:
- {
- CtxColor col;
- CtxColor *color = &col;
- //state->gstate.source.type = CTX_SOURCE_COLOR;
- switch ((int)c->rgba.model)
- {
- case CTX_RGB:
- ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, 1.0f);
- break;
- case CTX_RGBA:
- //ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
- ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
- break;
- case CTX_DRGBA:
- ctx_color_set_drgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
- break;
-#if CTX_ENABLE_CMYK
- case CTX_CMYKA:
- ctx_color_set_cmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k,
c->cmyka.a);
- break;
- case CTX_CMYK:
- ctx_color_set_cmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, 1.0f);
- break;
- case CTX_DCMYKA:
- ctx_color_set_dcmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k,
c->cmyka.a);
- break;
- case CTX_DCMYK:
- ctx_color_set_dcmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, 1.0f);
- break;
-#endif
- case CTX_GRAYA:
- ctx_color_set_graya (state, color, c->graya.g, c->graya.a);
- break;
- case CTX_GRAY:
- ctx_color_set_graya (state, color, c->graya.g, 1.0f);
- break;
- }
- ctx_set_color (rasterizer->ctx, CTX_shadowColor, color);
- }
- break;
+#if CTX_RASTERIZER_FORCE_AA==0
+ rasterizer->pending_edges = 0;
#endif
- case CTX_LINE_DASH:
- if (c->line_dash.count)
- {
- ctx_rasterizer_line_dash (rasterizer, c->line_dash.count, c->line_dash.data);
- }
- else
- ctx_rasterizer_line_dash (rasterizer, 0, NULL);
- break;
+ rasterizer->active_edges = 0;
+ rasterizer->has_shape = 0;
+ rasterizer->has_prev = 0;
+ rasterizer->edge_list.count = 0; // ready for new edges
+ rasterizer->edge_pos = 0;
+ rasterizer->needs_aa = 0;
+ rasterizer->scanline = 0;
+ if (!rasterizer->preserve)
+ {
+ rasterizer->scan_min = 5000;
+ rasterizer->scan_max = -5000;
+ rasterizer->col_min = 5000;
+ rasterizer->col_max = -5000;
+ }
+ //rasterizer->comp_op = NULL;
+}
- case CTX_LINE_TO:
- ctx_rasterizer_line_to (rasterizer, c->c.x0, c->c.y0);
- break;
- case CTX_REL_LINE_TO:
- ctx_rasterizer_rel_line_to (rasterizer, c->c.x0, c->c.y0);
- break;
- case CTX_MOVE_TO:
- ctx_rasterizer_move_to (rasterizer, c->c.x0, c->c.y0);
- break;
- case CTX_REL_MOVE_TO:
- ctx_rasterizer_rel_move_to (rasterizer, c->c.x0, c->c.y0);
- break;
- case CTX_CURVE_TO:
- ctx_rasterizer_curve_to (rasterizer, c->c.x0, c->c.y0,
- c->c.x1, c->c.y1,
- c->c.x2, c->c.y2);
- break;
- case CTX_REL_CURVE_TO:
- ctx_rasterizer_rel_curve_to (rasterizer, c->c.x0, c->c.y0,
- c->c.x1, c->c.y1,
- c->c.x2, c->c.y2);
- break;
- case CTX_QUAD_TO:
- ctx_rasterizer_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
- break;
- case CTX_REL_QUAD_TO:
- 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);
- break;
- case CTX_RECTANGLE:
- ctx_rasterizer_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
- c->rectangle.width, c->rectangle.height);
- break;
- case CTX_ROUND_RECTANGLE:
- ctx_rasterizer_round_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
- c->rectangle.width, c->rectangle.height,
- c->rectangle.radius);
- break;
- case CTX_SET_PIXEL:
- ctx_rasterizer_set_pixel (rasterizer, c->set_pixel.x, c->set_pixel.y,
- c->set_pixel.rgba[0],
- c->set_pixel.rgba[1],
- c->set_pixel.rgba[2],
- c->set_pixel.rgba[3]);
- break;
- case CTX_TEXTURE:
- ctx_rasterizer_set_texture (rasterizer, ctx_arg_u32 (0),
- ctx_arg_float (2), ctx_arg_float (3) );
- rasterizer->comp_op = NULL;
- break;
-#if 0
- case CTX_LOAD_IMAGE:
- ctx_rasterizer_load_image (rasterizer, ctx_arg_string(),
- ctx_arg_float (0), ctx_arg_float (1) );
- break;
+static void
+ctx_rasterizer_rasterize_edges (CtxRasterizer *rasterizer, int winding
+#if CTX_SHAPE_CACHE
+ ,CtxShapeEntry *shape
#endif
-#if CTX_GRADIENTS
- case CTX_GRADIENT_STOP:
+ )
+{
+ uint8_t *dst = ( (uint8_t *) rasterizer->buf);
+ int aa = rasterizer->aa;
+
+ int scan_start = rasterizer->blit_y * aa;
+ int scan_end = scan_start + rasterizer->blit_height * aa;
+ int blit_width = rasterizer->blit_width;
+ int blit_max_x = rasterizer->blit_x + blit_width;
+ int minx = rasterizer->col_min / CTX_SUBDIV - rasterizer->blit_x;
+ int maxx = (rasterizer->col_max + CTX_SUBDIV-1) / CTX_SUBDIV - rasterizer->blit_x;
+
+#if 1
+ if (
+#if CTX_SHAPE_CACHE
+ !shape &&
+#endif
+ maxx > blit_max_x - 1)
+ { maxx = blit_max_x - 1; }
+#endif
+#if 1
+ if (rasterizer->state->gstate.clip_min_x>
+ minx)
+ { minx = rasterizer->state->gstate.clip_min_x; }
+ if (rasterizer->state->gstate.clip_max_x <
+ maxx)
+ { maxx = rasterizer->state->gstate.clip_max_x; }
+#endif
+ if (minx < 0)
+ { minx = 0; }
+ if (minx >= maxx)
+ {
+ ctx_rasterizer_reset (rasterizer);
+ return;
+ }
+#if CTX_SHAPE_CACHE
+ uint8_t _coverage[shape?2:maxx-minx+1];
+#else
+ uint8_t _coverage[maxx-minx+1];
+#endif
+ uint8_t *coverage = &_coverage[0];
+
+ ctx_compositor_setup_default (rasterizer);
+
+#if CTX_SHAPE_CACHE
+ if (shape)
+ {
+ coverage = &shape->data[0];
+ }
+#endif
+ ctx_assert (coverage);
+ rasterizer->scan_min -= (rasterizer->scan_min % aa);
+#if CTX_SHAPE_CACHE
+ if (shape)
+ {
+ scan_start = rasterizer->scan_min;
+ scan_end = rasterizer->scan_max;
+ }
+ else
+#endif
+ {
+ if (rasterizer->scan_min > scan_start)
{
- float rgba[4]= {ctx_u8_to_float (ctx_arg_u8 (4) ),
- ctx_u8_to_float (ctx_arg_u8 (4+1) ),
- ctx_u8_to_float (ctx_arg_u8 (4+2) ),
- ctx_u8_to_float (ctx_arg_u8 (4+3) )
- };
- ctx_rasterizer_gradient_add_stop (rasterizer,
- ctx_arg_float (0), rgba);
+ dst += (rasterizer->blit_stride * (rasterizer->scan_min-scan_start) / aa);
+ scan_start = rasterizer->scan_min;
}
- break;
- case CTX_LINEAR_GRADIENT:
- ctx_state_gradient_clear_stops (rasterizer->state);
- rasterizer->comp_op = NULL;
- break;
- case CTX_RADIAL_GRADIENT:
- ctx_state_gradient_clear_stops (rasterizer->state);
- rasterizer->comp_op = NULL;
- break;
+ if (rasterizer->scan_max < scan_end)
+ { scan_end = rasterizer->scan_max; }
+ }
+ if (rasterizer->state->gstate.clip_min_y * aa > scan_start )
+ {
+ dst += (rasterizer->blit_stride * (rasterizer->state->gstate.clip_min_y * aa -scan_start) / aa);
+ scan_start = rasterizer->state->gstate.clip_min_y * aa;
+ }
+ if (rasterizer->state->gstate.clip_max_y * aa < scan_end)
+ { scan_end = rasterizer->state->gstate.clip_max_y * aa; }
+ if (scan_start > scan_end ||
+ (scan_start > (rasterizer->blit_y + rasterizer->blit_height) * aa) ||
+ (scan_end < (rasterizer->blit_y) * aa))
+ {
+ /* not affecting this rasterizers scanlines */
+ ctx_rasterizer_reset (rasterizer);
+ return;
+ }
+ ctx_rasterizer_sort_edges (rasterizer);
+ if (maxx>minx)
+ {
+#if CTX_RASTERIZER_FORCE_AA==0
+ int halfstep2 = aa/2;
+ int halfstep = aa/2 + 1;
#endif
- case CTX_PRESERVE:
- rasterizer->preserve = 1;
- break;
- case CTX_COLOR:
- case CTX_COMPOSITING_MODE:
- case CTX_BLEND_MODE:
- rasterizer->comp_op = NULL;
- break;
-#if CTX_COMPOSITING_GROUPS
- case CTX_START_GROUP:
- ctx_rasterizer_start_group (rasterizer);
- break;
- case CTX_END_GROUP:
- ctx_rasterizer_end_group (rasterizer);
- break;
+ rasterizer->needs_aa = 0;
+ rasterizer->scanline = scan_start-aa*200;
+ ctx_rasterizer_feed_edges (rasterizer);
+ ctx_rasterizer_discard_edges (rasterizer);
+ ctx_rasterizer_increment_edges (rasterizer, aa * 200);
+ rasterizer->scanline = scan_start;
+ ctx_rasterizer_feed_edges (rasterizer);
+ ctx_rasterizer_discard_edges (rasterizer);
+
+ for (rasterizer->scanline = scan_start; rasterizer->scanline <= scan_end;)
+ {
+ ctx_memset (coverage, 0,
+#if CTX_SHAPE_CACHE
+ shape?shape->width:
+#endif
+ sizeof (_coverage) );
+#if CTX_RASTERIZER_FORCE_AA==1
+ rasterizer->needs_aa = 1;
#endif
- case CTX_RESTORE:
- for (int i = state->gstate_no?state->gstate_stack[state->gstate_no-1].keydb_pos:0;
- i < state->gstate.keydb_pos; i++)
+#if CTX_RASTERIZER_FORCE_AA==0
+ if (rasterizer->needs_aa
+ || rasterizer->pending_edges
+ || rasterizer->ending_edges
+ || rasterizer->force_aa
+ || aa == 1
+ )
+#endif
{
- if (state->keydb[i].key == CTX_clip)
+ switch (aa)
{
- clear_clip = 1;
+#if CTX_FORCE_INLINES
+ case 5:
+ if (winding)
+ for (int i = 0; i < 5; i++)
+ {
+ ctx_rasterizer_sort_active_edges (rasterizer);
+ ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, 1, 5);
+ rasterizer->scanline ++;
+ ctx_rasterizer_increment_edges (rasterizer, 1);
+ ctx_rasterizer_feed_edges (rasterizer);
+ ctx_rasterizer_discard_edges (rasterizer);
+ }
+ else
+ for (int i = 0; i < 5; i++)
+ {
+ ctx_rasterizer_sort_active_edges (rasterizer);
+ ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, 1, 5);
+ rasterizer->scanline ++;
+ ctx_rasterizer_increment_edges (rasterizer, 1);
+ ctx_rasterizer_feed_edges (rasterizer);
+ ctx_rasterizer_discard_edges (rasterizer);
+ }
+ break;
+ case 15: /* */
+ if (winding)
+ for (int i = 0; i < 15; i++)
+ {
+ ctx_rasterizer_sort_active_edges (rasterizer);
+ ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, 1, 15);
+ rasterizer->scanline ++;
+ ctx_rasterizer_increment_edges (rasterizer, 1);
+ ctx_rasterizer_feed_edges (rasterizer);
+ ctx_rasterizer_discard_edges (rasterizer);
+ }
+ else
+ for (int i = 0; i < 15; i++)
+ {
+ ctx_rasterizer_sort_active_edges (rasterizer);
+ ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, 0, 15);
+ rasterizer->scanline ++;
+ ctx_rasterizer_increment_edges (rasterizer, 1);
+ ctx_rasterizer_feed_edges (rasterizer);
+ ctx_rasterizer_discard_edges (rasterizer);
+ }
+ break;
+#endif
+ default:
+ for (int i = 0; i < aa; i++)
+ {
+ ctx_rasterizer_sort_active_edges (rasterizer);
+ ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, winding, aa);
+ rasterizer->scanline ++;
+ ctx_rasterizer_increment_edges (rasterizer, 1);
+ ctx_rasterizer_feed_edges (rasterizer);
+ ctx_rasterizer_discard_edges (rasterizer);
+ }
}
}
- /* FALLTHROUGH */
- case CTX_ROTATE:
- case CTX_SCALE:
- case CTX_TRANSLATE:
- case CTX_SAVE:
- rasterizer->comp_op = NULL;
- rasterizer->uses_transforms = 1;
- ctx_interpret_transforms (rasterizer->state, entry, NULL);
- if (clear_clip)
- {
- ctx_rasterizer_clip_reset (rasterizer);
- for (int i = state->gstate_no?state->gstate_stack[state->gstate_no-1].keydb_pos:0;
- i < state->gstate.keydb_pos; i++)
+#if CTX_RASTERIZER_FORCE_AA==0
+ else
{
- if (state->keydb[i].key == CTX_clip)
- {
- int idx = ctx_float_to_string_index (state->keydb[i].value);
- if (idx >=0)
- {
- CtxEntry *edges = (CtxEntry*)&state->stringpool[idx];
- ctx_rasterizer_clip_apply (rasterizer, edges);
- }
- }
- }
+ ctx_rasterizer_increment_edges (rasterizer, halfstep);
+ ctx_rasterizer_sort_active_edges (rasterizer);
+ ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, winding, 1);
+ ctx_rasterizer_increment_edges (rasterizer, halfstep2);
+ rasterizer->scanline += aa;
+ ctx_rasterizer_feed_edges (rasterizer);
+ ctx_rasterizer_discard_edges (rasterizer);
}
- break;
- case CTX_STROKE:
-#if CTX_ENABLE_SHADOW_BLUR
- if (rasterizer->state->gstate.shadow_blur > 0.0 &&
- !rasterizer->in_text)
- ctx_rasterizer_shadow_stroke (rasterizer);
#endif
- if (rasterizer->state->gstate.n_dashes)
{
- int n_dashes = rasterizer->state->gstate.n_dashes;
- float *dashes = rasterizer->state->gstate.dashes;
-
- float factor =
- ctx_maxf (ctx_maxf (ctx_fabsf (state->gstate.transform.m[0][0]),
- ctx_fabsf (state->gstate.transform.m[0][1]) ),
- ctx_maxf (ctx_fabsf (state->gstate.transform.m[1][0]),
- ctx_fabsf (state->gstate.transform.m[1][1]) ) );
-
- int count = rasterizer->edge_list.count;
- int aa = rasterizer->aa;
- CtxEntry temp[count]; /* copy of already built up path's poly line */
- memcpy (temp, rasterizer->edge_list.entries, sizeof (temp));
- int start = 0;
- int end = 0;
- CtxMatrix transform_backup = rasterizer->state->gstate.transform;
- ctx_matrix_identity (&rasterizer->state->gstate.transform);
- 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;
-
- int dash_no = 0.0;
- float dash_lpos = 0.0;
- int is_down = 0;
-
- while (start < count)
- {
- int started = 0;
- int i;
- is_down = 0;
-
- if (!is_down)
- {
- CtxEntry *entry = &temp[0];
- prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
- prev_y = entry->data.s16[1] * 1.0f / aa;
- ctx_rasterizer_move_to (rasterizer, prev_x, prev_y);
- is_down = 1;
- }
-
-
- for (i = start; i < count; i++)
+#if CTX_SHAPE_CACHE
+ if (shape == NULL)
+#endif
{
- CtxEntry *entry = &temp[i];
- float x, y;
- if (entry->code == CTX_NEW_EDGE)
- {
- if (started)
- {
- end = i - 1;
- dash_no = 0;
- dash_lpos = 0.0;
- goto foo;
- }
- prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
- prev_y = entry->data.s16[1] * 1.0f / aa;
- started = 1;
- start = i;
- is_down = 1;
- ctx_rasterizer_move_to (rasterizer, prev_x, prev_y);
- }
-
-again:
-
- x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
- y = entry->data.s16[3] * 1.0f / aa;
- float dx = x - prev_x;
- float dy = y - prev_y;
- float length = ctx_fast_hypotf (dx, dy);
-
-
- if (dash_lpos + length >= dashes[dash_no] * factor)
- {
- float p = (dashes[dash_no] * factor - dash_lpos) / length;
- float splitx = x * p + (1.0f - p) * prev_x;
- float splity = y * p + (1.0f - p) * prev_y;
- if (is_down)
- {
- ctx_rasterizer_line_to (rasterizer, splitx, splity);
- is_down = 0;
- }
- else
- {
- ctx_rasterizer_move_to (rasterizer, splitx, splity);
- is_down = 1;
- }
- prev_x = splitx;
- prev_y = splity;
- dash_no++;
- dash_lpos=0;
- if (dash_no >= n_dashes) dash_no = 0;
- goto again;
- }
- else
+#if 0
+ if (aa==1)
{
- pos += length;
- dash_lpos += length;
- {
- if (is_down)
- ctx_rasterizer_line_to (rasterizer, x, y);
- }
+ for (int x = 0; x < maxx-minx; x++)
+ coverage
}
- prev_x = x;
- prev_y = y;
+#endif
+ ctx_rasterizer_apply_coverage (rasterizer,
+ &dst[(minx * rasterizer->format->bpp) /8],
+ minx,
+ coverage, maxx-minx + 1);
}
- end = i-1;
-foo:
- start = end+1;
}
- rasterizer->state->gstate.transform = transform_backup;
+#if CTX_SHAPE_CACHE
+ if (shape)
+ {
+ coverage += shape->width;
}
-
- ctx_rasterizer_stroke (rasterizer);
- break;
- case CTX_FONT:
- ctx_rasterizer_set_font (rasterizer, ctx_arg_string() );
- break;
- case CTX_TEXT:
- rasterizer->in_text++;
-#if CTX_ENABLE_SHADOW_BLUR
- if (rasterizer->state->gstate.shadow_blur > 0.0)
- ctx_rasterizer_shadow_text (rasterizer, ctx_arg_string ());
-#endif
- ctx_rasterizer_text (rasterizer, ctx_arg_string(), 0);
- rasterizer->in_text--;
- ctx_rasterizer_reset (rasterizer);
- break;
- case CTX_TEXT_STROKE:
- ctx_rasterizer_text (rasterizer, ctx_arg_string(), 1);
- ctx_rasterizer_reset (rasterizer);
- break;
- case CTX_GLYPH:
- ctx_rasterizer_glyph (rasterizer, entry[0].data.u32[0], entry[0].data.u8[4]);
- break;
- case CTX_FILL:
-#if CTX_ENABLE_SHADOW_BLUR
- if (rasterizer->state->gstate.shadow_blur > 0.0 &&
- !rasterizer->in_text)
- ctx_rasterizer_shadow_fill (rasterizer);
#endif
- ctx_rasterizer_fill (rasterizer);
- break;
- case CTX_RESET:
- case CTX_BEGIN_PATH:
- ctx_rasterizer_reset (rasterizer);
- break;
- case CTX_CLIP:
- ctx_rasterizer_clip (rasterizer);
- break;
- case CTX_CLOSE_PATH:
- ctx_rasterizer_finish_shape (rasterizer);
- break;
+ dst += rasterizer->blit_stride;
}
- ctx_interpret_pos_bare (rasterizer->state, entry, NULL);
- ctx_interpret_style (rasterizer->state, entry, NULL);
-}
-
-void
-ctx_rasterizer_deinit (CtxRasterizer *rasterizer)
-{
- ctx_drawlist_deinit (&rasterizer->edge_list);
-#if CTX_ENABLE_CLIP
- if (rasterizer->clip_buffer)
- {
- ctx_buffer_free (rasterizer->clip_buffer);
- rasterizer->clip_buffer = NULL;
}
-#endif
-#if CTX_SHAPE_CACHE
- for (int i = 0; i < CTX_SHAPE_CACHE_ENTRIES; i ++)
- if (rasterizer->shape_cache.entries[i])
- {
- free (rasterizer->shape_cache.entries[i]);
- rasterizer->shape_cache.entries[i] = NULL;
- }
-#endif
- free (rasterizer);
-}
-
-int ctx_renderer_is_sdl (Ctx *ctx);
-int ctx_renderer_is_fb (Ctx *ctx);
-
-static int _ctx_is_rasterizer (Ctx *ctx);
-CtxAntialias ctx_get_antialias (Ctx *ctx)
-{
-#if CTX_EVENTS
- if (ctx_renderer_is_sdl (ctx) || ctx_renderer_is_fb (ctx))
+ if (rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_OUT ||
+ rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_IN ||
+ rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_DESTINATION_IN ||
+ rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_COPY ||
+ rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_DESTINATION_ATOP ||
+ rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_CLEAR)
{
- CtxThreaded *fb = (CtxThreaded*)(ctx->renderer);
- return fb->antialias;
- }
-#endif
- if (!_ctx_is_rasterizer (ctx)) return CTX_ANTIALIAS_DEFAULT;
+ /* fill in the rest of the blitrect when compositing mode permits it */
+ uint8_t nocoverage[rasterizer->blit_width];
+ //int gscan_start = rasterizer->state->gstate.clip_min_y * aa;
+ int gscan_start = rasterizer->state->gstate.clip_min_y * aa;
+ int gscan_end = rasterizer->state->gstate.clip_max_y * aa;
+ memset (nocoverage, 0, sizeof(nocoverage));
+ int startx = rasterizer->state->gstate.clip_min_x;
+ int endx = rasterizer->state->gstate.clip_max_x;
+ int clipw = endx-startx + 1;
+ uint8_t *dst = ( (uint8_t *) rasterizer->buf);
- switch (((CtxRasterizer*)(ctx->renderer))->aa)
- {
- case 1: return CTX_ANTIALIAS_NONE;
- case 3: return CTX_ANTIALIAS_FAST;
- case 5: return CTX_ANTIALIAS_GOOD;
- default:
- case 15: return CTX_ANTIALIAS_DEFAULT;
- case 17: return CTX_ANTIALIAS_BEST;
- }
-}
-
-int _ctx_antialias_to_aa (CtxAntialias antialias)
-{
- switch (antialias)
- {
- case CTX_ANTIALIAS_NONE: return 1;
- case CTX_ANTIALIAS_FAST: return 3;
- case CTX_ANTIALIAS_GOOD: return 5;
- default:
- case CTX_ANTIALIAS_DEFAULT: return CTX_RASTERIZER_AA;
- case CTX_ANTIALIAS_BEST: return 17;
- }
-}
+ dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (gscan_start / aa);
+ for (rasterizer->scanline = gscan_start; rasterizer->scanline < scan_start;)
+ {
+ ctx_rasterizer_apply_coverage (rasterizer,
+ &dst[ (startx * rasterizer->format->bpp) /8],
+ 0,
+ nocoverage, clipw);
+ rasterizer->scanline += aa;
+ dst += rasterizer->blit_stride;
+ }
+ if (minx < startx)
+ {
+ dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_start / aa);
+ for (rasterizer->scanline = scan_start; rasterizer->scanline < scan_end;)
+ {
+ ctx_rasterizer_apply_coverage (rasterizer,
+ &dst[ (startx * rasterizer->format->bpp) /8],
+ 0,
+ nocoverage, minx-startx);
+ dst += rasterizer->blit_stride;
+ }
+ }
+ if (endx > maxx)
+ {
+ dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_start / aa);
+ for (rasterizer->scanline = scan_start; rasterizer->scanline < scan_end;)
+ {
+ ctx_rasterizer_apply_coverage (rasterizer,
+ &dst[ (maxx * rasterizer->format->bpp) /8],
+ 0,
+ nocoverage, endx-maxx);
-void
-ctx_set_antialias (Ctx *ctx, CtxAntialias antialias)
-{
-#if CTX_EVENTS
- if (ctx_renderer_is_sdl (ctx) || ctx_renderer_is_fb (ctx))
- {
- CtxThreaded *fb = (CtxThreaded*)(ctx->renderer);
- fb->antialias = antialias;
- for (int i = 0; i < _ctx_max_threads; i++)
+ rasterizer->scanline += aa;
+ dst += rasterizer->blit_stride;
+ }
+ }
+ dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_end / aa);
+ // XXX valgrind/asan this
+ if(0)for (rasterizer->scanline = scan_end; rasterizer->scanline/aa < gscan_end-1;)
{
- ctx_set_antialias (fb->host[i], antialias);
+ ctx_rasterizer_apply_coverage (rasterizer,
+ &dst[ (startx * rasterizer->format->bpp) /8],
+ 0,
+ nocoverage, clipw-1);
+
+ rasterizer->scanline += aa;
+ dst += rasterizer->blit_stride;
}
- return;
}
-#endif
- if (!_ctx_is_rasterizer (ctx)) return;
-
- ((CtxRasterizer*)(ctx->renderer))->aa =
- _ctx_antialias_to_aa (antialias);
-/* vertical level of supersampling at full/forced AA.
- *
- * 1 is none, 3 is fast 5 is good 15 or 17 is best for 8bit
- *
- * valid values: - for other values we do not add up to 255
- * 3 5 15 17 51
- *
- */
+ ctx_rasterizer_reset (rasterizer);
}
-CtxRasterizer *
-ctx_rasterizer_init (CtxRasterizer *rasterizer, Ctx *ctx, Ctx *texture_source, CtxState *state, void *data,
int x, int y, int width, int height, int stride, CtxPixelFormat pixel_format, CtxAntialias antialias)
-{
-#if CTX_ENABLE_CLIP
- if (rasterizer->clip_buffer)
- ctx_buffer_free (rasterizer->clip_buffer);
-#endif
- if (rasterizer->edge_list.size)
- ctx_drawlist_deinit (&rasterizer->edge_list);
-
- ctx_memset (rasterizer, 0, sizeof (CtxRasterizer) );
- rasterizer->vfuncs.process = ctx_rasterizer_process;
- rasterizer->vfuncs.free = (CtxDestroyNotify)ctx_rasterizer_deinit;
- rasterizer->edge_list.flags |= CTX_DRAWLIST_EDGE_LIST;
- rasterizer->state = state;
- rasterizer->ctx = ctx;
- rasterizer->texture_source = texture_source?texture_source:ctx;
- rasterizer->aa = _ctx_antialias_to_aa (antialias);
- rasterizer->force_aa = 0;
- ctx_state_init (rasterizer->state);
- rasterizer->buf = data;
- rasterizer->blit_x = x;
- rasterizer->blit_y = y;
- rasterizer->blit_width = width;
- rasterizer->blit_height = height;
- rasterizer->state->gstate.clip_min_x = x;
- rasterizer->state->gstate.clip_min_y = y;
- rasterizer->state->gstate.clip_max_x = x + width - 1;
- rasterizer->state->gstate.clip_max_y = y + height - 1;
- rasterizer->blit_stride = stride;
- rasterizer->scan_min = 5000;
- rasterizer->scan_max = -5000;
- rasterizer->format = ctx_pixel_format_info (pixel_format);
-
- return rasterizer;
-}
-Ctx *
-ctx_new_for_buffer (CtxBuffer *buffer)
+static int
+ctx_rasterizer_fill_rect (CtxRasterizer *rasterizer,
+ int x0,
+ int y0,
+ int x1,
+ int y1)
{
- Ctx *ctx = ctx_new ();
- ctx_set_renderer (ctx,
- ctx_rasterizer_init ( (CtxRasterizer *) malloc (sizeof (CtxRasterizer) ),
- ctx, NULL, &ctx->state,
- buffer->data, 0, 0, buffer->width, buffer->height,
- buffer->stride, buffer->format->pixel_format,
- CTX_ANTIALIAS_DEFAULT));
- return ctx;
+ int aa = rasterizer->aa;
+ if (x0>x1) { // && y0>y1) {
+ int tmp = x1;
+ x1 = x0;
+ x0 = tmp;
+ tmp = y1;
+ y1 = y0;
+ y0 = tmp;
+ }
+ if (x1 % CTX_SUBDIV ||
+ x0 % CTX_SUBDIV ||
+ y1 % aa ||
+ y0 % aa)
+ { return 0; }
+ x1 /= CTX_SUBDIV;
+ x0 /= CTX_SUBDIV;
+ y1 /= aa;
+ y0 /= aa;
+ uint8_t coverage[x1-x0 + 1];
+ uint8_t *dst = ( (uint8_t *) rasterizer->buf);
+ ctx_compositor_setup_default (rasterizer);
+ ctx_memset (coverage, 0xff, sizeof (coverage) );
+ if (x0 < rasterizer->blit_x)
+ { x0 = rasterizer->blit_x; }
+ if (y0 < rasterizer->blit_y)
+ { y0 = rasterizer->blit_y; }
+ if (y1 > rasterizer->blit_y + rasterizer->blit_height)
+ { y1 = rasterizer->blit_y + rasterizer->blit_height; }
+ if (x1 > rasterizer->blit_x + rasterizer->blit_width)
+ { x1 = rasterizer->blit_x + rasterizer->blit_width; }
+ dst += (y0 - rasterizer->blit_y) * rasterizer->blit_stride;
+ int width = x1 - x0;
+ if (width > 0)
+ {
+ rasterizer->scanline = y0 * aa;
+ for (int y = y0; y < y1; y++)
+ {
+ rasterizer->scanline += aa;
+ ctx_rasterizer_apply_coverage (rasterizer,
+ &dst[ (x0) * rasterizer->format->bpp/8],
+ x0,
+ coverage, width);
+ dst += rasterizer->blit_stride;
+ }
+ }
+ return 1;
}
-Ctx *
-ctx_new_for_framebuffer (void *data, int width, int height,
- int stride,
- CtxPixelFormat pixel_format)
+inline static int
+ctx_is_transparent (CtxRasterizer *rasterizer, int stroke)
{
- Ctx *ctx = ctx_new ();
- CtxRasterizer *r = ctx_rasterizer_init ( (CtxRasterizer *) ctx_calloc (sizeof (CtxRasterizer), 1),
- ctx, NULL, &ctx->state, data, 0, 0, width, height,
- stride, pixel_format, CTX_ANTIALIAS_DEFAULT);
- ctx_set_renderer (ctx, r);
- return ctx;
+ CtxGState *gstate = &rasterizer->state->gstate;
+ if (gstate->global_alpha_u8 == 0)
+ return 1;
+ if (gstate->source_fill.type == CTX_SOURCE_COLOR)
+ {
+ uint8_t ga[2];
+ ctx_color_get_graya_u8 (rasterizer->state, &gstate->source_fill.color, ga);
+ if (ga[1] == 0)
+ return 1;
+ }
+ return 0;
}
-// ctx_new_for_stream (FILE *stream);
-
-#if 0
-CtxRasterizer *ctx_rasterizer_new (void *data, int x, int y, int width, int height,
- int stride, CtxPixelFormat pixel_format)
+static void
+ctx_rasterizer_fill (CtxRasterizer *rasterizer)
{
- CtxState *state = (CtxState *) malloc (sizeof (CtxState) );
- CtxRasterizer *rasterizer = (CtxRasterizer *) malloc (sizeof (CtxRenderer) );
- ctx_rasterizer_init (rasterizer, state, data, x, y, width, height,
- stride, pixel_format, CTX_ANTIALIAS_DEFAULT);
-}
-#endif
-
-CtxPixelFormatInfo *ctx_pixel_formats = NULL;
-
-extern CtxPixelFormatInfo ctx_pixel_formats_default[];
+ int count = rasterizer->preserve?rasterizer->edge_list.count:0;
+ int aa = rasterizer->aa;
+ CtxEntry temp[count]; /* copy of already built up path's poly line
+ XXX - by building a large enough path
+ the stack can be smashed!
+ */
+ if (rasterizer->preserve)
+ { memcpy (temp, rasterizer->edge_list.entries, sizeof (temp) ); }
-CtxPixelFormatInfo *
-ctx_pixel_format_info (CtxPixelFormat format)
-{
- if (!ctx_pixel_formats)
+#if CTX_ENABLE_SHADOW_BLUR
+ if (rasterizer->in_shadow)
{
- ctx_pixel_formats = ctx_pixel_formats_default;
-
+ for (int i = 0; i < rasterizer->edge_list.count; i++)
+ {
+ CtxEntry *entry = &rasterizer->edge_list.entries[i];
+ entry->data.s16[2] += rasterizer->shadow_x * CTX_SUBDIV;
+ entry->data.s16[3] += rasterizer->shadow_y * aa;
+ }
+ rasterizer->scan_min += rasterizer->shadow_y * aa;
+ rasterizer->scan_max += rasterizer->shadow_y * aa;
+ rasterizer->col_min += (rasterizer->shadow_x - rasterizer->state->gstate.shadow_blur * 3 + 1) *
CTX_SUBDIV;
+ rasterizer->col_max += (rasterizer->shadow_x + rasterizer->state->gstate.shadow_blur * 3 + 1) *
CTX_SUBDIV;
}
+#endif
- for (unsigned int i = 0; ctx_pixel_formats[i].pixel_format; i++)
+ if (ctx_is_transparent (rasterizer, 0) ||
+ rasterizer->scan_min / aa > rasterizer->blit_y + rasterizer->blit_height ||
+ rasterizer->scan_max / aa < rasterizer->blit_y ||
+ rasterizer->col_min / CTX_SUBDIV > rasterizer->blit_x + rasterizer->blit_width ||
+ rasterizer->col_max / CTX_SUBDIV < rasterizer->blit_x)
{
- if (ctx_pixel_formats[i].pixel_format == format)
- {
- return &ctx_pixel_formats[i];
- }
+ ctx_rasterizer_reset (rasterizer);
}
- return NULL;
-}
-#else
+ else
+ {
+ ctx_compositor_setup_default (rasterizer);
-CtxPixelFormatInfo *
-ctx_pixel_format_info (CtxPixelFormat format)
-{
- return NULL;
-}
+ rasterizer->state->min_x =
+ ctx_mini (rasterizer->state->min_x, rasterizer->col_min / CTX_SUBDIV);
+ rasterizer->state->max_x =
+ ctx_maxi (rasterizer->state->max_x, rasterizer->col_max / CTX_SUBDIV);
+ rasterizer->state->min_y =
+ ctx_mini (rasterizer->state->min_y, rasterizer->scan_min / aa);
+ rasterizer->state->max_y =
+ ctx_maxi (rasterizer->state->max_y, rasterizer->scan_max / aa);
+ if (rasterizer->edge_list.count == 6)
+ {
+ CtxEntry *entry0 = &rasterizer->edge_list.entries[0];
+ CtxEntry *entry1 = &rasterizer->edge_list.entries[1];
+ CtxEntry *entry2 = &rasterizer->edge_list.entries[2];
+ CtxEntry *entry3 = &rasterizer->edge_list.entries[3];
+ if (!rasterizer->state->gstate.clipped &&
+ (entry0->data.s16[2] == entry1->data.s16[2]) &&
+ (entry0->data.s16[3] == entry3->data.s16[3]) &&
+ (entry1->data.s16[3] == entry2->data.s16[3]) &&
+ (entry2->data.s16[2] == entry3->data.s16[2]) &&
+ ((entry3->data.s16[2] & (CTX_SUBDIV-1)) == 0) &&
+ ((entry3->data.s16[3] & (aa-1)) == 0)
+#if CTX_ENABLE_SHADOW_BLUR
+ && !rasterizer->in_shadow
#endif
+ )
+ if (ctx_rasterizer_fill_rect (rasterizer,
+ entry3->data.s16[2],
+ entry3->data.s16[3],
+ entry1->data.s16[2],
+ entry1->data.s16[3]) )
+ {
+ ctx_rasterizer_reset (rasterizer);
+ goto done;
+ }
+ }
+ ctx_rasterizer_finish_shape (rasterizer);
-void
-ctx_current_point (Ctx *ctx, float *x, float *y)
-{
- if (!ctx)
- {
- if (x) { *x = 0.0f; }
- if (y) { *y = 0.0f; }
- }
-#if CTX_RASTERIZER
- if (ctx->renderer)
+ uint32_t hash = ctx_rasterizer_poly_to_edges (rasterizer);
+ if (hash){};
+
+#if CTX_SHAPE_CACHE
+ int width = (rasterizer->col_max + (CTX_SUBDIV-1) ) / CTX_SUBDIV - rasterizer->col_min/CTX_SUBDIV + 1;
+ int height = (rasterizer->scan_max + (aa-1) ) / aa - rasterizer->scan_min / aa + 1;
+ if (width * height < CTX_SHAPE_CACHE_DIM && width >=1 && height >= 1
+ && width < CTX_SHAPE_CACHE_MAX_DIM
+ && height < CTX_SHAPE_CACHE_MAX_DIM
+#if CTX_ENABLE_SHADOW_BLUR
+ && !rasterizer->in_shadow
+#endif
+ )
+ {
+ int scan_min = rasterizer->scan_min;
+ int col_min = rasterizer->col_min;
+ scan_min -= (scan_min % aa);
+ int y0 = scan_min / aa;
+ int y1 = y0 + height;
+ int x0 = col_min / CTX_SUBDIV;
+ int ymin = y0;
+ int x1 = x0 + width;
+ int clip_x_min = rasterizer->blit_x;
+ int clip_x_max = rasterizer->blit_x + rasterizer->blit_width - 1;
+ int clip_y_min = rasterizer->blit_y;
+ int clip_y_max = rasterizer->blit_y + rasterizer->blit_height - 1;
+
+ int dont_cache = 0;
+ if (x1 >= clip_x_max)
+ { x1 = clip_x_max;
+ dont_cache = 1;
+ }
+ int xo = 0;
+ if (x0 < clip_x_min)
+ {
+ xo = clip_x_min - x0;
+ x0 = clip_x_min;
+ dont_cache = 1;
+ }
+ if (y0 < clip_y_min || y1 >= clip_y_max)
+ dont_cache = 1;
+ if (dont_cache)
+ {
+ ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule
+#if CTX_SHAPE_CACHE
+ , NULL
+#endif
+ );
+ }
+ else
+ {
+
+ rasterizer->scanline = scan_min;
+ CtxShapeEntry *shape = ctx_shape_entry_find (rasterizer, hash, width, height);
+
+ if (shape->uses == 0)
+ {
+ CtxBuffer *buffer_backup = rasterizer->clip_buffer;
+ rasterizer->clip_buffer = NULL;
+ ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule, shape);
+ rasterizer->clip_buffer = buffer_backup;
+ }
+ rasterizer->scanline = scan_min;
+
+ int ewidth = x1 - x0;
+ if (ewidth>0)
+ {
+ if (rasterizer->clip_buffer && !rasterizer->clip_rectangle)
+ {
+ uint8_t composite[ewidth];
+ for (int y = y0; y < y1; y++)
+ {
+ if ( (y >= clip_y_min) && (y <= clip_y_max) )
+ {
+ for (int x = 0; x < ewidth; x++)
+ {
+ int val = shape->data[shape->width * (int)(y-ymin) + xo + x];
+ // XXX : not valid for 1bit clip buffers
+ val = (val*((uint8_t*)rasterizer->clip_buffer->data) [
+ ((y-rasterizer->blit_y) * rasterizer->blit_width) + x0 + x])/255;
+ composite[x] = val;
+ }
+ ctx_rasterizer_apply_coverage (rasterizer,
+ ( (uint8_t *) rasterizer->buf) + (y-rasterizer->blit_y) *
rasterizer->blit_stride + (int) (x0) * rasterizer->format->bpp/8,
+ x0, // is 0
+ composite,
+ ewidth );
+ rasterizer->scanline += aa;
+ }
+ }
+ }
+ else
+ for (int y = y0; y < y1; y++)
+ {
+ if ( (y >= clip_y_min) && (y <= clip_y_max) )
+ {
+ ctx_rasterizer_apply_coverage (rasterizer,
+ ( (uint8_t *) rasterizer->buf) + (y-rasterizer->blit_y) *
rasterizer->blit_stride + (int) (x0) * rasterizer->format->bpp/8,
+ x0,
+ &shape->data[shape->width * (int) (y-ymin) + xo],
+ ewidth );
+ }
+ rasterizer->scanline += aa;
+ }
+ }
+ if (shape->uses != 0)
+ {
+ ctx_rasterizer_reset (rasterizer);
+ }
+ }
+ }
+ else
+#endif
+ ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule
+#if CTX_SHAPE_CACHE
+ , NULL
+#endif
+ );
+ }
+ done:
+ if (rasterizer->preserve)
{
- if (x) { *x = ( (CtxRasterizer *) (ctx->renderer) )->x; }
- if (y) { *y = ( (CtxRasterizer *) (ctx->renderer) )->y; }
- return;
+ memcpy (rasterizer->edge_list.entries, temp, sizeof (temp) );
+ rasterizer->edge_list.count = count;
}
+#if CTX_ENABLE_SHADOW_BLUR
+ if (rasterizer->in_shadow)
+ {
+ rasterizer->scan_min -= rasterizer->shadow_y * aa;
+ rasterizer->scan_max -= rasterizer->shadow_y * aa;
+ rasterizer->col_min -= (rasterizer->shadow_x - rasterizer->state->gstate.shadow_blur * 3 + 1) *
CTX_SUBDIV;
+ rasterizer->col_max -= (rasterizer->shadow_x + rasterizer->state->gstate.shadow_blur * 3 + 1) *
CTX_SUBDIV;
+ }
#endif
- if (x) { *x = ctx->state.x; }
- if (y) { *y = ctx->state.y; }
+ rasterizer->preserve = 0;
}
-float ctx_x (Ctx *ctx)
+#if 0
+static void
+ctx_rasterizer_triangle (CtxRasterizer *rasterizer,
+ int x0, int y0,
+ int x1, int y1,
+ int x2, int y2,
+ int r0, int g0, int b0, int a0,
+ int r1, int g1, int b1, int a1,
+ int r2, int g2, int b2, int a2,
+ int u0, int v0,
+ int u1, int v1)
{
- float x = 0, y = 0;
- ctx_current_point (ctx, &x, &y);
- return x;
+
}
+#endif
-float ctx_y (Ctx *ctx)
+
+typedef struct _CtxTermGlyph CtxTermGlyph;
+
+struct _CtxTermGlyph
{
- float x = 0, y = 0;
- ctx_current_point (ctx, &x, &y);
- return y;
+ uint32_t unichar;
+ int col;
+ int row;
+ uint8_t rgba_bg[4];
+ uint8_t rgba_fg[4];
+};
+
+static int _ctx_glyph (Ctx *ctx, uint32_t unichar, int stroke);
+static void
+ctx_rasterizer_glyph (CtxRasterizer *rasterizer, uint32_t unichar, int stroke)
+{
+ float tx = rasterizer->state->x;
+ float ty = rasterizer->state->y - rasterizer->state->gstate.font_size;
+ float tx2 = rasterizer->state->x + rasterizer->state->gstate.font_size;
+ float ty2 = rasterizer->state->y + rasterizer->state->gstate.font_size;
+ _ctx_user_to_device (rasterizer->state, &tx, &ty);
+ _ctx_user_to_device (rasterizer->state, &tx2, &ty2);
+
+ if (tx2 < rasterizer->blit_x || ty2 < rasterizer->blit_y) return;
+ if (tx > rasterizer->blit_x + rasterizer->blit_width ||
+ ty > rasterizer->blit_y + rasterizer->blit_height)
+ return;
+
+#if CTX_BRAILLE_TEXT
+ float font_size = 0;
+ int ch = 1;
+ int cw = 1;
+
+ if (rasterizer->term_glyphs)
+ {
+ float tx = 0;
+ float ty = rasterizer->state->gstate.font_size;
+ float txb = 0;
+ float tyb = 0;
+
+ ch = ctx_term_get_cell_height (rasterizer->ctx);
+ cw = ctx_term_get_cell_width (rasterizer->ctx);
+
+ _ctx_user_to_device (rasterizer->state, &tx, &ty);
+ _ctx_user_to_device (rasterizer->state, &txb, &tyb);
+ font_size = ty-tyb;
+ }
+ if (rasterizer->term_glyphs && !stroke &&
+ fabs (font_size - ch) < 0.5)
+ {
+ 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;
+ CtxTermGlyph *glyph = ctx_calloc (sizeof (CtxTermGlyph), 1);
+ ctx_list_append (&rasterizer->glyphs, glyph);
+ glyph->unichar = unichar;
+ glyph->col = col;
+ glyph->row = row;
+ ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color,
+ &glyph->rgba_fg[0]);
+ }
+ else
+#endif
+ _ctx_glyph (rasterizer->ctx, unichar, stroke);
}
-void
-ctx_process (Ctx *ctx, CtxEntry *entry)
+
+static void
+_ctx_text (Ctx *ctx,
+ const char *string,
+ int stroke,
+ int visible);
+static void
+ctx_rasterizer_text (CtxRasterizer *rasterizer, const char *string, int stroke)
{
-#if CTX_CURRENT_PATH
- switch (entry->code)
+#if CTX_BRAILLE_TEXT
+ float font_size = 0;
+ if (rasterizer->term_glyphs)
+ {
+ float tx = 0;
+ float ty = rasterizer->state->gstate.font_size;
+ _ctx_user_to_device (rasterizer->state, &tx, &ty);
+ font_size = ty;
+ }
+ int ch = ctx_term_get_cell_height (rasterizer->ctx);
+ int cw = ctx_term_get_cell_width (rasterizer->ctx);
+
+ if (rasterizer->term_glyphs && !stroke &&
+ fabs (font_size - ch) < 0.5)
+ {
+ 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;
+ for (int i = 0; string[i]; i++, col++)
{
- case CTX_TEXT:
- case CTX_TEXT_STROKE:
- case CTX_BEGIN_PATH:
- ctx->current_path.count = 0;
- break;
- case CTX_CLIP:
- case CTX_FILL:
- case CTX_STROKE:
- // XXX unless preserve
- ctx->current_path.count = 0;
- break;
- case CTX_CLOSE_PATH:
- case CTX_LINE_TO:
- case CTX_MOVE_TO:
- case CTX_QUAD_TO:
- case CTX_SMOOTH_TO:
- case CTX_SMOOTHQ_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:
- case CTX_REL_ARC_TO:
- case CTX_RECTANGLE:
- case CTX_ROUND_RECTANGLE:
- ctx_drawlist_add_entry (&ctx->current_path, entry);
- break;
- default:
- break;
- }
-#endif
- if (ctx->renderer && ctx->renderer->process)
- {
- ctx->renderer->process (ctx->renderer, (CtxCommand *) entry);
+ CtxTermGlyph *glyph = ctx_calloc (sizeof (CtxTermGlyph), 1);
+ ctx_list_prepend (&rasterizer->glyphs, glyph);
+ glyph->unichar = string[i];
+ glyph->col = col;
+ glyph->row = row;
+ ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color,
+ glyph->rgba_fg);
}
+ }
else
- {
- /* these functions might alter the code and coordinates of
- command that in the end gets added to the drawlist
- */
- ctx_interpret_style (&ctx->state, entry, ctx);
- ctx_interpret_transforms (&ctx->state, entry, ctx);
- ctx_interpret_pos (&ctx->state, entry, ctx);
- ctx_drawlist_add_entry (&ctx->drawlist, entry);
-#if 1
- if (entry->code == CTX_TEXT ||
- entry->code == CTX_LINE_DASH ||
- entry->code == CTX_COLOR_SPACE ||
- entry->code == CTX_TEXT_STROKE ||
- entry->code == CTX_FONT)
- {
- /* the image command and its data is submitted as one unit,
- */
- ctx_drawlist_add_entry (&ctx->drawlist, entry+1);
- ctx_drawlist_add_entry (&ctx->drawlist, entry+2);
- }
#endif
- }
+ {
+ _ctx_text (rasterizer->ctx, string, stroke, 1);
+ }
}
-int ctx_gradient_cache_valid = 0;
-
void
-ctx_state_gradient_clear_stops (CtxState *state)
-{
-//#if CTX_GRADIENT_CACHE
-// ctx_gradient_cache_reset ();
-//#endif
- ctx_gradient_cache_valid = 0;
- state->gradient.n_stops = 0;
-}
-
-uint8_t ctx_gradient_cache_u8[CTX_GRADIENT_CACHE_ELEMENTS][4];
-uint8_t ctx_gradient_cache_u8_a[CTX_GRADIENT_CACHE_ELEMENTS][4];
-
-/**** end of engine ****/
-
-CtxBuffer *ctx_buffer_new_bare (void)
-{
- CtxBuffer *buffer = (CtxBuffer *) ctx_calloc (sizeof (CtxBuffer), 1);
- return buffer;
-}
-
-void ctx_buffer_set_data (CtxBuffer *buffer,
- void *data, int width, int height,
- int stride,
- CtxPixelFormat pixel_format,
- void (*freefunc) (void *pixels, void *user_data),
- void *user_data)
+_ctx_font (Ctx *ctx, const char *name);
+static void
+ctx_rasterizer_set_font (CtxRasterizer *rasterizer, const char *font_name)
{
- if (buffer->free_func)
- { buffer->free_func (buffer->data, buffer->user_data); }
- buffer->data = data;
- buffer->width = width;
- buffer->height = height;
- buffer->stride = stride;
- buffer->format = ctx_pixel_format_info (pixel_format);
- buffer->free_func = freefunc;
- buffer->user_data = user_data;
+ _ctx_font (rasterizer->ctx, font_name);
}
-
-
-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)
+static void
+ctx_rasterizer_arc (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ float radius,
+ float start_angle,
+ float end_angle,
+ int anticlockwise)
{
- CtxBuffer *buffer = ctx_buffer_new_bare ();
- ctx_buffer_set_data (buffer, data, width, height, stride, pixel_format,
- freefunc, user_data);
- return buffer;
-}
-
+ int full_segments = CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS;
+ full_segments = radius * CTX_PI * 2;
+ if (full_segments > CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS)
+ { full_segments = CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS; }
+ float step = CTX_PI*2.0/full_segments;
+ int steps;
-static void ctx_buffer_pixels_free (void *pixels, void *userdata)
-{
- free (pixels);
-}
+ 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;
-CtxBuffer *ctx_buffer_new (int width, int height,
- CtxPixelFormat pixel_format)
-{
- CtxPixelFormatInfo *info = ctx_pixel_format_info (pixel_format);
- CtxBuffer *buffer = ctx_buffer_new_bare ();
- int stride = width * info->ebpp;
- uint8_t *pixels = (uint8_t*)ctx_calloc (stride, height + 1);
+ if (radius <= 0.0001)
+ return;
- ctx_buffer_set_data (buffer, pixels, width, height, stride, pixel_format,
- ctx_buffer_pixels_free, NULL);
- return buffer;
+ if (end_angle == start_angle)
+ // XXX also detect arcs fully outside render view
+ {
+ if (rasterizer->has_prev!=0)
+ ctx_rasterizer_line_to (rasterizer, x + ctx_cosf (end_angle) * radius,
+ y + ctx_sinf (end_angle) * radius);
+ else
+ ctx_rasterizer_move_to (rasterizer, x + ctx_cosf (end_angle) * radius,
+ y + ctx_sinf (end_angle) * radius);
+ return;
+ }
+#if 1
+ if ( (!anticlockwise && fabsf((end_angle - start_angle) - CTX_PI*2) < 0.01f) ||
+ ( (anticlockwise && fabsf((start_angle - end_angle) - CTX_PI*2) < 0.01f ) )
+ || (anticlockwise && fabsf((end_angle - start_angle) - CTX_PI*2) < 0.01f) || (!anticlockwise &&
fabsf((start_angle - end_angle) - CTX_PI*2) < 0.01f ) )
+ {
+ start_angle = start_angle;
+ steps = full_segments - 1;
+ }
+ else
+#endif
+ {
+ steps = (end_angle - start_angle) / (CTX_PI*2) * full_segments;
+ if (anticlockwise)
+ { steps = full_segments - steps; };
+ // if (steps > full_segments)
+ // steps = full_segments;
+ }
+ if (anticlockwise) { step = step * -1; }
+ int first = 1;
+ if (steps == 0 /* || steps==full_segments -1 || (anticlockwise && steps == full_segments) */)
+ {
+ float xv = x + ctx_cosf (start_angle) * radius;
+ float yv = y + ctx_sinf (start_angle) * radius;
+ if (!rasterizer->has_prev)
+ { ctx_rasterizer_move_to (rasterizer, xv, yv); }
+ first = 0;
+ }
+ else
+ {
+ for (float angle = start_angle, i = 0; i < steps; angle += step, i++)
+ {
+ float xv = x + ctx_cosf (angle) * radius;
+ float yv = y + ctx_sinf (angle) * radius;
+ if (first && !rasterizer->has_prev)
+ { ctx_rasterizer_move_to (rasterizer, xv, yv); }
+ else
+ { ctx_rasterizer_line_to (rasterizer, xv, yv); }
+ first = 0;
+ }
+ }
+ ctx_rasterizer_line_to (rasterizer, x + ctx_cosf (end_angle) * radius,
+ y + ctx_sinf (end_angle) * radius);
}
-void ctx_buffer_deinit (CtxBuffer *buffer)
+static void
+ctx_rasterizer_quad_to (CtxRasterizer *rasterizer,
+ float cx,
+ float cy,
+ float x,
+ float y)
{
- if (buffer->free_func)
- { buffer->free_func (buffer->data, buffer->user_data); }
- buffer->data = NULL;
- buffer->free_func = NULL;
- buffer->user_data = NULL;
+ /* XXX : it is probably cheaper/faster to do quad interpolation directly -
+ * though it will increase the code-size, an
+ * alternative is to turn everything into cubic
+ * and deal with cubics more directly during
+ * rasterization
+ */
+ ctx_rasterizer_curve_to (rasterizer,
+ (cx * 2 + rasterizer->x) / 3.0f, (cy * 2 + rasterizer->y) / 3.0f,
+ (cx * 2 + x) / 3.0f, (cy * 2 + y) / 3.0f,
+ x, y);
}
-void ctx_buffer_free (CtxBuffer *buffer)
+static void
+ctx_rasterizer_rel_quad_to (CtxRasterizer *rasterizer,
+ float cx, float cy,
+ float x, float y)
{
- ctx_buffer_deinit (buffer);
- free (buffer);
+ ctx_rasterizer_quad_to (rasterizer, cx + rasterizer->x, cy + rasterizer->y,
+ x + rasterizer->x, y + rasterizer->y);
}
-void ctx_texture_release (Ctx *ctx, int id)
+#define LENGTH_OVERSAMPLE 1
+static void
+ctx_rasterizer_pset (CtxRasterizer *rasterizer, int x, int y, uint8_t cov)
{
- if (id < 0 || id >= CTX_MAX_TEXTURES)
+ // XXX - we avoid rendering here x==0 - to keep with
+ // an off-by one elsewhere
+ //
+ // XXX onlt works in rgba8 formats
+ if (x <= 0 || y < 0 || x >= rasterizer->blit_width ||
+ y >= rasterizer->blit_height)
{ return; }
- ctx_buffer_deinit (&ctx->texture[id]);
-}
-
-static int ctx_allocate_texture_id (Ctx *ctx, int id)
-{
- if (id < 0 || id >= CTX_MAX_TEXTURES)
+ uint8_t fg_color[4];
+ ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, fg_color);
+ uint8_t pixel[4];
+ uint8_t *dst = ( (uint8_t *) rasterizer->buf);
+ dst += y * rasterizer->blit_stride;
+ dst += x * rasterizer->format->bpp / 8;
+ if (!rasterizer->format->to_comp ||
+ !rasterizer->format->from_comp)
+ { return; }
+ if (cov == 255)
+ {
+ for (int c = 0; c < 4; c++)
+ {
+ pixel[c] = fg_color[c];
+ }
+ }
+ else
{
- for (int i = 0; i < CTX_MAX_TEXTURES; i++)
- if (ctx->texture[i].data == NULL)
- { return i; }
- int sacrifice = random()%CTX_MAX_TEXTURES; // better to bias towards old
- ctx_texture_release (ctx, sacrifice);
- return sacrifice;
- return -1; // eeek
+ rasterizer->format->to_comp (rasterizer, x, dst, &pixel[0], 1);
+ for (int c = 0; c < 4; c++)
+ {
+ pixel[c] = ctx_lerp_u8 (pixel[c], fg_color[c], cov);
+ }
}
- return id;
+ rasterizer->format->from_comp (rasterizer, x, &pixel[0], dst, 1);
}
-int ctx_texture_init (Ctx *ctx,
- int id, /* should be a string? - also the auto-ids*/
- int width,
- int height,
- int stride,
- CtxPixelFormat format,
- uint8_t *pixels,
- void (*freefunc) (void *pixels, void *user_data),
- void *user_data)
+static void
+ctx_rasterizer_stroke_1px (CtxRasterizer *rasterizer)
{
- /* .. how to relay? ..
- * fully serializing is one needed option - for that there is no free
- * func..
- *
- * mmap texute bank - that is one of many in compositor, prefixed with "pid-",
- * ... we want string identifiers instead of integers.
- *
- * a context to use as texturing source
- * implemented.
- */
- id = ctx_allocate_texture_id (ctx, id);
- if (id < 0)
- { return id; }
- int bpp = ctx_pixel_format_bpp (format);
- ctx_buffer_deinit (&ctx->texture[id]);
-
- if (!stride)
- {
- stride = width * (bpp/8);
- }
-
- ctx_buffer_set_data (&ctx->texture[id],
- pixels, width, height,
- stride, format,
- freefunc, user_data);
- return id;
-}
-
-int
-ctx_texture_load (Ctx *ctx, int id, const char *path, int *tw, int *th)
-{
-#ifdef STBI_INCLUDE_STB_IMAGE_H
- int w, h, components;
- unsigned char *data = stbi_load (path, &w, &h, &components, 0);
- if (data)
- {
- CtxPixelFormat pixel_format = CTX_FORMAT_RGBA8;
- switch (components)
- {
- 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;
- }
- if (tw) *tw = w;
- if (th) *th = h;
- return ctx_texture_init (ctx, id, w, h, w * components, pixel_format, data,
- ctx_buffer_pixels_free, NULL);
- }
+ int count = rasterizer->edge_list.count;
+ CtxEntry *temp = rasterizer->edge_list.entries;
+ float prev_x = 0.0f;
+ float prev_y = 0.0f;
+ int aa = rasterizer->aa;
+ int start = 0;
+ int end = 0;
+#if 0
+ float factor = ctx_matrix_get_scale (&state->gstate.transform);
#endif
- return -1;
-}
-
-int ctx_utf8_len (const unsigned char first_byte)
-{
- if ( (first_byte & 0x80) == 0)
- { return 1; } /* ASCII */
- else if ( (first_byte & 0xE0) == 0xC0)
- { return 2; }
- else if ( (first_byte & 0xF0) == 0xE0)
- { return 3; }
- else if ( (first_byte & 0xF8) == 0xF0)
- { return 4; }
- return 1;
-}
-
-const char *ctx_utf8_skip (const char *s, int utf8_length)
-{
- int count;
- if (!s)
- { return NULL; }
- for (count = 0; *s; s++)
+ while (start < count)
{
- if ( (*s & 0xC0) != 0x80)
- { count++; }
- if (count == utf8_length + 1)
- { return s; }
+ int started = 0;
+ int i;
+ for (i = start; i < count; i++)
+ {
+ CtxEntry *entry = &temp[i];
+ float x, y;
+ if (entry->code == CTX_NEW_EDGE)
+ {
+ if (started)
+ {
+ end = i - 1;
+ goto foo;
+ }
+ prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
+ prev_y = entry->data.s16[1] * 1.0f / aa;
+ started = 1;
+ start = i;
+ }
+ x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[3] * 1.0f / aa;
+ int dx = x - prev_x;
+ int dy = y - prev_y;
+ int length = ctx_maxf (abs (dx), abs (dy) );
+ if (length)
+ {
+ length *= LENGTH_OVERSAMPLE;
+ int len = length;
+ int tx = prev_x * 256;
+ int ty = prev_y * 256;
+ dx *= 256;
+ dy *= 256;
+ dx /= length;
+ dy /= length;
+ for (int i = 0; i < len; i++)
+ {
+ ctx_rasterizer_pset (rasterizer, tx/256, ty/256, 255);
+ tx += dx;
+ ty += dy;
+ ctx_rasterizer_pset (rasterizer, tx/256, ty/256, 255);
+ }
+ }
+ prev_x = x;
+ prev_y = y;
+ }
+ end = i-1;
+foo:
+ start = end+1;
}
- return s;
+ ctx_rasterizer_reset (rasterizer);
}
-// XXX : unused
-int ctx_utf8_strlen (const char *s)
+static void
+ctx_rasterizer_stroke (CtxRasterizer *rasterizer)
{
- int count;
- if (!s)
- { return 0; }
- for (count = 0; *s; s++)
- if ( (*s & 0xC0) != 0x80)
- { count++; }
- return count;
-}
+ CtxSource source_backup = rasterizer->state->gstate.source_fill;
+ rasterizer->state->gstate.source_fill = rasterizer->state->gstate.source_stroke;
+ CtxState *state = rasterizer->state;
+ int count = rasterizer->edge_list.count;
+ int preserved = rasterizer->preserve;
+ float factor = ctx_matrix_get_scale (&state->gstate.transform);
-int
-ctx_unichar_to_utf8 (uint32_t ch,
- uint8_t *dest)
-{
- /* http://www.cprogramming.com/tutorial/utf8.c */
- /* Basic UTF-8 manipulation routines
- by Jeff Bezanson
- placed in the public domain Fall 2005 ... */
- if (ch < 0x80)
- {
- dest[0] = (char) ch;
- return 1;
- }
- if (ch < 0x800)
- {
- dest[0] = (ch>>6) | 0xC0;
- dest[1] = (ch & 0x3F) | 0x80;
- return 2;
- }
- if (ch < 0x10000)
+ int aa = rasterizer->aa;
+ CtxEntry temp[count]; /* copy of already built up path's poly line */
+ memcpy (temp, rasterizer->edge_list.entries, sizeof (temp) );
+#if 1
+ if (rasterizer->state->gstate.line_width * factor <= 0.0f &&
+ rasterizer->state->gstate.line_width * factor > -10.0f)
{
- dest[0] = (ch>>12) | 0xE0;
- dest[1] = ( (ch>>6) & 0x3F) | 0x80;
- dest[2] = (ch & 0x3F) | 0x80;
- return 3;
+ ctx_rasterizer_stroke_1px (rasterizer);
}
- if (ch < 0x110000)
+ else
+#endif
{
- dest[0] = (ch>>18) | 0xF0;
- dest[1] = ( (ch>>12) & 0x3F) | 0x80;
- dest[2] = ( (ch>>6) & 0x3F) | 0x80;
- dest[3] = (ch & 0x3F) | 0x80;
- return 4;
- }
- return 0;
-}
-
-uint32_t
-ctx_utf8_to_unichar (const char *input)
-{
- const uint8_t *utf8 = (const uint8_t *) input;
- uint8_t c = utf8[0];
- if ( (c & 0x80) == 0)
- { return c; }
- else if ( (c & 0xE0) == 0xC0)
- return ( (utf8[0] & 0x1F) << 6) |
- (utf8[1] & 0x3F);
- else if ( (c & 0xF0) == 0xE0)
- return ( (utf8[0] & 0xF) << 12) |
- ( (utf8[1] & 0x3F) << 6) |
- (utf8[2] & 0x3F);
- else if ( (c & 0xF8) == 0xF0)
- return ( (utf8[0] & 0x7) << 18) |
- ( (utf8[1] & 0x3F) << 12) |
- ( (utf8[2] & 0x3F) << 6) |
- (utf8[3] & 0x3F);
- else if ( (c & 0xFC) == 0xF8)
- return ( (utf8[0] & 0x3) << 24) |
- ( (utf8[1] & 0x3F) << 18) |
- ( (utf8[2] & 0x3F) << 12) |
- ( (utf8[3] & 0x3F) << 6) |
- (utf8[4] & 0x3F);
- else if ( (c & 0xFE) == 0xFC)
- return ( (utf8[0] & 0x1) << 30) |
- ( (utf8[1] & 0x3F) << 24) |
- ( (utf8[2] & 0x3F) << 18) |
- ( (utf8[3] & 0x3F) << 12) |
- ( (utf8[4] & 0x3F) << 6) |
- (utf8[5] & 0x3F);
- return 0;
-}
+ ctx_rasterizer_reset (rasterizer); /* then start afresh with our stroked shape */
+ CtxMatrix transform_backup = rasterizer->state->gstate.transform;
+ ctx_matrix_identity (&rasterizer->state->gstate.transform);
+ float prev_x = 0.0f;
+ float prev_y = 0.0f;
+ float half_width_x = rasterizer->state->gstate.line_width * factor/2;
+ float half_width_y = rasterizer->state->gstate.line_width * factor/2;
+ if (rasterizer->state->gstate.line_width <= 0.0f)
+ {
+ half_width_x = .5;
+ half_width_y = .5;
+ }
+ int start = 0;
+ int end = 0;
+ while (start < count)
+ {
+ int started = 0;
+ int i;
+ for (i = start; i < count; i++)
+ {
+ CtxEntry *entry = &temp[i];
+ float x, y;
+ if (entry->code == CTX_NEW_EDGE)
+ {
+ if (started)
+ {
+ end = i - 1;
+ goto foo;
+ }
+ prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
+ prev_y = entry->data.s16[1] * 1.0f / aa;
+ started = 1;
+ start = i;
+ }
+ x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[3] * 1.0f / aa;
+ float dx = x - prev_x;
+ float dy = y - prev_y;
+ float length = ctx_fast_hypotf (dx, dy);
+ if (length>0.001f)
+ {
+ dx = dx/length * half_width_x;
+ dy = dy/length * half_width_y;
+ if (entry->code == CTX_NEW_EDGE)
+ {
+ ctx_rasterizer_finish_shape (rasterizer);
+ ctx_rasterizer_move_to (rasterizer, prev_x+dy, prev_y-dx);
+ }
+ ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
+
+ // we need to know the slope of the other side
-#if CTX_RASTERIZER
+ // XXX possible miter line-to
+ //ctx_rasterizer_line_to (rasterizer, prev_x-dy+4, prev_y+dx+10);
+ //ctx_rasterizer_line_to (rasterizer, prev_x-dy+8, prev_y+dx+0);
-struct _CtxHasher
-{
- CtxRasterizer rasterizer;
- int cols;
- int rows;
- uint8_t *hashes;
-};
-#define SHA1_IMPLEMENTATION
-/* LibTomCrypt, modular cryptographic library -- Tom St Denis
- *
- * LibTomCrypt is a library that provides various cryptographic
- * algorithms in a highly modular and flexible manner.
- *
- * The library is free for all purposes without any express
- * guarantee it works.
- *
- * Tom St Denis, tomstdenis gmail com, http://libtom.org
- *
- * The plain ANSIC sha1 functionality has been extracted from libtomcrypt,
- * and is included directly in the sources. /Øyvind K. - since libtomcrypt
- * is public domain the adaptations done here to make the sha1 self contained
- * also is public domain.
- */
-#ifndef __SHA1_H
-#define __SHA1_H
-#include <inttypes.h>
+ ctx_rasterizer_line_to (rasterizer, x-dy, y+dx);
+ }
+ prev_x = x;
+ prev_y = y;
+ }
+ end = i-1;
+foo:
+ for (int i = end; i >= start; i--)
+ {
+ CtxEntry *entry = &temp[i];
+ float x, y, dx, dy;
+ x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[3] * 1.0f / aa;
+ dx = x - prev_x;
+ dy = y - prev_y;
+ float length = ctx_fast_hypotf (dx, dy);
+ dx = dx/length * half_width_x;
+ dy = dy/length * half_width_y;
+ if (length>0.001f)
+ {
+ ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
+ // XXX possible miter line-to
+ // ctx_rasterizer_line_to (rasterizer, prev_x-dy+10, prev_y+dx+10);
+ ctx_rasterizer_line_to (rasterizer, x-dy, y+dx);
+ }
+ prev_x = x;
+ prev_y = y;
+ if (entry->code == CTX_NEW_EDGE)
+ {
+ x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[1] * 1.0f / aa;
+ dx = x - prev_x;
+ dy = y - prev_y;
+ length = ctx_fast_hypotf (dx, dy);
+ if (length>0.001f)
+ {
+ dx = dx / length * half_width_x;
+ dy = dy / length * half_width_y;
+ ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
+ ctx_rasterizer_line_to (rasterizer, x-dy, y+dx);
+ }
+ }
+ if ( (prev_x != x) && (prev_y != y) )
+ {
+ prev_x = x;
+ prev_y = y;
+ }
+ }
+ start = end+1;
+ }
+ ctx_rasterizer_finish_shape (rasterizer);
+ switch (rasterizer->state->gstate.line_cap)
+ {
+ case CTX_CAP_SQUARE: // XXX:NYI
+ case CTX_CAP_NONE: /* nothing to do */
+ break;
+ case CTX_CAP_ROUND:
+ {
+ float x = 0, y = 0;
+ int has_prev = 0;
+ for (int i = 0; i < count; i++)
+ {
+ CtxEntry *entry = &temp[i];
+ if (entry->code == CTX_NEW_EDGE)
+ {
+ if (has_prev)
+ {
+ ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
+ ctx_rasterizer_finish_shape (rasterizer);
+ }
+ x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[1] * 1.0f / aa;
+ ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
+ ctx_rasterizer_finish_shape (rasterizer);
+ }
+ x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[3] * 1.0f / aa;
+ has_prev = 1;
+ }
+ ctx_rasterizer_move_to (rasterizer, x, y);
+ ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
+ ctx_rasterizer_finish_shape (rasterizer);
+ break;
+ }
+ }
+ switch (rasterizer->state->gstate.line_join)
+ {
+ case CTX_JOIN_BEVEL:
+ case CTX_JOIN_MITER:
+ break;
+ case CTX_JOIN_ROUND:
+ {
+ float x = 0, y = 0;
+ for (int i = 0; i < count-1; i++)
+ {
+ CtxEntry *entry = &temp[i];
+ x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[3] * 1.0f / aa;
+ if (entry[1].code == CTX_EDGE)
+ {
+ ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*2, 0, 1);
+ ctx_rasterizer_finish_shape (rasterizer);
+ }
+ }
+ break;
+ }
+ }
+ CtxFillRule rule_backup = rasterizer->state->gstate.fill_rule;
+ rasterizer->state->gstate.fill_rule = CTX_FILL_RULE_WINDING;
+ rasterizer->preserve = 0; // so fill isn't tripped
+ ctx_rasterizer_fill (rasterizer);
+ rasterizer->state->gstate.fill_rule = rule_backup;
+ //rasterizer->state->gstate.source = source_backup;
+ rasterizer->state->gstate.transform = transform_backup;
+ }
+ if (preserved)
+ {
+ memcpy (rasterizer->edge_list.entries, temp, sizeof (temp) );
+ rasterizer->edge_list.count = count;
+ rasterizer->preserve = 0;
+ }
+ rasterizer->state->gstate.source_fill = source_backup;
+}
-struct _CtxSHA1 {
- uint64_t length;
- uint32_t state[5], curlen;
- unsigned char buf[64];
-};
+#if CTX_1BIT_CLIP
+#define CTX_CLIP_FORMAT CTX_FORMAT_GRAY1
+#else
+#define CTX_CLIP_FORMAT CTX_FORMAT_GRAY8
+#endif
-int ctx_sha1_init(CtxSHA1 * sha1);
-CtxSHA1 *ctx_sha1_new (void)
+
+static void
+ctx_rasterizer_clip_reset (CtxRasterizer *rasterizer)
{
- CtxSHA1 *state = calloc (sizeof (CtxSHA1), 1);
- ctx_sha1_init (state);
- return state;
+#if CTX_ENABLE_CLIP
+ if (rasterizer->clip_buffer)
+ ctx_buffer_free (rasterizer->clip_buffer);
+ rasterizer->clip_buffer = NULL;
+#endif
+ rasterizer->state->gstate.clip_min_x = rasterizer->blit_x;
+ rasterizer->state->gstate.clip_min_y = rasterizer->blit_y;
+
+ rasterizer->state->gstate.clip_max_x = rasterizer->blit_x + rasterizer->blit_width - 1;
+ rasterizer->state->gstate.clip_max_y = rasterizer->blit_y + rasterizer->blit_height - 1;
}
-void ctx_sha1_free (CtxSHA1 *sha1)
+
+static void
+ctx_rasterizer_clip_apply (CtxRasterizer *rasterizer,
+ CtxEntry *edges)
{
- free (sha1);
-}
+ int count = edges[0].data.u32[0];
+ int aa = rasterizer->aa;
-#if 0
- CtxSHA1 sha1;
- ctx_sha1_init (&sha1);
- ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxRectangle));
- ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
-#endif
+ int minx = 5000;
+ int miny = 5000;
+ int maxx = -5000;
+ int maxy = -5000;
+ int prev_x = 0;
+ int prev_y = 0;
+ int blit_width = rasterizer->blit_width;
+ int blit_height = rasterizer->blit_height;
-#ifdef FF0
-#undef FF0
-#endif
-#ifdef FF1
-#undef FF1
-#endif
-#ifdef SHA1_IMPLEMENTATION
-#include <stdlib.h>
-#include <string.h>
+ float coords[6][2];
-#define STORE64H(x, y)
\
- { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
- (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
- (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
- (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+ for (int i = 0; i < count; i++)
+ {
+ CtxEntry *entry = &edges[i+1];
+ 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 / aa;
+ if (prev_x < minx) { minx = prev_x; }
+ if (prev_y < miny) { miny = prev_y; }
+ if (prev_x > maxx) { maxx = prev_x; }
+ if (prev_y > maxy) { maxy = prev_y; }
+ }
+ x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[3] * 1.0f / aa;
+ coords[i][0] = x;
+ coords[i][1] = y;
+ if (x < minx) { minx = x; }
+ if (y < miny) { miny = y; }
+ if (x > maxx) { maxx = x; }
+ if (y > maxy) { maxy = y; }
+ }
-#define STORE32H(x, y)
\
- { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
- (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+ if (rasterizer->clip_rectangle || !rasterizer->clip_buffer)
+ {
+ if (count == 6)
+ {
+ if (coords[3][0] == coords[5][0] &&
+ coords[3][1] == coords[5][1])
+ {
+#if 0
+ printf ("%d,%d %dx%d\n", minx, miny,
+ maxx-minx+1, maxy-miny+1);
+#endif
-#define LOAD32H(x, y) \
- { x = ((unsigned long)((y)[0] & 255)<<24) | \
- ((unsigned long)((y)[1] & 255)<<16) | \
- ((unsigned long)((y)[2] & 255)<<8) | \
- ((unsigned long)((y)[3] & 255)); }
+ rasterizer->state->gstate.clip_min_x =
+ ctx_maxi (minx, rasterizer->state->gstate.clip_min_x);
+ rasterizer->state->gstate.clip_min_y =
+ ctx_maxi (miny, rasterizer->state->gstate.clip_min_y);
+ rasterizer->state->gstate.clip_max_x =
+ ctx_mini (maxx, rasterizer->state->gstate.clip_max_x);
+ rasterizer->state->gstate.clip_max_y =
+ ctx_mini (maxy, rasterizer->state->gstate.clip_max_y);
-/* rotates the hard way */
-#define ROL(x, y) ((((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned
long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
-#define ROLc(x, y) ROL(x,y)
+ rasterizer->clip_rectangle = 1;
+ return;
+ }
+ }
+ }
+ rasterizer->clip_rectangle = 0;
-#define CRYPT_OK 0
-#define CRYPT_ERROR 1
-#define CRYPT_NOP 2
+#if CTX_ENABLE_CLIP
+ if ((minx == maxx) || (miny == maxy)) // XXX : reset hack
+ {
+ ctx_rasterizer_clip_reset (rasterizer);
+ return;//goto done;
+ }
-#ifndef MAX
- #define MAX(x, y) ( ((x)>(y))?(x):(y) )
-#endif
-#ifndef MIN
- #define MIN(x, y) ( ((x)<(y))?(x):(y) )
-#endif
+ int we_made_it = 0;
+ CtxBuffer *clip_buffer;
-/* a simple macro for making hash "process" functions */
-#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \
-int func_name (CtxSHA1 *sha1, const unsigned char *in, unsigned long inlen) \
-{ \
- unsigned long n; \
- int err; \
- assert (sha1 != NULL); \
- assert (in != NULL); \
- if (sha1->curlen > sizeof(sha1->buf)) { \
- return -1; \
- } \
- while (inlen > 0) { \
- if (sha1->curlen == 0 && inlen >= block_size) { \
- if ((err = compress_name (sha1, (unsigned char *)in)) != CRYPT_OK) { \
- return err; \
- } \
- sha1->length += block_size * 8; \
- in += block_size; \
- inlen -= block_size; \
- } else { \
- n = MIN(inlen, (block_size - sha1->curlen)); \
- memcpy(sha1->buf + sha1->curlen, in, (size_t)n); \
- sha1->curlen += n; \
- in += n; \
- inlen -= n; \
- if (sha1->curlen == block_size) { \
- if ((err = compress_name (sha1, sha1->buf)) != CRYPT_OK) { \
- return err; \
- } \
- sha1->length += 8*block_size; \
- sha1->curlen = 0; \
- } \
- } \
- } \
- return CRYPT_OK; \
-}
+ if (!rasterizer->clip_buffer)
+ {
+ rasterizer->clip_buffer = ctx_buffer_new (blit_width,
+ blit_height,
+ CTX_CLIP_FORMAT);
+ clip_buffer = rasterizer->clip_buffer;
+ we_made_it = 1;
+ if (CTX_CLIP_FORMAT == CTX_FORMAT_GRAY1)
+ memset (rasterizer->clip_buffer->data, 0, blit_width * blit_height/8);
+ else
+ memset (rasterizer->clip_buffer->data, 0, blit_width * blit_height);
+ }
+ else
+ {
+ clip_buffer = ctx_buffer_new (blit_width, blit_height,
+ CTX_CLIP_FORMAT);
+ }
-/**********************/
+ {
-#define F0(x,y,z) (z ^ (x & (y ^ z)))
-#define F1(x,y,z) (x ^ y ^ z)
-#define F2(x,y,z) ((x & y) | (z & (x | y)))
-#define F3(x,y,z) (x ^ y ^ z)
+ int prev_x = 0;
+ int prev_y = 0;
-static int ctx_sha1_compress(CtxSHA1 *sha1, unsigned char *buf)
-{
- uint32_t a,b,c,d,e,W[80],i;
+ Ctx *ctx = ctx_new_for_framebuffer (clip_buffer->data, blit_width, blit_height,
+ blit_width,
+ CTX_CLIP_FORMAT);
- /* copy the state into 512-bits into W[0..15] */
- for (i = 0; i < 16; i++) {
- LOAD32H(W[i], buf + (4*i));
+ for (int i = 0; i < count; i++)
+ {
+ CtxEntry *entry = &edges[i+1];
+ 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 / aa;
+ ctx_move_to (ctx, prev_x, prev_y);
+ }
+ x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[3] * 1.0f / aa;
+ ctx_line_to (ctx, x, y);
}
+ ctx_gray (ctx, 1.0f);
+ ctx_fill (ctx);
+ ctx_free (ctx);
+ }
- /* copy state */
- a = sha1->state[0];
- b = sha1->state[1];
- c = sha1->state[2];
- d = sha1->state[3];
- e = sha1->state[4];
+ rasterizer->clip_rectangle = 0;
- /* expand it */
- for (i = 16; i < 80; i++) {
- W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
+ if (CTX_CLIP_FORMAT == CTX_FORMAT_GRAY1)
+ {
+ int count = blit_width * blit_height / 8;
+ for (int i = 0; i < count; i++)
+ {
+ ((uint8_t*)rasterizer->clip_buffer->data)[i] =
+ (((uint8_t*)rasterizer->clip_buffer->data)[i] &
+ ((uint8_t*)clip_buffer->data)[i]);
}
+ }
+ else
+ {
+ int count = blit_width * blit_height;
- /* compress */
- /* round one */
- #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
- #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
- #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
- #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
-
- for (i = 0; i < 20; ) {
- FF0(a,b,c,d,e,i++);
- FF0(e,a,b,c,d,i++);
- FF0(d,e,a,b,c,i++);
- FF0(c,d,e,a,b,i++);
- FF0(b,c,d,e,a,i++);
- }
+ int maybe_rect = 1;
- /* round two */
- for (; i < 40; ) {
- FF1(a,b,c,d,e,i++);
- FF1(e,a,b,c,d,i++);
- FF1(d,e,a,b,c,i++);
- FF1(c,d,e,a,b,i++);
- FF1(b,c,d,e,a,i++);
+ int i;
+ int x0 = 0;
+ int y0 = 0;
+ int width = -1;
+ int next_stage = 0;
+ uint8_t *p_data = (uint8_t*)rasterizer->clip_buffer->data;
+ uint8_t *data = (uint8_t*)clip_buffer->data;
+
+ i=0;
+ /* find upper left */
+ for (; i < count && maybe_rect && !next_stage; i++)
+ {
+ uint8_t val = (p_data[i] * data[i])/255;
+ data[i] = val;
+ switch (val)
+ {
+ case 255:
+ x0 = i % blit_width;
+ y0 = i / blit_width;
+ next_stage = 1;
+ break;
+ case 0: break;
+ default:
+ maybe_rect = 0;
+ break;
+ }
}
- /* round three */
- for (; i < 60; ) {
- FF2(a,b,c,d,e,i++);
- FF2(e,a,b,c,d,i++);
- FF2(d,e,a,b,c,i++);
- FF2(c,d,e,a,b,i++);
- FF2(b,c,d,e,a,i++);
- }
+ next_stage = 0;
+ /* figure out with */
+ for (; i < count && !next_stage && maybe_rect; i++)
+ {
+ int x = i % blit_width;
+ int y = i / blit_width;
+ uint8_t val = (p_data[i] * data[i])/255;
+ data[i] = val;
- /* round four */
- for (; i < 80; ) {
- FF3(a,b,c,d,e,i++);
- FF3(e,a,b,c,d,i++);
- FF3(d,e,a,b,c,i++);
- FF3(c,d,e,a,b,i++);
- FF3(b,c,d,e,a,i++);
+ if (y == y0)
+ {
+ switch (val)
+ {
+ case 255:
+ width = x - x0 + 1;
+ break;
+ case 0:
+ next_stage = 1;
+ break;
+ default:
+ maybe_rect = 0;
+ break;
+ }
+ if (x % blit_width == blit_width - 1) next_stage = 1;
+ }
+ else next_stage = 1;
}
- #undef FF0
- #undef FF1
- #undef FF2
- #undef FF3
-
- /* store */
- sha1->state[0] = sha1->state[0] + a;
- sha1->state[1] = sha1->state[1] + b;
- sha1->state[2] = sha1->state[2] + c;
- sha1->state[3] = sha1->state[3] + d;
- sha1->state[4] = sha1->state[4] + e;
-
- return CRYPT_OK;
-}
-
-/**
- Initialize the hash state
- @param md The hash state you wish to initialize
- @return CRYPT_OK if successful
-*/
-int ctx_sha1_init(CtxSHA1 * sha1)
-{
- assert(sha1 != NULL);
- sha1->state[0] = 0x67452301UL;
- sha1->state[1] = 0xefcdab89UL;
- sha1->state[2] = 0x98badcfeUL;
- sha1->state[3] = 0x10325476UL;
- sha1->state[4] = 0xc3d2e1f0UL;
- sha1->curlen = 0;
- sha1->length = 0;
- return CRYPT_OK;
-}
-
-/**
- Process a block of memory though the hash
- @param md The hash state
- @param in The data to hash
- @param inlen The length of the data (octets)
- @return CRYPT_OK if successful
-*/
-HASH_PROCESS(ctx_sha1_process, ctx_sha1_compress, sha1, 64)
-
-/**
- Terminate the hash to get the digest
- @param md The hash state
- @param out [out] The destination of the hash (20 bytes)
- @return CRYPT_OK if successful
-*/
-int ctx_sha1_done(CtxSHA1 * sha1, unsigned char *out)
-{
- int i;
-
- assert(sha1 != NULL);
- assert(out != NULL);
+ next_stage = 0;
+ /* body */
+ for (; i < count && maybe_rect && !next_stage; i++)
+ {
+ int x = i % blit_width;
+ uint8_t val = (p_data[i] * data[i])/255;
+ data[i] = val;
- if (sha1->curlen >= sizeof(sha1->buf)) {
- return -1;
+ if (x < x0)
+ {
+ if (val != 0){ maybe_rect = 0; next_stage = 1; }
+ } else if (x < x0 + width)
+ {
+ if (val != 255){ if (val != 0) maybe_rect = 0; next_stage = 1; }
+ } else {
+ if (val != 0){ maybe_rect = 0; next_stage = 1; }
+ }
}
- /* increase the length of the message */
- sha1->length += sha1->curlen * 8;
-
- /* append the '1' bit */
- sha1->buf[sha1->curlen++] = (unsigned char)0x80;
-
- /* if the length is currently above 56 bytes we append zeros
- * then compress. Then we can fall back to padding zeros and length
- * encoding like normal.
- */
- if (sha1->curlen > 56) {
- while (sha1->curlen < 64) {
- sha1->buf[sha1->curlen++] = (unsigned char)0;
- }
- ctx_sha1_compress(sha1, sha1->buf);
- sha1->curlen = 0;
- }
+ next_stage = 0;
+ /* foot */
+ for (; i < count && maybe_rect && !next_stage; i++)
+ {
+ uint8_t val = (p_data[i] * data[i])/255;
+ data[i] = val;
- /* pad upto 56 bytes of zeroes */
- while (sha1->curlen < 56) {
- sha1->buf[sha1->curlen++] = (unsigned char)0;
+ if (val != 0){ maybe_rect = 0; next_stage = 1; }
}
- /* store length */
- STORE64H(sha1->length, sha1->buf+56);
- ctx_sha1_compress(sha1, sha1->buf);
- /* copy output */
- for (i = 0; i < 5; i++) {
- STORE32H(sha1->state[i], out+(4*i));
+ for (; i < count; i++)
+ {
+ uint8_t val = (p_data[i] * data[i])/255;
+ data[i] = val;
}
- return CRYPT_OK;
-}
-#endif
+ if (maybe_rect)
+ rasterizer->clip_rectangle = 1;
+ }
+ if (!we_made_it)
+ ctx_buffer_free (clip_buffer);
#endif
+
+ rasterizer->state->gstate.clip_min_x = ctx_maxi (minx,
+ rasterizer->state->gstate.clip_min_x);
+ rasterizer->state->gstate.clip_min_y = ctx_maxi (miny,
+ rasterizer->state->gstate.clip_min_y);
+ rasterizer->state->gstate.clip_max_x = ctx_mini (maxx,
+ rasterizer->state->gstate.clip_max_x);
+ rasterizer->state->gstate.clip_max_y = ctx_mini (maxy,
+ rasterizer->state->gstate.clip_max_y);
+}
-static int
-ctx_rect_intersect (const CtxRectangle *a, const CtxRectangle *b)
+static void
+ctx_rasterizer_clip (CtxRasterizer *rasterizer)
{
- if (a->x >= b->x + b->width ||
- b->x >= a->x + a->width ||
- a->y >= b->y + b->height ||
- b->y >= a->y + a->height) return 0;
-
- return 1;
+ int count = rasterizer->edge_list.count;
+ CtxEntry temp[count+1]; /* copy of already built up path's poly line */
+ rasterizer->state->has_clipped=1;
+ rasterizer->state->gstate.clipped=1;
+ //if (rasterizer->preserve)
+ { memcpy (temp + 1, rasterizer->edge_list.entries, sizeof (temp) - sizeof (temp[0]));
+ temp[0].code = CTX_NOP;
+ temp[0].data.u32[0] = count;
+ ctx_state_set_blob (rasterizer->state, CTX_clip, (uint8_t*)temp, sizeof(temp));
+ }
+ ctx_rasterizer_clip_apply (rasterizer, temp);
+ ctx_rasterizer_reset (rasterizer);
+ if (rasterizer->preserve)
+ {
+ memcpy (rasterizer->edge_list.entries, temp + 1, sizeof (temp) - sizeof(temp[0]));
+ rasterizer->edge_list.count = count;
+ rasterizer->preserve = 0;
+ }
}
+
+#if 0
static void
-_ctx_add_hash (CtxHasher *hasher, CtxRectangle *shape_rect, char *hash)
+ctx_rasterizer_load_image (CtxRasterizer *rasterizer,
+ const char *path,
+ float x,
+ float y)
{
- CtxRectangle rect = {0,0, hasher->rasterizer.blit_width/hasher->cols,
- hasher->rasterizer.blit_height/hasher->rows};
- int hno = 0;
- for (int row = 0; row < hasher->rows; row++)
- for (int col = 0; col < hasher->cols; col++, hno++)
- {
- rect.x = col * rect.width;
- rect.y = row * rect.height;
- if (ctx_rect_intersect (shape_rect, &rect))
- {
- int temp = hasher->hashes[(row * hasher->cols + col) *20 + 0];
- for (int i = 0; i <19;i++)
- hasher->hashes[(row * hasher->cols + col) *20 + i] =
- hasher->hashes[(row * hasher->cols + col) *20 + i+1]^
- hash[i];
- hasher->hashes[(row * hasher->cols + col) *20 + 19] =
- temp ^ hash[19];
- }
- }
+ // decode PNG, put it in image is slot 1,
+ // magic width height stride format data
+ ctx_buffer_load_png (&rasterizer->ctx->texture[0], path);
+ ctx_rasterizer_set_texture (rasterizer, 0, x, y);
}
-
+#endif
static void
-ctx_hasher_process (void *user_data, CtxCommand *command)
+ctx_rasterizer_set_pixel (CtxRasterizer *rasterizer,
+ uint16_t x,
+ uint16_t y,
+ uint8_t r,
+ uint8_t g,
+ uint8_t b,
+ uint8_t a)
{
- CtxEntry *entry = &command->entry;
- CtxRasterizer *rasterizer = (CtxRasterizer *) user_data;
- CtxHasher *hasher = (CtxHasher*) user_data;
- CtxState *state = rasterizer->state;
- CtxCommand *c = (CtxCommand *) entry;
- int aa = rasterizer->aa;
- switch (c->code)
- {
- case CTX_TEXT:
- {
- CtxSHA1 sha1;
- ctx_sha1_init (&sha1);
- char ctx_sha1_hash[20];
- float width = ctx_text_width (rasterizer->ctx, ctx_arg_string());
+ rasterizer->state->gstate.source_fill.type = CTX_SOURCE_COLOR;
+ ctx_color_set_RGBA8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, r, g, b, a);
+#if 0
+ // XXX : doesn't take transforms into account
+ ctx_rasterizer_pset (rasterizer, x, y, 255);
+#else
+ ctx_rasterizer_move_to (rasterizer, x, y);
+ ctx_rasterizer_rel_line_to (rasterizer, 1, 0);
+ ctx_rasterizer_rel_line_to (rasterizer, 0, 1);
+ ctx_rasterizer_rel_line_to (rasterizer, -1, 0);
+ ctx_rasterizer_fill (rasterizer);
+#endif
+}
+static void
+ctx_rasterizer_rectangle (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ float width,
+ float height)
+{
+ ctx_rasterizer_move_to (rasterizer, x, y);
+ ctx_rasterizer_rel_line_to (rasterizer, width, 0);
+ ctx_rasterizer_rel_line_to (rasterizer, 0, height);
+ ctx_rasterizer_rel_line_to (rasterizer, -width, 0);
+ ctx_rasterizer_rel_line_to (rasterizer, 0, -height);
+ ctx_rasterizer_rel_line_to (rasterizer, 0.3, 0);
+ ctx_rasterizer_finish_shape (rasterizer);
+}
- float height = ctx_get_font_size (rasterizer->ctx);
- CtxRectangle shape_rect;
-
- shape_rect.x=rasterizer->x;
- shape_rect.y=rasterizer->y - height,
- shape_rect.width = width;
- shape_rect.height = height * 2;
- switch ((int)ctx_state_get (rasterizer->state, CTX_text_align))
- {
- case CTX_TEXT_ALIGN_LEFT:
- case CTX_TEXT_ALIGN_START:
- break;
- case CTX_TEXT_ALIGN_END:
- case CTX_TEXT_ALIGN_RIGHT:
- shape_rect.x -= shape_rect.width;
- break;
- case CTX_TEXT_ALIGN_CENTER:
- shape_rect.x -= shape_rect.width/2;
- break;
- // XXX : doesn't take all text-alignments into account
- }
+#if CTX_ENABLE_SHADOW_BLUR
+static float
+ctx_gaussian (float x, float mu, float sigma)
+{
+ float a = ( x- mu) / sigma;
+ return ctx_expf (-0.5 * a * a);
+}
- uint32_t color;
- ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source.color,
(uint8_t*)(&color));
- ctx_sha1_process(&sha1, (const unsigned char*)ctx_arg_string(), strlen (ctx_arg_string()));
- ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof
(rasterizer->state->gstate.transform));
- ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
- ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxRectangle));
- ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
- _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
+static void
+ctx_compute_gaussian_kernel (int dim, float radius, float *kernel)
+{
+ float sigma = radius / 2;
+ float sum = 0.0;
+ int i = 0;
+ //for (int row = 0; row < dim; row ++)
+ for (int col = 0; col < dim; col ++, i++)
+ {
+ float val = //ctx_gaussian (row, radius, sigma) *
+ ctx_gaussian (col, radius, sigma);
+ kernel[i] = val;
+ sum += val;
+ }
+ i = 0;
+ //for (int row = 0; row < dim; row ++)
+ for (int col = 0; col < dim; col ++, i++)
+ kernel[i] /= sum;
+}
+#endif
- ctx_rasterizer_rel_move_to (rasterizer, width, 0);
- }
- ctx_rasterizer_reset (rasterizer);
- break;
- case CTX_TEXT_STROKE:
- {
- CtxSHA1 sha1;
- ctx_sha1_init (&sha1);
- char ctx_sha1_hash[20];
- float width = ctx_text_width (rasterizer->ctx, ctx_arg_string());
- float height = ctx_get_font_size (rasterizer->ctx);
+static void
+ctx_rasterizer_round_rectangle (CtxRasterizer *rasterizer, float x, float y, float width, float height,
float corner_radius)
+{
+ float aspect = 1.0f;
+ float radius = corner_radius / aspect;
+ float degrees = CTX_PI / 180.0f;
- CtxRectangle shape_rect = {
- rasterizer->x, rasterizer->y - height,
- width, height * 2
- };
+ if (radius > width/2) radius = width/2;
+ if (radius > height/2) radius = height/2;
- uint32_t color;
- ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source.color,
(uint8_t*)(&color));
- ctx_sha1_process(&sha1, (unsigned char*)ctx_arg_string(), strlen (ctx_arg_string()));
- ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof
(rasterizer->state->gstate.transform));
- ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
- ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxRectangle));
- ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
- _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
+ ctx_rasterizer_finish_shape (rasterizer);
+ ctx_rasterizer_arc (rasterizer, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees, 0);
+ ctx_rasterizer_arc (rasterizer, x + width - radius, y + height - radius, radius, 0 * degrees, 90 *
degrees, 0);
+ ctx_rasterizer_arc (rasterizer, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees, 0);
+ ctx_rasterizer_arc (rasterizer, x + radius, y + radius, radius, 180 * degrees, 270 * degrees, 0);
+ ctx_rasterizer_finish_shape (rasterizer);
+}
- ctx_rasterizer_rel_move_to (rasterizer, width, 0);
- }
- ctx_rasterizer_reset (rasterizer);
- break;
- case CTX_GLYPH:
- {
- CtxSHA1 sha1;
- ctx_sha1_init (&sha1);
+static void
+ctx_rasterizer_process (void *user_data, CtxCommand *command);
- char ctx_sha1_hash[20];
- uint8_t string[8];
- string[ctx_unichar_to_utf8 (c->u32.a0, string)]=0;
- float width = ctx_text_width (rasterizer->ctx, (char*)string);
- float height = ctx_get_font_size (rasterizer->ctx);
+int
+_ctx_is_rasterizer (Ctx *ctx)
+{
+ if (ctx->renderer && ctx->renderer->process == ctx_rasterizer_process)
+ return 1;
+ return 0;
+}
- float tx = rasterizer->x;
- float ty = rasterizer->y;
- float tw = width;
- float th = height * 2;
+#if CTX_COMPOSITING_GROUPS
+static void
+ctx_rasterizer_start_group (CtxRasterizer *rasterizer)
+{
+ CtxEntry save_command = ctx_void(CTX_SAVE);
+ // allocate buffer, and set it as temporary target
+ int no;
+ if (rasterizer->group[0] == NULL) // first group
+ {
+ rasterizer->saved_buf = rasterizer->buf;
+ }
+ for (no = 0; rasterizer->group[no] && no < CTX_GROUP_MAX; no++);
- _ctx_user_to_device (rasterizer->state, &tx, &ty);
- _ctx_user_to_device_distance (rasterizer->state, &tw, &th);
- CtxRectangle shape_rect = {tx,ty-th/2,tw,th};
+ if (no >= CTX_GROUP_MAX)
+ return;
+ rasterizer->group[no] = ctx_buffer_new (rasterizer->blit_width,
+ rasterizer->blit_height,
+ rasterizer->format->composite_format);
+ rasterizer->buf = rasterizer->group[no]->data;
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
+}
+static void
+ctx_rasterizer_end_group (CtxRasterizer *rasterizer)
+{
+ CtxEntry restore_command = ctx_void(CTX_RESTORE);
+ CtxEntry save_command = ctx_void(CTX_SAVE);
+ int no = 0;
+ for (no = 0; rasterizer->group[no] && no < CTX_GROUP_MAX; no++);
+ no--;
- uint32_t color;
- ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source.color,
(uint8_t*)(&color));
- ctx_sha1_process(&sha1, string, strlen ((const char*)string));
- ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof
(rasterizer->state->gstate.transform));
- ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
- ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxRectangle));
- ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
- _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
+ if (no < 0)
+ return;
- ctx_rasterizer_rel_move_to (rasterizer, width, 0);
- ctx_rasterizer_reset (rasterizer);
- }
- break;
- case CTX_FILL:
- {
- CtxSHA1 sha1;
- ctx_sha1_init (&sha1);
- char ctx_sha1_hash[20];
+ CtxCompositingMode comp = rasterizer->state->gstate.compositing_mode;
+ CtxBlend blend = rasterizer->state->gstate.blend_mode;
+ float global_alpha = rasterizer->state->gstate.global_alpha_f;
+ // fetch compositing, blending, global alpha
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
+ CtxEntry set_state[3]=
+ {
+ ctx_u8 (CTX_COMPOSITING_MODE, comp, 0,0,0,0,0,0,0),
+ ctx_u8 (CTX_BLEND_MODE, blend, 0,0,0,0,0,0,0),
+ ctx_f (CTX_GLOBAL_ALPHA, global_alpha, 0.0)
+ };
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[0]);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[1]);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[2]);
+ if (no == 0)
+ {
+ rasterizer->buf = rasterizer->saved_buf;
+ }
+ else
+ {
+ rasterizer->buf = rasterizer->group[no-1]->data;
+ }
+ // XXX use texture_source ?
+ ctx_texture_init (rasterizer->ctx, ".ctx-group", // XXX ? count groups..
+ rasterizer->blit_width, // or have group based on thread-id?
+ rasterizer->blit_height, // .. this would mean threadsafe
+ // allocation
+ rasterizer->blit_width * rasterizer->format->bpp/8,
+ rasterizer->format->pixel_format,
+ NULL, // space
+ (uint8_t*)rasterizer->group[no]->data,
+ NULL, NULL);
+ {
+ char *eid = ".ctx-group";
+ int eid_len = strlen (eid);
- /* we eant this hasher to be as good as possible internally,
- * since it is also used in the small shapes rasterization
- * cache
- */
- uint64_t hash = ctx_rasterizer_poly_to_hash (rasterizer);
- CtxRectangle shape_rect = {
- rasterizer->col_min / CTX_SUBDIV,
- rasterizer->scan_min / aa,
- (rasterizer->col_max - rasterizer->col_min + 1) / CTX_SUBDIV,
- (rasterizer->scan_max - rasterizer->scan_min + 1) / aa
- };
+ CtxEntry commands[4] =
+ {
+ ctx_f (CTX_TEXTURE, rasterizer->blit_x, rasterizer->blit_y),
+ ctx_u32 (CTX_DATA, eid_len, eid_len/9+1),
+ ctx_u32 (CTX_CONT, 0,0),
+ ctx_u32 (CTX_CONT, 0,0)
+ };
+ memcpy( (char *) &commands[2].data.u8[0], eid, eid_len);
+ ( (char *) (&commands[2].data.u8[0]) ) [eid_len]=0;
- hash ^= (rasterizer->state->gstate.fill_rule * 23);
- hash ^= (rasterizer->state->gstate.source.type * 117);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
+ }
+ {
+ CtxEntry commands[2]=
+ {
+ ctx_f (CTX_RECTANGLE, rasterizer->blit_x, rasterizer->blit_y),
+ ctx_f (CTX_CONT, rasterizer->blit_width, rasterizer->blit_height)
+ };
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
+ }
+ {
+ CtxEntry commands[1]= { ctx_void (CTX_FILL) };
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
+ }
+ //ctx_texture_release (rasterizer->ctx, ".ctx-group");
+ ctx_buffer_free (rasterizer->group[no]);
+ rasterizer->group[no] = 0;
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
+}
+#endif
- ctx_sha1_process(&sha1, (unsigned char*)&hash, 8);
+#if CTX_ENABLE_SHADOW_BLUR
+static void
+ctx_rasterizer_shadow_stroke (CtxRasterizer *rasterizer)
+{
+ CtxColor color;
+ CtxEntry save_command = ctx_void(CTX_SAVE);
- uint32_t color;
- ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source.color, (uint8_t*)(&color));
+ float rgba[4] = {0, 0, 0, 1.0};
+ if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
+ ctx_color_get_rgba (rasterizer->state, &color, rgba);
- ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
- ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
- _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
+ CtxEntry set_color_command [3]=
+ {
+ ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
+ ctx_f (CTX_CONT, rgba[1], rgba[2]),
+ ctx_f (CTX_CONT, rgba[3], 0)
+ };
+ CtxEntry restore_command = ctx_void(CTX_RESTORE);
+ float radius = rasterizer->state->gstate.shadow_blur;
+ int dim = 2 * radius + 1;
+ if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
+ dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
+ ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
+ {
+ int i = 0;
+ for (int v = 0; v < dim; v += 1, i++)
+ {
+ float dy = rasterizer->state->gstate.shadow_offset_y + v - dim/2;
+ set_color_command[2].data.f[0] = rasterizer->kernel[i] * rgba[3];
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command[0]);
+#if CTX_ENABLE_SHADOW_BLUR
+ rasterizer->in_shadow = 1;
+#endif
+ rasterizer->shadow_x = rasterizer->state->gstate.shadow_offset_x;
+ rasterizer->shadow_y = dy;
+ rasterizer->preserve = 1;
+ ctx_rasterizer_stroke (rasterizer);
+#if CTX_ENABLE_SHADOW_BLUR
+ rasterizer->in_shadow = 0;
+#endif
+ }
+ }
+ //free (kernel);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
+}
- if (!rasterizer->preserve)
- ctx_rasterizer_reset (rasterizer);
- rasterizer->preserve = 0;
- }
- break;
- case CTX_STROKE:
- {
- CtxSHA1 sha1;
- ctx_sha1_init (&sha1);
- char ctx_sha1_hash[20];
- uint64_t hash = ctx_rasterizer_poly_to_hash (rasterizer);
- CtxRectangle shape_rect = {
- rasterizer->col_min / CTX_SUBDIV - rasterizer->state->gstate.line_width,
- rasterizer->scan_min / aa - rasterizer->state->gstate.line_width,
- (rasterizer->col_max - rasterizer->col_min + 1) / CTX_SUBDIV +
rasterizer->state->gstate.line_width,
- (rasterizer->scan_max - rasterizer->scan_min + 1) / aa + rasterizer->state->gstate.line_width
- };
+static void
+ctx_rasterizer_shadow_text (CtxRasterizer *rasterizer, const char *str)
+{
+ float x = rasterizer->state->x;
+ float y = rasterizer->state->y;
+ CtxColor color;
+ CtxEntry save_command = ctx_void(CTX_SAVE);
- 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;
+ float rgba[4] = {0, 0, 0, 1.0};
+ if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
+ ctx_color_get_rgba (rasterizer->state, &color, rgba);
- hash ^= (int)(rasterizer->state->gstate.line_width * 110);
- hash ^= (rasterizer->state->gstate.line_cap * 23);
- hash ^= (rasterizer->state->gstate.source.type * 117);
+ CtxEntry set_color_command [3]=
+ {
+ ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
+ ctx_f (CTX_CONT, rgba[1], rgba[2]),
+ ctx_f (CTX_CONT, rgba[3], 0)
+ };
+ CtxEntry move_to_command [1]=
+ {
+ ctx_f (CTX_MOVE_TO, x, y),
+ };
+ CtxEntry restore_command = ctx_void(CTX_RESTORE);
+ float radius = rasterizer->state->gstate.shadow_blur;
+ int dim = 2 * radius + 1;
+ if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
+ dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
+ ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
- ctx_sha1_process(&sha1, (unsigned char*)&hash, 8);
+ {
+ {
+ move_to_command[0].data.f[0] = x;
+ move_to_command[0].data.f[1] = y;
+ set_color_command[2].data.f[0] = rgba[3];
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&move_to_command);
+ rasterizer->in_shadow=1;
+ ctx_rasterizer_text (rasterizer, str, 0);
+ rasterizer->in_shadow=0;
+ }
+ }
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
+ move_to_command[0].data.f[0] = x;
+ move_to_command[0].data.f[1] = y;
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&move_to_command);
+}
- uint32_t color;
- ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source.color, (uint8_t*)(&color));
+static void
+ctx_rasterizer_shadow_fill (CtxRasterizer *rasterizer)
+{
+ CtxColor color;
+ CtxEntry save_command = ctx_void(CTX_SAVE);
- ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
+ float rgba[4] = {0, 0, 0, 1.0};
+ if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
+ ctx_color_get_rgba (rasterizer->state, &color, rgba);
- ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
- _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
- }
- if (!rasterizer->preserve)
- ctx_rasterizer_reset (rasterizer);
- rasterizer->preserve = 0;
- break;
- /* the above cases are the painting cases and
- * the only ones differing from the rasterizer's process switch
- */
+ CtxEntry set_color_command [3]=
+ {
+ ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
+ ctx_f (CTX_CONT, rgba[1], rgba[2]),
+ ctx_f (CTX_CONT, rgba[3], 0)
+ };
+ CtxEntry restore_command = ctx_void(CTX_RESTORE);
+ float radius = rasterizer->state->gstate.shadow_blur;
+ int dim = 2 * radius + 1;
+ if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
+ dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
+ ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
- case CTX_LINE_TO:
- ctx_rasterizer_line_to (rasterizer, c->c.x0, c->c.y0);
- break;
- case CTX_REL_LINE_TO:
- ctx_rasterizer_rel_line_to (rasterizer, c->c.x0, c->c.y0);
- break;
- case CTX_MOVE_TO:
- ctx_rasterizer_move_to (rasterizer, c->c.x0, c->c.y0);
- break;
- case CTX_REL_MOVE_TO:
- ctx_rasterizer_rel_move_to (rasterizer, c->c.x0, c->c.y0);
- break;
- case CTX_CURVE_TO:
- ctx_rasterizer_curve_to (rasterizer, c->c.x0, c->c.y0,
- c->c.x1, c->c.y1,
- c->c.x2, c->c.y2);
- break;
- case CTX_REL_CURVE_TO:
- ctx_rasterizer_rel_curve_to (rasterizer, c->c.x0, c->c.y0,
- c->c.x1, c->c.y1,
- c->c.x2, c->c.y2);
- break;
- case CTX_QUAD_TO:
- ctx_rasterizer_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
- break;
- case CTX_REL_QUAD_TO:
- 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);
- break;
- case CTX_RECTANGLE:
- ctx_rasterizer_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
- c->rectangle.width, c->rectangle.height);
- break;
- case CTX_ROUND_RECTANGLE:
- ctx_rasterizer_round_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
- c->rectangle.width, c->rectangle.height,
- c->rectangle.radius);
- break;
- case CTX_SET_PIXEL:
- ctx_rasterizer_set_pixel (rasterizer, c->set_pixel.x, c->set_pixel.y,
- c->set_pixel.rgba[0],
+ {
+ for (int v = 0; v < dim; v ++)
+ {
+ int i = v;
+ float dy = rasterizer->state->gstate.shadow_offset_y + v - dim/2;
+ set_color_command[2].data.f[0] = rasterizer->kernel[i] * rgba[3];
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command);
+ rasterizer->in_shadow = 1;
+ rasterizer->shadow_x = rasterizer->state->gstate.shadow_offset_x;
+ rasterizer->shadow_y = dy;
+ rasterizer->preserve = 1;
+ ctx_rasterizer_fill (rasterizer);
+ rasterizer->in_shadow = 0;
+ }
+ }
+ ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
+}
+#endif
+
+static void
+ctx_rasterizer_line_dash (CtxRasterizer *rasterizer, int count, float *dashes)
+{
+ if (!dashes)
+ {
+ rasterizer->state->gstate.n_dashes = 0;
+ return;
+ }
+ count = CTX_MIN(count, CTX_PARSER_MAX_ARGS-1);
+ rasterizer->state->gstate.n_dashes = count;
+ memcpy(&rasterizer->state->gstate.dashes[0], dashes, count * sizeof(float));
+ for (int i = 0; i < count; i ++)
+ {
+ if (rasterizer->state->gstate.dashes[i] < 0.0001f)
+ rasterizer->state->gstate.dashes[i] = 0.0001f; // hang protection
+ }
+}
+
+
+static void
+ctx_rasterizer_process (void *user_data, CtxCommand *command)
+{
+ CtxEntry *entry = &command->entry;
+ CtxRasterizer *rasterizer = (CtxRasterizer *) user_data;
+ CtxState *state = rasterizer->state;
+ CtxCommand *c = (CtxCommand *) entry;
+ int clear_clip = 0;
+ switch (c->code)
+ {
+#if CTX_ENABLE_SHADOW_BLUR
+ case CTX_SHADOW_COLOR:
+ {
+ CtxColor col;
+ CtxColor *color = &col;
+ //state->gstate.source_fill.type = CTX_SOURCE_COLOR;
+ switch ((int)c->rgba.model)
+ {
+ case CTX_RGB:
+ ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, 1.0f);
+ break;
+ case CTX_RGBA:
+ //ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
+ ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
+ break;
+ case CTX_DRGBA:
+ ctx_color_set_drgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
+ break;
+#if CTX_ENABLE_CMYK
+ case CTX_CMYKA:
+ ctx_color_set_cmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k,
c->cmyka.a);
+ break;
+ case CTX_CMYK:
+ ctx_color_set_cmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, 1.0f);
+ break;
+ case CTX_DCMYKA:
+ ctx_color_set_dcmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k,
c->cmyka.a);
+ break;
+ case CTX_DCMYK:
+ ctx_color_set_dcmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, 1.0f);
+ break;
+#endif
+ case CTX_GRAYA:
+ ctx_color_set_graya (state, color, c->graya.g, c->graya.a);
+ break;
+ case CTX_GRAY:
+ ctx_color_set_graya (state, color, c->graya.g, 1.0f);
+ break;
+ }
+ ctx_set_color (rasterizer->ctx, CTX_shadowColor, color);
+ }
+ break;
+#endif
+ case CTX_LINE_DASH:
+ if (c->line_dash.count)
+ {
+ ctx_rasterizer_line_dash (rasterizer, c->line_dash.count, c->line_dash.data);
+ }
+ else
+ ctx_rasterizer_line_dash (rasterizer, 0, NULL);
+ break;
+
+ case CTX_LINE_TO:
+ ctx_rasterizer_line_to (rasterizer, c->c.x0, c->c.y0);
+ break;
+ case CTX_REL_LINE_TO:
+ ctx_rasterizer_rel_line_to (rasterizer, c->c.x0, c->c.y0);
+ break;
+ case CTX_MOVE_TO:
+ ctx_rasterizer_move_to (rasterizer, c->c.x0, c->c.y0);
+ break;
+ case CTX_REL_MOVE_TO:
+ ctx_rasterizer_rel_move_to (rasterizer, c->c.x0, c->c.y0);
+ break;
+ case CTX_CURVE_TO:
+ ctx_rasterizer_curve_to (rasterizer, c->c.x0, c->c.y0,
+ c->c.x1, c->c.y1,
+ c->c.x2, c->c.y2);
+ break;
+ case CTX_REL_CURVE_TO:
+ ctx_rasterizer_rel_curve_to (rasterizer, c->c.x0, c->c.y0,
+ c->c.x1, c->c.y1,
+ c->c.x2, c->c.y2);
+ break;
+ case CTX_QUAD_TO:
+ ctx_rasterizer_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
+ break;
+ case CTX_REL_QUAD_TO:
+ 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);
+ break;
+ case CTX_RECTANGLE:
+ ctx_rasterizer_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
+ c->rectangle.width, c->rectangle.height);
+ break;
+ case CTX_ROUND_RECTANGLE:
+ ctx_rasterizer_round_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
+ c->rectangle.width, c->rectangle.height,
+ c->rectangle.radius);
+ break;
+ case CTX_SET_PIXEL:
+ ctx_rasterizer_set_pixel (rasterizer, c->set_pixel.x, c->set_pixel.y,
+ c->set_pixel.rgba[0],
c->set_pixel.rgba[1],
c->set_pixel.rgba[2],
c->set_pixel.rgba[3]);
break;
+ case CTX_DEFINE_TEXTURE:
+ {
+ uint8_t *pixel_data = ctx_define_texture_pixel_data (entry);
+ ctx_rasterizer_define_texture (rasterizer, c->define_texture.eid,
+ c->define_texture.width, c->define_texture.height,
+ c->define_texture.format,
+ pixel_data);
+ }
+ break;
case CTX_TEXTURE:
-#if 0
- ctx_rasterizer_set_texture (rasterizer, ctx_arg_u32 (0),
- ctx_arg_float (2), ctx_arg_float (3) );
-#endif
+ ctx_rasterizer_set_texture (rasterizer, c->texture.eid,
+ c->texture.x, c->texture.y);
+ rasterizer->comp_op = NULL;
break;
#if 0
case CTX_LOAD_IMAGE:
@@ -12151,3850 +12435,5526 @@ ctx_hasher_process (void *user_data, CtxCommand *command)
break;
case CTX_LINEAR_GRADIENT:
ctx_state_gradient_clear_stops (rasterizer->state);
+ rasterizer->comp_op = NULL;
break;
case CTX_RADIAL_GRADIENT:
ctx_state_gradient_clear_stops (rasterizer->state);
+ rasterizer->comp_op = NULL;
break;
#endif
case CTX_PRESERVE:
rasterizer->preserve = 1;
break;
+ case CTX_COLOR:
+ case CTX_COMPOSITING_MODE:
+ case CTX_BLEND_MODE:
+ rasterizer->comp_op = NULL;
+ break;
+#if CTX_COMPOSITING_GROUPS
+ case CTX_START_GROUP:
+ ctx_rasterizer_start_group (rasterizer);
+ break;
+ case CTX_END_GROUP:
+ ctx_rasterizer_end_group (rasterizer);
+ break;
+#endif
+
+ case CTX_RESTORE:
+ for (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)
+ {
+ clear_clip = 1;
+ }
+ }
+ /* FALLTHROUGH */
case CTX_ROTATE:
case CTX_SCALE:
case CTX_TRANSLATE:
case CTX_SAVE:
- case CTX_RESTORE:
+ rasterizer->comp_op = NULL;
rasterizer->uses_transforms = 1;
ctx_interpret_transforms (rasterizer->state, entry, NULL);
-
-
- break;
- case CTX_FONT:
- ctx_rasterizer_set_font (rasterizer, ctx_arg_string() );
- break;
- case CTX_BEGIN_PATH:
- ctx_rasterizer_reset (rasterizer);
- break;
- case CTX_CLIP:
- // should perhaps modify a global state to include
- // in hash?
- ctx_rasterizer_clip (rasterizer);
- break;
- case CTX_CLOSE_PATH:
- ctx_rasterizer_finish_shape (rasterizer);
+ if (clear_clip)
+ {
+ ctx_rasterizer_clip_reset (rasterizer);
+ for (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)
+ {
+ int idx = ctx_float_to_string_index (state->keydb[i].value);
+ if (idx >=0)
+ {
+ CtxEntry *edges = (CtxEntry*)&state->stringpool[idx];
+ ctx_rasterizer_clip_apply (rasterizer, edges);
+ }
+ }
+ }
+ }
break;
- }
- ctx_interpret_pos_bare (rasterizer->state, entry, NULL);
- ctx_interpret_style (rasterizer->state, entry, NULL);
- if (command->code == CTX_LINE_WIDTH)
- {
- float x = state->gstate.line_width;
- /* normalize line width according to scaling factor
- */
- x = x * ctx_maxf (ctx_maxf (ctx_fabsf (state->gstate.transform.m[0][0]),
- ctx_fabsf (state->gstate.transform.m[0][1]) ),
- ctx_maxf (ctx_fabsf (state->gstate.transform.m[1][0]),
- ctx_fabsf (state->gstate.transform.m[1][1]) ) );
- state->gstate.line_width = x;
- }
-}
+ case CTX_STROKE:
+#if CTX_ENABLE_SHADOW_BLUR
+ if (rasterizer->state->gstate.shadow_blur > 0.0 &&
+ !rasterizer->in_text)
+ ctx_rasterizer_shadow_stroke (rasterizer);
+#endif
+ if (rasterizer->state->gstate.n_dashes)
+ {
+ int n_dashes = rasterizer->state->gstate.n_dashes;
+ float *dashes = rasterizer->state->gstate.dashes;
+ float factor = ctx_matrix_get_scale (&state->gstate.transform);
+ int count = rasterizer->edge_list.count;
+ int aa = rasterizer->aa;
+ CtxEntry temp[count]; /* copy of already built up path's poly line */
+ memcpy (temp, rasterizer->edge_list.entries, sizeof (temp));
+ int start = 0;
+ int end = 0;
+ CtxMatrix transform_backup = rasterizer->state->gstate.transform;
+ ctx_matrix_identity (&rasterizer->state->gstate.transform);
+ 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;
-static CtxRasterizer *
-ctx_hasher_init (CtxRasterizer *rasterizer, Ctx *ctx, CtxState *state, int width, int height, int cols, int
rows)
-{
- CtxHasher *hasher = (CtxHasher*)rasterizer;
- ctx_memset (rasterizer, 0, sizeof (CtxHasher) );
- rasterizer->vfuncs.process = ctx_hasher_process;
- rasterizer->vfuncs.free = (CtxDestroyNotify)ctx_rasterizer_deinit;
- // XXX need own destructor to not leak ->hashes
- rasterizer->edge_list.flags |= CTX_DRAWLIST_EDGE_LIST;
- rasterizer->state = state;
- rasterizer->ctx = ctx;
- ctx_state_init (rasterizer->state);
- rasterizer->blit_x = 0;
- rasterizer->blit_y = 0;
- rasterizer->blit_width = width;
- rasterizer->blit_height = height;
- rasterizer->state->gstate.clip_min_x = 0;
- rasterizer->state->gstate.clip_min_y = 0;
- rasterizer->state->gstate.clip_max_x = width - 1;
- rasterizer->state->gstate.clip_max_y = height - 1;
- rasterizer->scan_min = 5000;
- rasterizer->scan_max = -5000;
- rasterizer->aa = 5;
- rasterizer->force_aa = 0;
-
- hasher->rows = rows;
- hasher->cols = cols;
+ int dash_no = 0.0;
+ float dash_lpos = rasterizer->state->gstate.line_dash_offset * factor;
+ int is_down = 0;
- hasher->hashes = (uint8_t*)ctx_calloc (20, rows * cols);
+ while (start < count)
+ {
+ int started = 0;
+ int i;
+ is_down = 0;
- return rasterizer;
-}
+ if (!is_down)
+ {
+ CtxEntry *entry = &temp[0];
+ prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
+ prev_y = entry->data.s16[1] * 1.0f / aa;
+ ctx_rasterizer_move_to (rasterizer, prev_x, prev_y);
+ is_down = 1;
+ }
-Ctx *ctx_hasher_new (int width, int height, int cols, int rows)
-{
- Ctx *ctx = ctx_new ();
- CtxState *state = &ctx->state;
- CtxRasterizer *rasterizer = (CtxRasterizer *) ctx_calloc (sizeof (CtxHasher), 1);
- ctx_hasher_init (rasterizer, ctx, state, width, height, cols, rows);
- ctx_set_renderer (ctx, (void*)rasterizer);
- return ctx;
-}
-uint8_t *ctx_hasher_get_hash (Ctx *ctx, int col, int row)
-{
- CtxHasher *hasher = (CtxHasher*)ctx->renderer;
- if (row < 0) row =0;
- if (col < 0) col =0;
- if (row >= hasher->rows) row = hasher->rows-1;
- if (col >= hasher->cols) col = hasher->cols-1;
- return &hasher->hashes[(row*hasher->cols+col)*20];
-}
+ for (i = start; i < count; i++)
+ {
+ CtxEntry *entry = &temp[i];
+ float x, y;
+ if (entry->code == CTX_NEW_EDGE)
+ {
+ if (started)
+ {
+ end = i - 1;
+ dash_no = 0;
+ dash_lpos = 0.0;
+ goto foo;
+ }
+ prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
+ prev_y = entry->data.s16[1] * 1.0f / aa;
+ started = 1;
+ start = i;
+ is_down = 1;
+ ctx_rasterizer_move_to (rasterizer, prev_x, prev_y);
+ }
-#endif
-#if CTX_EVENTS
+again:
+ x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
+ y = entry->data.s16[3] * 1.0f / aa;
+ float dx = x - prev_x;
+ float dy = y - prev_y;
+ float length = ctx_fast_hypotf (dx, dy);
-#include <fcntl.h>
-#include <sys/ioctl.h>
-int ctx_terminal_width (void)
-{
- struct winsize ws;
- if (ioctl(0,TIOCGWINSZ,&ws)!=0)
- return 80;
- return ws.ws_xpixel;
-}
+ if (dash_lpos + length >= dashes[dash_no] * factor)
+ {
+ float p = (dashes[dash_no] * factor - dash_lpos) / length;
+ float splitx = x * p + (1.0f - p) * prev_x;
+ float splity = y * p + (1.0f - p) * prev_y;
+ if (is_down)
+ {
+ ctx_rasterizer_line_to (rasterizer, splitx, splity);
+ is_down = 0;
+ }
+ else
+ {
+ ctx_rasterizer_move_to (rasterizer, splitx, splity);
+ is_down = 1;
+ }
+ prev_x = splitx;
+ prev_y = splity;
+ dash_no++;
+ dash_lpos=0;
+ if (dash_no >= n_dashes) dash_no = 0;
+ goto again;
+ }
+ else
+ {
+ pos += length;
+ dash_lpos += length;
+ {
+ if (is_down)
+ ctx_rasterizer_line_to (rasterizer, x, y);
+ }
+ }
+ prev_x = x;
+ prev_y = y;
+ }
+ end = i-1;
+foo:
+ start = end+1;
+ }
+ rasterizer->state->gstate.transform = transform_backup;
+ }
-int ctx_terminal_height (void)
-{
- struct winsize ws;
- if (ioctl(0,TIOCGWINSZ,&ws)!=0)
- return 80;
- return ws.ws_ypixel;
-}
+ ctx_rasterizer_stroke (rasterizer);
+ break;
+ case CTX_FONT:
+ ctx_rasterizer_set_font (rasterizer, ctx_arg_string() );
+ break;
+ case CTX_TEXT:
+ rasterizer->in_text++;
+#if CTX_ENABLE_SHADOW_BLUR
+ if (rasterizer->state->gstate.shadow_blur > 0.0)
+ ctx_rasterizer_shadow_text (rasterizer, ctx_arg_string ());
+#endif
+ ctx_rasterizer_text (rasterizer, ctx_arg_string(), 0);
+ rasterizer->in_text--;
+ ctx_rasterizer_reset (rasterizer);
+ break;
+ case CTX_STROKE_TEXT:
+ ctx_rasterizer_text (rasterizer, ctx_arg_string(), 1);
+ ctx_rasterizer_reset (rasterizer);
+ break;
+ case CTX_GLYPH:
+ ctx_rasterizer_glyph (rasterizer, entry[0].data.u32[0], entry[0].data.u8[4]);
+ break;
+ case CTX_FILL:
+#if CTX_ENABLE_SHADOW_BLUR
+ if (rasterizer->state->gstate.shadow_blur > 0.0 &&
+ !rasterizer->in_text)
+ ctx_rasterizer_shadow_fill (rasterizer);
+#endif
+ ctx_rasterizer_fill (rasterizer);
+ break;
+ case CTX_RESET:
+ case CTX_BEGIN_PATH:
+ ctx_rasterizer_reset (rasterizer);
+ break;
+ case CTX_CLIP:
+ ctx_rasterizer_clip (rasterizer);
+ break;
+ case CTX_CLOSE_PATH:
+ ctx_rasterizer_finish_shape (rasterizer);
+ break;
+ }
+ ctx_interpret_pos_bare (rasterizer->state, entry, NULL);
+ ctx_interpret_style (rasterizer->state, entry, NULL);
+}
-int ctx_terminal_cols (void)
+void
+ctx_rasterizer_deinit (CtxRasterizer *rasterizer)
{
- struct winsize ws;
- if (ioctl(0,TIOCGWINSZ,&ws)!=0)
- return 80;
- return ws.ws_col;
-}
+ ctx_drawlist_deinit (&rasterizer->edge_list);
+#if CTX_ENABLE_CLIP
+ if (rasterizer->clip_buffer)
+ {
+ ctx_buffer_free (rasterizer->clip_buffer);
+ rasterizer->clip_buffer = NULL;
+ }
+#endif
+#if CTX_SHAPE_CACHE
+ for (int i = 0; i < CTX_SHAPE_CACHE_ENTRIES; i ++)
+ if (rasterizer->shape_cache.entries[i])
+ {
+ free (rasterizer->shape_cache.entries[i]);
+ rasterizer->shape_cache.entries[i] = NULL;
+ }
-int ctx_terminal_rows (void)
-{
- struct winsize ws;
- if (ioctl(0,TIOCGWINSZ,&ws)!=0)
- return 25;
- return ws.ws_row;
+#endif
+ free (rasterizer);
}
+int ctx_renderer_is_sdl (Ctx *ctx);
+int ctx_renderer_is_fb (Ctx *ctx);
-
-
-
-#define DECTCEM_CURSOR_SHOW "\033[?25h"
-#define DECTCEM_CURSOR_HIDE "\033[?25l"
-#define TERMINAL_MOUSE_OFF "\033[?1000l\033[?1003l"
-#define TERMINAL_MOUSE_ON_BASIC "\033[?1000h"
-#define TERMINAL_MOUSE_ON_DRAG "\033[?1000h\033[?1003h" /* +ON_BASIC for wider */
-#define TERMINAL_MOUSE_ON_FULL "\033[?1000h\033[?1004h" /* compatibility */
-#define XTERM_ALTSCREEN_ON "\033[?47h"
-#define XTERM_ALTSCREEN_OFF "\033[?47l"
-
-/*************************** input handling *************************/
-
-#include <termios.h>
-#include <errno.h>
-#include <signal.h>
-
-#define DELAY_MS 100
-
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
+int _ctx_is_rasterizer (Ctx *ctx);
+CtxAntialias ctx_get_antialias (Ctx *ctx)
+{
+#if CTX_EVENTS
+ if (ctx_renderer_is_sdl (ctx) || ctx_renderer_is_fb (ctx))
+ {
+ CtxTiled *fb = (CtxTiled*)(ctx->renderer);
+ return fb->antialias;
+ }
#endif
+ if (!_ctx_is_rasterizer (ctx)) return CTX_ANTIALIAS_DEFAULT;
-static int size_changed = 0; /* XXX: global state */
-static int signal_installed = 0; /* XXX: global state */
+ switch (((CtxRasterizer*)(ctx->renderer))->aa)
+ {
+ case 1: return CTX_ANTIALIAS_NONE;
+ case 3: return CTX_ANTIALIAS_FAST;
+ case 5: return CTX_ANTIALIAS_GOOD;
+ default:
+ case 15: return CTX_ANTIALIAS_DEFAULT;
+ case 17: return CTX_ANTIALIAS_BEST;
+ }
+}
-static const char *mouse_modes[]=
-{TERMINAL_MOUSE_OFF,
- TERMINAL_MOUSE_ON_BASIC,
- TERMINAL_MOUSE_ON_DRAG,
- TERMINAL_MOUSE_ON_FULL,
- NULL};
+int _ctx_antialias_to_aa (CtxAntialias antialias)
+{
+ switch (antialias)
+ {
+ case CTX_ANTIALIAS_NONE: return 1;
+ case CTX_ANTIALIAS_FAST: return 3;
+ case CTX_ANTIALIAS_GOOD: return 5;
+ default:
+ case CTX_ANTIALIAS_DEFAULT: return CTX_RASTERIZER_AA;
+ case CTX_ANTIALIAS_BEST: return 17;
+ }
+}
-/* note that a nick can have multiple occurences, the labels
- * should be kept the same for all occurences of a combination. */
-typedef struct NcKeyCode {
- const char *nick; /* programmers name for key (combo) */
- const char *label; /* utf8 label for key */
- const char sequence[10]; /* terminal sequence */
-} NcKeyCode;
-static const NcKeyCode keycodes[]={
+void
+ctx_set_antialias (Ctx *ctx, CtxAntialias antialias)
+{
+#if CTX_EVENTS
+ if (ctx_renderer_is_sdl (ctx) || ctx_renderer_is_fb (ctx))
+ {
+ CtxTiled *fb = (CtxTiled*)(ctx->renderer);
+ fb->antialias = antialias;
+ for (int i = 0; i < _ctx_max_threads; i++)
+ {
+ ctx_set_antialias (fb->host[i], antialias);
+ }
+ return;
+ }
+#endif
+ if (!_ctx_is_rasterizer (ctx)) return;
- {"up", "↑", "\033[A"},
- {"down", "↓", "\033[B"},
- {"right", "→", "\033[C"},
- {"left", "←", "\033[D"},
+ ((CtxRasterizer*)(ctx->renderer))->aa =
+ _ctx_antialias_to_aa (antialias);
+/* vertical level of supersampling at full/forced AA.
+ *
+ * 1 is none, 3 is fast 5 is good 15 or 17 is best for 8bit
+ *
+ * valid values: - for other values we do not add up to 255
+ * 3 5 15 17 51
+ *
+ */
+}
- {"shift-up", "⇧↑", "\033[1;2A"},
- {"shift-down", "⇧↓", "\033[1;2B"},
- {"shift-right", "⇧→", "\033[1;2C"},
- {"shift-left", "⇧←", "\033[1;2D"},
+CtxRasterizer *
+ctx_rasterizer_init (CtxRasterizer *rasterizer, Ctx *ctx, Ctx *texture_source, CtxState *state, void *data,
int x, int y, int width, int height, int stride, CtxPixelFormat pixel_format, CtxAntialias antialias)
+{
+#if CTX_ENABLE_CLIP
+ if (rasterizer->clip_buffer)
+ ctx_buffer_free (rasterizer->clip_buffer);
+#endif
+ if (rasterizer->edge_list.size)
+ ctx_drawlist_deinit (&rasterizer->edge_list);
- {"alt-up", "^↑", "\033[1;3A"},
- {"alt-down", "^↓", "\033[1;3B"},
- {"alt-right", "^→", "\033[1;3C"},
- {"alt-left", "^←", "\033[1;3D"},
+ ctx_memset (rasterizer, 0, sizeof (CtxRasterizer) );
+ rasterizer->vfuncs.process = ctx_rasterizer_process;
+ rasterizer->vfuncs.free = (CtxDestroyNotify)ctx_rasterizer_deinit;
+ rasterizer->edge_list.flags |= CTX_DRAWLIST_EDGE_LIST;
+ rasterizer->state = state;
+ rasterizer->ctx = ctx;
+ rasterizer->texture_source = texture_source?texture_source:ctx;
+ rasterizer->aa = _ctx_antialias_to_aa (antialias);
+ rasterizer->force_aa = 0;
+ ctx_state_init (rasterizer->state);
+ rasterizer->buf = data;
+ rasterizer->blit_x = x;
+ rasterizer->blit_y = y;
+ rasterizer->blit_width = width;
+ rasterizer->blit_height = height;
+ rasterizer->state->gstate.clip_min_x = x;
+ rasterizer->state->gstate.clip_min_y = y;
+ rasterizer->state->gstate.clip_max_x = x + width - 1;
+ rasterizer->state->gstate.clip_max_y = y + height - 1;
+ rasterizer->blit_stride = stride;
+ rasterizer->scan_min = 5000;
+ rasterizer->scan_max = -5000;
+ rasterizer->format = ctx_pixel_format_info (pixel_format);
- {"alt-shift-up", "alt-s↑", "\033[1;4A"},
- {"alt-shift-down", "alt-s↓", "\033[1;4B"},
- {"alt-shift-right", "alt-s→", "\033[1;4C"},
- {"alt-shift-left", "alt-s←", "\033[1;4D"},
+ return rasterizer;
+}
- {"control-up", "^↑", "\033[1;5A"},
- {"control-down", "^↓", "\033[1;5B"},
- {"control-right", "^→", "\033[1;5C"},
- {"control-left", "^←", "\033[1;5D"},
+Ctx *
+ctx_new_for_buffer (CtxBuffer *buffer)
+{
+ Ctx *ctx = ctx_new ();
+ ctx_set_renderer (ctx,
+ ctx_rasterizer_init ( (CtxRasterizer *) malloc (sizeof (CtxRasterizer) ),
+ ctx, NULL, &ctx->state,
+ buffer->data, 0, 0, buffer->width, buffer->height,
+ buffer->stride, buffer->format->pixel_format,
+ CTX_ANTIALIAS_DEFAULT));
+ return ctx;
+}
- /* putty */
- {"control-up", "^↑", "\033OA"},
- {"control-down", "^↓", "\033OB"},
- {"control-right", "^→", "\033OC"},
- {"control-left", "^←", "\033OD"},
+Ctx *
+ctx_new_for_framebuffer (void *data, int width, int height,
+ int stride,
+ CtxPixelFormat pixel_format)
+{
+ Ctx *ctx = ctx_new ();
+ CtxRasterizer *r = ctx_rasterizer_init ( (CtxRasterizer *) ctx_calloc (sizeof (CtxRasterizer), 1),
+ ctx, NULL, &ctx->state, data, 0, 0, width, height,
+ stride, pixel_format, CTX_ANTIALIAS_DEFAULT);
+ ctx_set_renderer (ctx, r);
+ return ctx;
+}
- {"control-shift-up", "^⇧↑", "\033[1;6A"},
- {"control-shift-down", "^⇧↓", "\033[1;6B"},
- {"control-shift-right", "^⇧→", "\033[1;6C"},
- {"control-shift-left", "^⇧←", "\033[1;6D"},
+// ctx_new_for_stream (FILE *stream);
- {"control-up", "^↑", "\033Oa"},
- {"control-down", "^↓", "\033Ob"},
- {"control-right", "^→", "\033Oc"},
- {"control-left", "^←", "\033Od"},
+#if 0
+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 (CtxRenderer) );
+ ctx_rasterizer_init (rasterizer, state, data, x, y, width, height,
+ stride, pixel_format, CTX_ANTIALIAS_DEFAULT);
+}
+#endif
- {"shift-up", "⇧↑", "\033[a"},
- {"shift-down", "⇧↓", "\033[b"},
- {"shift-right", "⇧→", "\033[c"},
- {"shift-left", "⇧←", "\033[d"},
+CtxPixelFormatInfo *ctx_pixel_formats = NULL;
- {"insert", "ins", "\033[2~"},
- {"delete", "del", "\033[3~"},
- {"page-up", "PgUp", "\033[5~"},
- {"page-down", "PdDn", "\033[6~"},
- {"home", "Home", "\033OH"},
- {"end", "End", "\033OF"},
- {"home", "Home", "\033[H"},
- {"end", "End", "\033[F"},
- {"control-delete", "^del", "\033[3;5~"},
- {"shift-delete", "⇧del", "\033[3;2~"},
- {"control-shift-delete","^⇧del", "\033[3;6~"},
+extern CtxPixelFormatInfo ctx_pixel_formats_default[];
- {"F1", "F1", "\033[11~"},
- {"F2", "F2", "\033[12~"},
- {"F3", "F3", "\033[13~"},
- {"F4", "F4", "\033[14~"},
- {"F1", "F1", "\033OP"},
- {"F2", "F2", "\033OQ"},
- {"F3", "F3", "\033OR"},
- {"F4", "F4", "\033OS"},
- {"F5", "F5", "\033[15~"},
- {"F6", "F6", "\033[16~"},
- {"F7", "F7", "\033[17~"},
- {"F8", "F8", "\033[18~"},
- {"F9", "F9", "\033[19~"},
- {"F9", "F9", "\033[20~"},
- {"F10", "F10", "\033[21~"},
- {"F11", "F11", "\033[22~"},
- {"F12", "F12", "\033[23~"},
- {"tab", "↹", {9, '\0'}},
- {"shift-tab", "shift+↹", "\033[Z"},
- {"backspace", "⌫", {127, '\0'}},
- {"space", "␣", " "},
- {"esc", "␛", "\033"},
- {"return", "⏎", {10,0}},
- {"return", "⏎", {13,0}},
- /* this section could be autogenerated by code */
- {"control-a", "^A", {1,0}},
- {"control-b", "^B", {2,0}},
- {"control-c", "^C", {3,0}},
- {"control-d", "^D", {4,0}},
- {"control-e", "^E", {5,0}},
- {"control-f", "^F", {6,0}},
- {"control-g", "^G", {7,0}},
- {"control-h", "^H", {8,0}}, /* backspace? */
- {"control-i", "^I", {9,0}}, /* tab */
- {"control-j", "^J", {10,0}},
- {"control-k", "^K", {11,0}},
- {"control-l", "^L", {12,0}},
- {"control-n", "^N", {14,0}},
- {"control-o", "^O", {15,0}},
- {"control-p", "^P", {16,0}},
- {"control-q", "^Q", {17,0}},
- {"control-r", "^R", {18,0}},
- {"control-s", "^S", {19,0}},
- {"control-t", "^T", {20,0}},
- {"control-u", "^U", {21,0}},
- {"control-v", "^V", {22,0}},
- {"control-w", "^W", {23,0}},
- {"control-x", "^X", {24,0}},
- {"control-y", "^Y", {25,0}},
- {"control-z", "^Z", {26,0}},
- {"alt-0", "%0", "\0330"},
- {"alt-1", "%1", "\0331"},
- {"alt-2", "%2", "\0332"},
- {"alt-3", "%3", "\0333"},
- {"alt-4", "%4", "\0334"},
- {"alt-5", "%5", "\0335"},
- {"alt-6", "%6", "\0336"},
- {"alt-7", "%7", "\0337"}, /* backspace? */
- {"alt-8", "%8", "\0338"},
- {"alt-9", "%9", "\0339"},
- {"alt-+", "%+", "\033+"},
- {"alt--", "%-", "\033-"},
- {"alt-/", "%/", "\033/"},
- {"alt-a", "%A", "\033a"},
- {"alt-b", "%B", "\033b"},
- {"alt-c", "%C", "\033c"},
- {"alt-d", "%D", "\033d"},
- {"alt-e", "%E", "\033e"},
- {"alt-f", "%F", "\033f"},
- {"alt-g", "%G", "\033g"},
- {"alt-h", "%H", "\033h"}, /* backspace? */
- {"alt-i", "%I", "\033i"},
- {"alt-j", "%J", "\033j"},
- {"alt-k", "%K", "\033k"},
- {"alt-l", "%L", "\033l"},
- {"alt-n", "%N", "\033m"},
- {"alt-n", "%N", "\033n"},
- {"alt-o", "%O", "\033o"},
- {"alt-p", "%P", "\033p"},
- {"alt-q", "%Q", "\033q"},
- {"alt-r", "%R", "\033r"},
- {"alt-s", "%S", "\033s"},
- {"alt-t", "%T", "\033t"},
- {"alt-u", "%U", "\033u"},
- {"alt-v", "%V", "\033v"},
- {"alt-w", "%W", "\033w"},
- {"alt-x", "%X", "\033x"},
- {"alt-y", "%Y", "\033y"},
- {"alt-z", "%Z", "\033z"},
- {"shift-tab", "shift-↹", {27, 9, 0}},
- /* Linux Console */
- {"home", "Home", "\033[1~"},
- {"end", "End", "\033[4~"},
- {"F1", "F1", "\033[[A"},
- {"F2", "F2", "\033[[B"},
- {"F3", "F3", "\033[[C"},
- {"F4", "F4", "\033[[D"},
- {"F5", "F5", "\033[[E"},
- {"F6", "F6", "\033[[F"},
- {"F7", "F7", "\033[[G"},
- {"F8", "F8", "\033[[H"},
- {"F9", "F9", "\033[[I"},
- {"F10", "F10", "\033[[J"},
- {"F11", "F11", "\033[[K"},
- {"F12", "F12", "\033[[L"},
- {"ok", "", "\033[0n"},
- {NULL, }
-};
-static struct termios orig_attr; /* in order to restore at exit */
-static int nc_is_raw = 0;
-static int atexit_registered = 0;
-static int mouse_mode = NC_MOUSE_NONE;
+CtxPixelFormatInfo *
+ctx_pixel_format_info (CtxPixelFormat format)
+{
+ if (!ctx_pixel_formats)
+ {
+ ctx_pixel_formats = ctx_pixel_formats_default;
-static void _nc_noraw (void)
+ }
+
+ for (unsigned int i = 0; ctx_pixel_formats[i].pixel_format; i++)
+ {
+ if (ctx_pixel_formats[i].pixel_format == format)
+ {
+ return &ctx_pixel_formats[i];
+ }
+ }
+ return NULL;
+}
+#else
+
+CtxPixelFormatInfo *
+ctx_pixel_format_info (CtxPixelFormat format)
{
- if (nc_is_raw && tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr) != -1)
- nc_is_raw = 0;
+ return NULL;
}
+#endif
void
-nc_at_exit (void)
+ctx_current_point (Ctx *ctx, float *x, float *y)
{
- printf (TERMINAL_MOUSE_OFF);
- printf (XTERM_ALTSCREEN_OFF);
- _nc_noraw();
- fprintf (stdout, "\e[?25h");
- //if (ctx_native_events)
- fprintf (stdout, "\e[?201l");
- fprintf (stdout, "\e[?1049l");
+ if (!ctx)
+ {
+ if (x) { *x = 0.0f; }
+ if (y) { *y = 0.0f; }
+ }
+#if CTX_RASTERIZER
+ if (ctx->renderer)
+ {
+ if (x) { *x = ( (CtxRasterizer *) (ctx->renderer) )->x; }
+ if (y) { *y = ( (CtxRasterizer *) (ctx->renderer) )->y; }
+ return;
+ }
+#endif
+ if (x) { *x = ctx->state.x; }
+ if (y) { *y = ctx->state.y; }
}
-static const char *mouse_get_event_int (Ctx *n, int *x, int *y)
+float ctx_x (Ctx *ctx)
{
- static int prev_state = 0;
- const char *ret = "mouse-motion";
- float relx, rely;
- signed char buf[3];
- read (n->mouse_fd, buf, 3);
- relx = buf[1];
- rely = -buf[2];
-
- n->mouse_x += relx * 0.1;
- n->mouse_y += rely * 0.1;
-
- if (n->mouse_x < 1) n->mouse_x = 1;
- if (n->mouse_y < 1) n->mouse_y = 1;
- if (n->mouse_x >= n->events.width) n->mouse_x = n->events.width;
- if (n->mouse_y >= n->events.height) n->mouse_y = n->events.height;
+ float x = 0, y = 0;
+ ctx_current_point (ctx, &x, &y);
+ return x;
+}
- if (x) *x = n->mouse_x;
- if (y) *y = n->mouse_y;
+float ctx_y (Ctx *ctx)
+{
+ float x = 0, y = 0;
+ ctx_current_point (ctx, &x, &y);
+ return y;
+}
- if ((prev_state & 1) != (buf[0] & 1))
+void
+ctx_process (Ctx *ctx, CtxEntry *entry)
+{
+#if CTX_CURRENT_PATH
+ switch (entry->code)
{
- if (buf[0] & 1) ret = "mouse-press";
+ case CTX_TEXT:
+ case CTX_STROKE_TEXT:
+ case CTX_BEGIN_PATH:
+ ctx->current_path.count = 0;
+ break;
+ case CTX_CLIP:
+ case CTX_FILL:
+ case CTX_STROKE:
+ // XXX unless preserve
+ ctx->current_path.count = 0;
+ break;
+ case CTX_CLOSE_PATH:
+ case CTX_LINE_TO:
+ case CTX_MOVE_TO:
+ case CTX_QUAD_TO:
+ case CTX_SMOOTH_TO:
+ case CTX_SMOOTHQ_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:
+ case CTX_REL_ARC_TO:
+ case CTX_RECTANGLE:
+ case CTX_ROUND_RECTANGLE:
+ ctx_drawlist_add_entry (&ctx->current_path, entry);
+ break;
+ default:
+ break;
}
- else if (buf[0] & 1)
- ret = "mouse-drag";
-
- if ((prev_state & 2) != (buf[0] & 2))
+#endif
+ if (ctx->renderer && ctx->renderer->process)
{
- if (buf[0] & 2) ret = "mouse2-press";
+ ctx->renderer->process (ctx->renderer, (CtxCommand *) entry);
}
- else if (buf[0] & 2)
- ret = "mouse2-drag";
-
- if ((prev_state & 4) != (buf[0] & 4))
+ else
{
- if (buf[0] & 4) ret = "mouse1-press";
+ /* these functions might alter the code and coordinates of
+ command that in the end gets added to the drawlist
+ */
+ ctx_interpret_style (&ctx->state, entry, ctx);
+ ctx_interpret_transforms (&ctx->state, entry, ctx);
+ ctx_interpret_pos (&ctx->state, entry, ctx);
+ ctx_drawlist_add_entry (&ctx->drawlist, entry);
}
- else if (buf[0] & 4)
- ret = "mouse1-drag";
+}
- prev_state = buf[0];
- return ret;
+
+int ctx_gradient_cache_valid = 0;
+
+void
+ctx_state_gradient_clear_stops (CtxState *state)
+{
+//#if CTX_GRADIENT_CACHE
+// ctx_gradient_cache_reset ();
+//#endif
+ ctx_gradient_cache_valid = 0;
+ state->gradient.n_stops = 0;
}
-static const char *mev_type = NULL;
-static int mev_x = 0;
-static int mev_y = 0;
-static int mev_q = 0;
+uint8_t ctx_gradient_cache_u8[CTX_GRADIENT_CACHE_ELEMENTS][4];
+uint8_t ctx_gradient_cache_u8_a[CTX_GRADIENT_CACHE_ELEMENTS][4];
-static const char *mouse_get_event (Ctx *n, int *x, int *y)
+/**** end of engine ****/
+
+CtxBuffer *ctx_buffer_new_bare (void)
{
- if (!mev_q)
- return NULL;
- *x = mev_x;
- *y = mev_y;
- mev_q = 0;
- return mev_type;
+ CtxBuffer *buffer = (CtxBuffer *) ctx_calloc (sizeof (CtxBuffer), 1);
+ return buffer;
}
-static int mouse_has_event (Ctx *n)
+void ctx_buffer_set_data (CtxBuffer *buffer,
+ void *data, int width, int height,
+ int stride,
+ CtxPixelFormat pixel_format,
+ void (*freefunc) (void *pixels, void *user_data),
+ void *user_data)
{
- struct timeval tv;
- int retval;
+ if (buffer->free_func)
+ { buffer->free_func (buffer->data, buffer->user_data); }
+ if (stride <= 0)
+ stride = ctx_pixel_format_get_stride (pixel_format, width);
+ buffer->data = data;
+ buffer->width = width;
+ buffer->height = height;
+ buffer->stride = stride;
+ buffer->format = ctx_pixel_format_info (pixel_format);
+ buffer->free_func = freefunc;
+ buffer->user_data = user_data;
+}
- if (mouse_mode == NC_MOUSE_NONE)
- return 0;
+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)
+{
+ CtxBuffer *buffer = ctx_buffer_new_bare ();
+ ctx_buffer_set_data (buffer, data, width, height, stride, pixel_format,
+ freefunc, user_data);
+ return buffer;
+}
- if (mev_q)
- return 1;
+void ctx_buffer_pixels_free (void *pixels, void *userdata)
+{
+ free (pixels);
+}
- if (n->mouse_fd == 0)
- return 0;
- return 0;
+CtxBuffer *ctx_buffer_new (int width, int height,
+ CtxPixelFormat pixel_format)
+{
+ //CtxPixelFormatInfo *info = ctx_pixel_format_info (pixel_format);
+ CtxBuffer *buffer = ctx_buffer_new_bare ();
+ int stride = ctx_pixel_format_get_stride (pixel_format, width);
+ uint8_t *pixels = (uint8_t*)ctx_calloc (stride, height + 1);
+ ctx_buffer_set_data (buffer, pixels, width, height, stride, pixel_format,
+ ctx_buffer_pixels_free, NULL);
+ return buffer;
+}
+
+void ctx_buffer_deinit (CtxBuffer *buffer)
+{
+ if (buffer->free_func)
+ buffer->free_func (buffer->data, buffer->user_data);
+ if (buffer->eid)
{
- fd_set rfds;
- FD_ZERO (&rfds);
- FD_SET(n->mouse_fd, &rfds);
- tv.tv_sec = 0; tv.tv_usec = 0;
- retval = select (n->mouse_fd+1, &rfds, NULL, NULL, &tv);
+ free (buffer->eid);
}
-
- if (retval != 0)
- {
- int nx = 0, ny = 0;
- const char *type = mouse_get_event_int (n, &nx, &ny);
-
- if ((mouse_mode < NC_MOUSE_DRAG && mev_type && !strcmp (mev_type, "drag")) ||
- (mouse_mode < NC_MOUSE_ALL && mev_type && !strcmp (mev_type, "motion")))
- {
- mev_q = 0;
- return mouse_has_event (n);
- }
-
- if ((mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse-motion")) ||
- (mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse1-drag")) ||
- (mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse2-drag")))
- {
- if (nx == mev_x && ny == mev_y)
- {
- mev_q = 0;
- return mouse_has_event (n);
- }
- }
- mev_x = nx;
- mev_y = ny;
- mev_type = type;
- mev_q = 1;
+ buffer->eid = NULL;
+ buffer->data = NULL;
+ buffer->free_func = NULL;
+ buffer->user_data = NULL;
+ if (buffer->color_managed)
+ {
+ if (buffer->color_managed != buffer)
+ {
+ ctx_buffer_free (buffer->color_managed);
}
- return retval != 0;
+ buffer->color_managed = NULL;
+ }
}
+void ctx_buffer_free (CtxBuffer *buffer)
+{
+ ctx_buffer_deinit (buffer);
+ free (buffer);
+}
-static int _nc_raw (void)
+static int
+ctx_texture_check_eid (Ctx *ctx, const char *eid, int *tw, int *th)
{
- struct termios raw;
- if (!isatty (STDIN_FILENO))
- return -1;
- if (!atexit_registered)
+ for (int i = 0; i < CTX_MAX_TEXTURES; i++)
+ {
+ if (ctx->texture[i].data &&
+ ctx->texture[i].eid &&
+ !strcmp (ctx->texture[i].eid, eid))
{
- atexit (nc_at_exit);
- atexit_registered = 1;
+ if (tw) *tw = ctx->texture[i].width;
+ if (th) *th = ctx->texture[i].height;
+ ctx->texture[i].frame = ctx->texture_cache->frame;
+ return i;
}
- if (tcgetattr (STDIN_FILENO, &orig_attr) == -1)
- return -1;
- raw = orig_attr; /* modify the original mode */
- 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 -1;
- nc_is_raw = 1;
- tcdrain(STDIN_FILENO);
- tcflush(STDIN_FILENO, 1);
- return 0;
+ }
+ return -1;
}
-static int match_keycode (const char *buf, int length, const NcKeyCode **ret)
+const char* ctx_texture_init (Ctx *ctx,
+ const char *eid,
+ int width,
+ int height,
+ int stride,
+ CtxPixelFormat format,
+ void *space,
+ uint8_t *pixels,
+ void (*freefunc) (void *pixels, void *user_data),
+ void *user_data)
{
- int i;
- int matches = 0;
-
- if (!strncmp (buf, "\033[M", MIN(length,3)))
+ int id = 0;
+ if (eid)
+ {
+ for (int i = 0; i < CTX_MAX_TEXTURES; i++)
{
- if (length >= 6)
- return 9001;
- return 2342;
- }
- for (i = 0; keycodes[i].nick; i++)
- if (!strncmp (buf, keycodes[i].sequence, length))
+ if (ctx->texture[i].data &&
+ ctx->texture[i].eid &&
+ !strcmp (ctx->texture[i].eid, eid))
{
- matches ++;
- if ((int)strlen (keycodes[i].sequence) == length && ret)
- {
- *ret = &keycodes[i];
- return 1;
- }
+ ctx->texture[i].frame = ctx->texture_cache->frame;
+ if (freefunc && user_data != (void*)23)
+ freefunc (pixels, user_data);
+ return ctx->texture[i].eid;
}
- if (matches != 1 && ret)
- *ret = NULL;
- return matches==1?2:matches;
+ if (ctx->texture[i].data == NULL
+ || (ctx->texture_cache->frame - ctx->texture[i].frame >= 2))
+ id = i;
+ }
+ } else
+ {
+ for (int i = 0; i < CTX_MAX_TEXTURES; i++)
+ {
+ if (ctx->texture[i].data == NULL
+ || (ctx->texture_cache->frame - ctx->texture[i].frame > 2))
+ id = i;
+ }
+ }
+ //int bpp = ctx_pixel_format_bits_per_pixel (format);
+ ctx_buffer_deinit (&ctx->texture[id]);
+
+ if (stride<=0)
+ {
+ stride = ctx_pixel_format_get_stride ((CtxPixelFormat)format, width);
+ }
+
+ if (freefunc == ctx_buffer_pixels_free && user_data == (void*)23)
+ {
+ uint8_t *tmp = (uint8_t*)malloc (height * stride);
+ memcpy (tmp, pixels, height * stride);
+ pixels = tmp;
+ }
+
+ ctx_buffer_set_data (&ctx->texture[id],
+ pixels, width, height,
+ stride, format,
+ freefunc, user_data);
+#if CTX_ENABLE_CM
+ ctx->texture[id].space = space;
+#endif
+ ctx->texture[id].frame = ctx->texture_cache->frame;
+ if (eid)
+ {
+ /* we got an eid, this is the fast path */
+ ctx->texture[id].eid = strdup (eid);
+ }
+ else
+ {
+ uint8_t hash[20];
+ char ascii[41];
+
+ CtxSHA1 *sha1 = ctx_sha1_new ();
+ ctx_sha1_process (sha1, pixels, stride * height);
+ ctx_sha1_done (sha1, hash);
+ ctx_sha1_free (sha1);
+ const char *hex="0123456789abcdef";
+ for (int i = 0; i < 20; i ++)
+ {
+ ascii[i*2]=hex[hash[i]/16];
+ ascii[i*2+1]=hex[hash[i]%16];
+ }
+ ascii[40]=0;
+ ctx->texture[id].eid = strdup (ascii);
+ }
+ return ctx->texture[id].eid;
}
-static void nc_resize_term (int dummy)
+void
+_ctx_texture_prepare_color_management (CtxRasterizer *rasterizer,
+ CtxBuffer *buffer)
{
- size_changed = 1;
+ switch (buffer->format->pixel_format)
+ {
+#ifndef NO_BABL
+#if CTX_BABL
+ case CTX_FORMAT_RGBA8:
+ {
+ buffer->color_managed = ctx_buffer_new (buffer->width, buffer->height,
+ CTX_FORMAT_RGBA8);
+ babl_process (
+ babl_fish (babl_format_with_space ("R'G'B'A u8", buffer->space),
+ babl_format_with_space ("R'G'B'A u8", rasterizer->state->gstate.device_space)),
+ buffer->data, buffer->color_managed->data,
+ buffer->width * buffer->height
+ );
+ }
+ break;
+ case CTX_FORMAT_RGB8:
+ {
+ buffer->color_managed = ctx_buffer_new (buffer->width, buffer->height,
+ CTX_FORMAT_RGB8);
+ babl_process (
+ babl_fish (babl_format_with_space ("R'G'B' u8", buffer->space),
+ babl_format_with_space ("R'G'B' u8", rasterizer->state->gstate.device_space)),
+ buffer->data, buffer->color_managed->data,
+ buffer->width * buffer->height
+ );
+ }
+ break;
+#endif
+#endif
+ default:
+ buffer->color_managed = buffer;
+ }
}
-int ctx_has_event (Ctx *n, int delay_ms)
-{
- struct timeval tv;
- int retval;
- fd_set rfds;
- if (size_changed)
- return 1;
- FD_ZERO (&rfds);
- FD_SET (STDIN_FILENO, &rfds);
- tv.tv_sec = 0; tv.tv_usec = delay_ms * 1000;
- retval = select (1, &rfds, NULL, NULL, &tv);
- if (size_changed)
- return 1;
- return retval == 1 && retval != -1;
-}
-const char *ctx_nct_get_event (Ctx *n, int timeoutms, int *x, int *y)
+int ctx_utf8_len (const unsigned char first_byte)
{
- unsigned char buf[20];
- int length;
-
+ if ( (first_byte & 0x80) == 0)
+ { return 1; } /* ASCII */
+ else if ( (first_byte & 0xE0) == 0xC0)
+ { return 2; }
+ else if ( (first_byte & 0xF0) == 0xE0)
+ { return 3; }
+ else if ( (first_byte & 0xF8) == 0xF0)
+ { return 4; }
+ return 1;
+}
- if (x) *x = -1;
- if (y) *y = -1;
- if (!signal_installed)
+const char *ctx_utf8_skip (const char *s, int utf8_length)
+{
+ int count;
+ if (!s)
+ { return NULL; }
+ for (count = 0; *s; s++)
{
- _nc_raw ();
- signal_installed = 1;
- signal (SIGWINCH, nc_resize_term);
+ if ( (*s & 0xC0) != 0x80)
+ { count++; }
+ if (count == utf8_length + 1)
+ { return s; }
}
- if (mouse_mode) // XXX too often to do it all the time!
- printf(mouse_modes[mouse_mode]);
-
- {
- int elapsed = 0;
- int got_event = 0;
-
- do {
- if (size_changed)
- {
- size_changed = 0;
- return "size-changed";
- }
- got_event = mouse_has_event (n);
- if (!got_event)
- got_event = ctx_has_event (n, MIN(DELAY_MS, timeoutms-elapsed));
- if (size_changed)
- {
- size_changed = 0;
- return "size-changed";
- }
- /* only do this if the client has asked for idle events,
- * and perhaps programmed the ms timer?
- */
- elapsed += MIN(DELAY_MS, timeoutms-elapsed);
- if (!got_event && timeoutms && elapsed >= timeoutms)
- return "idle";
- } while (!got_event);
- }
+ return s;
+}
- if (mouse_has_event (n))
- return mouse_get_event (n, x, y);
+// XXX : unused
+int ctx_utf8_strlen (const char *s)
+{
+ int count;
+ if (!s)
+ { return 0; }
+ for (count = 0; *s; s++)
+ if ( (*s & 0xC0) != 0x80)
+ { count++; }
+ return count;
+}
- for (length = 0; length < 10; length ++)
- if (read (STDIN_FILENO, &buf[length], 1) != -1)
- {
- const NcKeyCode *match = NULL;
+int
+ctx_unichar_to_utf8 (uint32_t ch,
+ uint8_t *dest)
+{
+ /* http://www.cprogramming.com/tutorial/utf8.c */
+ /* Basic UTF-8 manipulation routines
+ by Jeff Bezanson
+ placed in the public domain Fall 2005 ... */
+ if (ch < 0x80)
+ {
+ dest[0] = (char) ch;
+ return 1;
+ }
+ if (ch < 0x800)
+ {
+ dest[0] = (ch>>6) | 0xC0;
+ dest[1] = (ch & 0x3F) | 0x80;
+ return 2;
+ }
+ if (ch < 0x10000)
+ {
+ dest[0] = (ch>>12) | 0xE0;
+ dest[1] = ( (ch>>6) & 0x3F) | 0x80;
+ dest[2] = (ch & 0x3F) | 0x80;
+ return 3;
+ }
+ if (ch < 0x110000)
+ {
+ dest[0] = (ch>>18) | 0xF0;
+ dest[1] = ( (ch>>12) & 0x3F) | 0x80;
+ dest[2] = ( (ch>>6) & 0x3F) | 0x80;
+ dest[3] = (ch & 0x3F) | 0x80;
+ return 4;
+ }
+ return 0;
+}
- /* special case ESC, so that we can use it alone in keybindings */
- if (length == 0 && buf[0] == 27)
- {
- struct timeval tv;
- fd_set rfds;
- FD_ZERO (&rfds);
- FD_SET (STDIN_FILENO, &rfds);
- tv.tv_sec = 0;
- tv.tv_usec = 1000 * DELAY_MS;
- if (select (1, &rfds, NULL, NULL, &tv) == 0)
- return "esc";
- }
-
- switch (match_keycode ((const char*)buf, length + 1, &match))
- {
- case 1: /* unique match */
- if (!match)
- return NULL;
- if (!strcmp(match->nick, "ok"))
- {
- ctx_frame_ack = 1;
- return NULL;
- }
- 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;
- switch (buf[3])
- {
- /* XXX : todo reduce this to less string constants */
- case 32: return "mouse-press";
- case 33: return "mouse1-press";
- case 34: return "mouse2-press";
- case 40: return "alt-mouse-press";
- case 41: return "alt-mouse1-press";
- case 42: return "alt-mouse2-press";
- case 48: return "control-mouse-press";
- case 49: return "control-mouse1-press";
- case 50: return "control-mouse2-press";
- case 56: return "alt-control-mouse-press";
- case 57: return "alt-control-mouse1-press";
- case 58: return "alt-control-mouse2-press";
- case 64: return "mouse-drag";
- case 65: return "mouse1-drag";
- case 66: return "mouse2-drag";
- case 71: return "mouse-motion"; /* shift+motion */
- case 72: return "alt-mouse-drag";
- case 73: return "alt-mouse1-drag";
- case 74: return "alt-mouse2-drag";
- case 75: return "mouse-motion"; /* alt+motion */
- case 80: return "control-mouse-drag";
- case 81: return "control-mouse1-drag";
- case 82: return "control-mouse2-drag";
- case 83: return "mouse-motion"; /* ctrl+motion */
- case 91: return "mouse-motion"; /* ctrl+alt+motion */
- case 95: return "mouse-motion"; /* ctrl+alt+shift+motion */
- case 96: return "scroll-up";
- case 97: return "scroll-down";
- case 100: return "shift-scroll-up";
- case 101: return "shift-scroll-down";
- case 104: return "alt-scroll-up";
- case 105: return "alt-scroll-down";
- case 112: return "control-scroll-up";
- case 113: return "control-scroll-down";
- case 116: return "control-shift-scroll-up";
- case 117: return "control-shift-scroll-down";
- case 35: /* (or release) */
- case 51: /* (or ctrl-release) */
- case 43: /* (or alt-release) */
- case 67: return "mouse-motion";
- /* have a separate mouse-drag ? */
- default: {
- static char rbuf[100];
- sprintf (rbuf, "mouse (unhandled state: %i)", buf[3]);
- return rbuf;
- }
- }
- case 0: /* no matches, bail*/
- {
- static char ret[256];
- if (length == 0 && ctx_utf8_len (buf[0])>1) /* single unicode
- char */
- {
- read (STDIN_FILENO, &buf[length+1], ctx_utf8_len(buf[0])-1);
- buf[ctx_utf8_len(buf[0])]=0;
- strcpy (ret, (const char*)buf);
- return ret;
- }
- if (length == 0) /* ascii */
- {
- buf[1]=0;
- strcpy (ret, (const char*)buf);
- return ret;
- }
- sprintf (ret, "unhandled %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c'",
- length>=0? buf[0]: 0, length>=0? buf[0]>31?buf[0]:'?': ' ',
- length>=1? buf[1]: 0, length>=1? buf[1]>31?buf[1]:'?': ' ',
- length>=2? buf[2]: 0, length>=2? buf[2]>31?buf[2]:'?': ' ',
- length>=3? buf[3]: 0, length>=3? buf[3]>31?buf[3]:'?': ' ',
- length>=4? buf[4]: 0, length>=4? buf[4]>31?buf[4]:'?': ' ',
- length>=5? buf[5]: 0, length>=5? buf[5]>31?buf[5]:'?': ' ',
- length>=6? buf[6]: 0, length>=6? buf[6]>31?buf[6]:'?': ' ');
- return ret;
- }
- return NULL;
- default: /* continue */
- break;
- }
- }
- else
- return "key read eek";
- return "fail";
-}
-
-int ctx_nct_consume_events (Ctx *ctx)
+uint32_t
+ctx_utf8_to_unichar (const char *input)
{
- int ix, iy;
- CtxCtx *ctxctx = (CtxCtx*)ctx->renderer;
- const char *event = NULL;
+ const uint8_t *utf8 = (const uint8_t *) input;
+ uint8_t c = utf8[0];
+ if ( (c & 0x80) == 0)
+ { return c; }
+ else if ( (c & 0xE0) == 0xC0)
+ return ( (utf8[0] & 0x1F) << 6) |
+ (utf8[1] & 0x3F);
+ else if ( (c & 0xF0) == 0xE0)
+ return ( (utf8[0] & 0xF) << 12) |
+ ( (utf8[1] & 0x3F) << 6) |
+ (utf8[2] & 0x3F);
+ else if ( (c & 0xF8) == 0xF0)
+ return ( (utf8[0] & 0x7) << 18) |
+ ( (utf8[1] & 0x3F) << 12) |
+ ( (utf8[2] & 0x3F) << 6) |
+ (utf8[3] & 0x3F);
+ else if ( (c & 0xFC) == 0xF8)
+ return ( (utf8[0] & 0x3) << 24) |
+ ( (utf8[1] & 0x3F) << 18) |
+ ( (utf8[2] & 0x3F) << 12) |
+ ( (utf8[3] & 0x3F) << 6) |
+ (utf8[4] & 0x3F);
+ else if ( (c & 0xFE) == 0xFC)
+ return ( (utf8[0] & 0x1) << 30) |
+ ( (utf8[1] & 0x3F) << 24) |
+ ( (utf8[2] & 0x3F) << 18) |
+ ( (utf8[3] & 0x3F) << 12) |
+ ( (utf8[4] & 0x3F) << 6) |
+ (utf8[5] & 0x3F);
+ return 0;
+}
- {
- float x, y;
- event = ctx_nct_get_event (ctx, 50, &ix, &iy);
+#if CTX_RASTERIZER
- x = (ix - 1.0 + 0.5) / ctxctx->cols * ctx->events.width;
- y = (iy - 1.0) / ctxctx->rows * ctx->events.height;
- if (!strcmp (event, "mouse-press"))
- {
- ctx_pointer_press (ctx, x, y, 0, 0);
- ctxctx->was_down = 1;
- } else if (!strcmp (event, "mouse-release"))
- {
- ctx_pointer_release (ctx, x, y, 0, 0);
- ctxctx->was_down = 0;
- } else if (!strcmp (event, "mouse-motion"))
- {
- //nct_set_cursor_pos (backend->term, ix, iy);
- //nct_flush (backend->term);
- if (ctxctx->was_down)
- {
- ctx_pointer_release (ctx, x, y, 0, 0);
- ctxctx->was_down = 0;
- }
- ctx_pointer_motion (ctx, x, y, 0, 0);
- } else if (!strcmp (event, "mouse-drag"))
- {
- ctx_pointer_motion (ctx, x, y, 0, 0);
- } else if (!strcmp (event, "size-changed"))
- {
-#if 0
- int width = nct_sys_terminal_width ();
- int height = nct_sys_terminal_height ();
- 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);
- mrg_set_size (mrg, width, height);
- mrg_queue_draw (mrg, NULL);
-#endif
- }
- else
- {
- if (!strcmp (event, "esc"))
- ctx_key_press (ctx, 0, "escape", 0);
- else if (!strcmp (event, "space"))
- ctx_key_press (ctx, 0, "space", 0);
- else if (!strcmp (event, "enter"))
- ctx_key_press (ctx, 0, "\n", 0);
- else if (!strcmp (event, "return"))
- ctx_key_press (ctx, 0, "\n", 0);
- else
- ctx_key_press (ctx, 0, event, 0);
- }
- }
+static int
+ctx_rect_intersect (const CtxIntRectangle *a, const CtxIntRectangle *b)
+{
+ if (a->x >= b->x + b->width ||
+ b->x >= a->x + a->width ||
+ a->y >= b->y + b->height ||
+ b->y >= a->y + a->height) return 0;
return 1;
}
-const char *ctx_native_get_event (Ctx *n, int timeoutms)
+static void
+_ctx_add_hash (CtxHasher *hasher, CtxIntRectangle *shape_rect, char *hash)
{
- static unsigned char buf[256];
- int length;
-
- if (!signal_installed)
- {
- _nc_raw ();
- signal_installed = 1;
- signal (SIGWINCH, nc_resize_term);
+ CtxIntRectangle rect = {0,0, hasher->rasterizer.blit_width/hasher->cols,
+ hasher->rasterizer.blit_height/hasher->rows};
+ int hno = 0;
+ for (int row = 0; row < hasher->rows; row++)
+ for (int col = 0; col < hasher->cols; col++, hno++)
+ {
+ rect.x = col * rect.width;
+ rect.y = row * rect.height;
+ if (ctx_rect_intersect (shape_rect, &rect))
+ {
+ int temp = hasher->hashes[(row * hasher->cols + col) *20 + 0];
+ for (int i = 0; i <19;i++)
+ hasher->hashes[(row * hasher->cols + col) *20 + i] =
+ hasher->hashes[(row * hasher->cols + col) *20 + i+1]^
+ hash[i];
+ hasher->hashes[(row * hasher->cols + col) *20 + 19] =
+ temp ^ hash[19];
+ }
}
-//if (mouse_mode) // XXX too often to do it all the time!
-// printf(mouse_modes[mouse_mode]);
+}
- int got_event = 0;
- {
- int elapsed = 0;
- do {
- if (size_changed)
- {
- size_changed = 0;
- return "size-changed";
- }
- got_event = ctx_has_event (n, MIN(DELAY_MS, timeoutms-elapsed));
- if (size_changed)
- {
- size_changed = 0;
- return "size-changed";
- }
- /* only do this if the client has asked for idle events,
- * and perhaps programmed the ms timer?
- */
- elapsed += MIN(DELAY_MS, timeoutms-elapsed);
- if (!got_event && timeoutms && elapsed >= timeoutms)
- {
- return "idle";
- }
- } while (!got_event);
- }
-
- for (length = 0; got_event && length < 200; length ++)
- {
- if (read (STDIN_FILENO, &buf[length], 1) != -1)
- {
- buf[length+1] = 0;
- if (!strcmp ((char*)buf, "\e[0n"))
- {
- ctx_frame_ack = 1;
- return NULL;
- }
- else if (buf[length]=='\n')
- {
- buf[length]=0;
- return (const char*)buf;
- }
- }
- got_event = ctx_has_event (n, 5);
- }
- return NULL;
-}
-
-const char *ctx_key_get_label (Ctx *n, const char *nick)
+static void
+ctx_hasher_process (void *user_data, CtxCommand *command)
{
- int j;
- int found = -1;
- for (j = 0; keycodes[j].nick; j++)
- if (found == -1 && !strcmp (keycodes[j].nick, nick))
- return keycodes[j].label;
- return NULL;
-}
+ CtxEntry *entry = &command->entry;
+ CtxRasterizer *rasterizer = (CtxRasterizer *) user_data;
+ CtxHasher *hasher = (CtxHasher*) user_data;
+ CtxState *state = rasterizer->state;
+ CtxCommand *c = (CtxCommand *) entry;
+ int aa = rasterizer->aa;
-void _ctx_mouse (Ctx *term, int mode)
-{
- //if (term->is_st && mode > 1)
- // mode = 1;
- if (mode != mouse_mode)
- {
- printf (mouse_modes[mode]);
- fflush (stdout);
- }
- mouse_mode = mode;
-}
+ ctx_interpret_pos_bare (rasterizer->state, entry, NULL);
+ ctx_interpret_style (rasterizer->state, entry, NULL);
+ switch (c->code)
+ {
+ case CTX_TEXT:
+ {
+ CtxSHA1 sha1;
+ memcpy (&sha1, &hasher->sha1_fill, sizeof (CtxSHA1));
+ char ctx_sha1_hash[20];
+ float width = ctx_text_width (rasterizer->ctx, ctx_arg_string());
-#endif
-#include <sys/time.h>
+ float height = ctx_get_font_size (rasterizer->ctx);
+ CtxIntRectangle shape_rect;
+
+ shape_rect.x=rasterizer->x;
+ shape_rect.y=rasterizer->y - height,
+ shape_rect.width = width;
+ shape_rect.height = height * 2;
+ switch ((int)ctx_state_get (rasterizer->state, CTX_text_align))
+ {
+ case CTX_TEXT_ALIGN_LEFT:
+ case CTX_TEXT_ALIGN_START:
+ break;
+ case CTX_TEXT_ALIGN_END:
+ case CTX_TEXT_ALIGN_RIGHT:
+ shape_rect.x -= shape_rect.width;
+ break;
+ case CTX_TEXT_ALIGN_CENTER:
+ shape_rect.x -= shape_rect.width/2;
+ break;
+ // 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
+ ctx_sha1_process(&sha1, (const unsigned char*)ctx_arg_string(), strlen (ctx_arg_string()));
+#if 0
+ ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof
(rasterizer->state->gstate.transform));
+ ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
+#endif
+ ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxIntRectangle));
+ ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
+ _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
-#define usecs(time) ((uint64_t)(time.tv_sec - start_time.tv_sec) * 1000000 + time. tv_usec)
+ ctx_rasterizer_rel_move_to (rasterizer, width, 0);
+ }
+ ctx_rasterizer_reset (rasterizer);
+ break;
+ case CTX_STROKE_TEXT:
+ {
+ CtxSHA1 sha1;
+ memcpy (&sha1, &hasher->sha1_stroke, sizeof (CtxSHA1));
+ char ctx_sha1_hash[20];
+ float width = ctx_text_width (rasterizer->ctx, ctx_arg_string());
+ float height = ctx_get_font_size (rasterizer->ctx);
-#if CTX_EVENTS
-static struct timeval start_time;
+ CtxIntRectangle shape_rect = {
+ rasterizer->x, rasterizer->y - height,
+ width, height * 2
+ };
-static void
-_ctx_init_ticks (void)
-{
- static int done = 0;
- if (done)
- return;
- done = 1;
- gettimeofday (&start_time, NULL);
-}
+#if 0
+ uint32_t color;
+ ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_stroke.color,
(uint8_t*)(&color));
+#endif
+ ctx_sha1_process(&sha1, (unsigned char*)ctx_arg_string(), strlen (ctx_arg_string()));
+#if 0
+ ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof
(rasterizer->state->gstate.transform));
+ ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
+#endif
+ ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxIntRectangle));
+ ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
+ _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
-static inline unsigned long
-_ctx_ticks (void)
-{
- struct timeval measure_time;
- gettimeofday (&measure_time, NULL);
- return usecs (measure_time) - usecs (start_time);
-}
+ ctx_rasterizer_rel_move_to (rasterizer, width, 0);
+ }
+ ctx_rasterizer_reset (rasterizer);
+ break;
+ case CTX_GLYPH:
+ {
+ CtxSHA1 sha1;
+ memcpy (&sha1, &hasher->sha1_fill, sizeof (CtxSHA1));
-unsigned long
-ctx_ticks (void)
-{
- _ctx_init_ticks ();
- return _ctx_ticks ();
-}
+ char ctx_sha1_hash[20];
+ uint8_t string[8];
+ string[ctx_unichar_to_utf8 (c->u32.a0, string)]=0;
+ float width = ctx_text_width (rasterizer->ctx, (char*)string);
+ float height = ctx_get_font_size (rasterizer->ctx);
-uint32_t ctx_ms (Ctx *ctx)
-{
- return _ctx_ticks () / 1000;
-}
+ float tx = rasterizer->x;
+ float ty = rasterizer->y;
+ float tw = width;
+ float th = height * 2;
+ _ctx_user_to_device (rasterizer->state, &tx, &ty);
+ _ctx_user_to_device_distance (rasterizer->state, &tw, &th);
+ CtxIntRectangle shape_rect = {tx,ty-th/2,tw,th};
-typedef enum _CtxFlags CtxFlags;
-enum _CtxFlags {
- CTX_FLAG_DIRECT = (1<<0),
-};
+#if 0
+ uint32_t color;
+ ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color,
(uint8_t*)(&color));
+#endif
+ ctx_sha1_process(&sha1, string, strlen ((const char*)string));
+#if 0
+ ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof
(rasterizer->state->gstate.transform));
+ ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
+#endif
+ ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxIntRectangle));
+ ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
+ _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
+ ctx_rasterizer_rel_move_to (rasterizer, width, 0);
+ ctx_rasterizer_reset (rasterizer);
+ }
+ break;
-int _ctx_max_threads = 1;
-int _ctx_enable_hash_cache = 1;
+ case CTX_FILL:
+ {
+ CtxSHA1 sha1;
+ memcpy (&sha1, &hasher->sha1_fill, sizeof (CtxSHA1));
+ char ctx_sha1_hash[20];
-void
-ctx_init (int *argc, char ***argv)
-{
-#if 0
- if (!getenv ("CTX_VERSION"))
- {
- int i;
- char *new_argv[*argc+3];
- new_argv[0] = "ctx";
- for (i = 0; i < *argc; i++)
- {
- new_argv[i+1] = *argv[i];
- }
- new_argv[i+1] = NULL;
- execvp (new_argv[0], new_argv);
- // if this fails .. we continue normal startup
- // and end up in self-hosted braille
- }
-#endif
-}
+ /* we eant this hasher to be as good as possible internally,
+ * since it is also used in the small shapes rasterization
+ * cache
+ */
+ uint64_t hash = ctx_rasterizer_poly_to_hash (rasterizer); // + hasher->salt;
+ CtxIntRectangle shape_rect = {
+ rasterizer->col_min / CTX_SUBDIV,
+ rasterizer->scan_min / aa,
+ (rasterizer->col_max - rasterizer->col_min + 1) / CTX_SUBDIV,
+ (rasterizer->scan_max - rasterizer->scan_min + 1) / aa
+ };
-int ctx_count (Ctx *ctx)
-{
- return ctx->drawlist.count;
-}
+ hash ^= (rasterizer->state->gstate.fill_rule * 23);
-Ctx *ctx_new_ui (int width, int height)
-{
- if (getenv ("CTX_THREADS"))
- {
- int val = atoi (getenv ("CTX_THREADS"));
- _ctx_max_threads = val;
- }
- else
- {
- _ctx_max_threads = 2;
-#ifdef _SC_NPROCESSORS_ONLN
- _ctx_max_threads = sysconf (_SC_NPROCESSORS_ONLN) / 2;
-#endif
- }
+ ctx_sha1_process(&sha1, (unsigned char*)&hash, 8);
- if (_ctx_max_threads < 1) _ctx_max_threads = 1;
- if (_ctx_max_threads > CTX_MAX_THREADS) _ctx_max_threads = CTX_MAX_THREADS;
+ {
+ int is = rasterizer->state->gstate.image_smoothing;
+ ctx_sha1_process(&sha1, (uint8_t*)&is, sizeof(int));
+ }
- //fprintf (stderr, "ctx using %i threads\n", _ctx_max_threads);
- const char *backend = getenv ("CTX_BACKEND");
+ ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
+ _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
- if (backend && !strcmp (backend, "auto"))
- backend = NULL;
- if (backend && !strcmp (backend, "list"))
- {
- fprintf (stderr, "possible values for CTX_BACKEND:\n");
- fprintf (stderr, " ctx");
-#if CTX_SDL
- fprintf (stderr, " SDL");
-#endif
-#if CTX_FB
- fprintf (stderr, " fb");
- fprintf (stderr, " drm");
-#endif
- fprintf (stderr, " braille");
- fprintf (stderr, "\n");
- exit (-1);
- }
+ if (!rasterizer->preserve)
+ ctx_rasterizer_reset (rasterizer);
+ rasterizer->preserve = 0;
+ }
+ break;
+ case CTX_STROKE:
+ {
+ CtxSHA1 sha1;
+ memcpy (&sha1, &hasher->sha1_stroke, sizeof (CtxSHA1));
+ char ctx_sha1_hash[20];
+ uint64_t hash = ctx_rasterizer_poly_to_hash (rasterizer);
+ CtxIntRectangle shape_rect = {
+ rasterizer->col_min / CTX_SUBDIV - rasterizer->state->gstate.line_width,
+ rasterizer->scan_min / aa - rasterizer->state->gstate.line_width,
+ (rasterizer->col_max - rasterizer->col_min + 1) / CTX_SUBDIV +
rasterizer->state->gstate.line_width,
+ (rasterizer->scan_max - rasterizer->scan_min + 1) / aa + rasterizer->state->gstate.line_width
+ };
- Ctx *ret = NULL;
- /* FIXME: to a terminal query instead - to avoid relying on
- * environment variables - thus making it work reliably over
- * ssh without configuration.
- */
- if (getenv ("CTX_VERSION"))
- {
- if (!backend || !strcmp (backend, "ctx"))
- {
- // full blown ctx protocol - in terminal or standalone
- ret = ctx_new_ctx (width, height);
- }
- }
+ 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;
-#if CTX_SDL
- if (!ret && getenv ("DISPLAY"))
- {
- if ((backend==NULL) || (!strcmp (backend, "SDL")))
- ret = ctx_new_sdl (width, height);
- }
-#endif
+ hash ^= (int)(rasterizer->state->gstate.line_width * 110);
+ hash ^= (rasterizer->state->gstate.line_cap * 23);
+ hash ^= (rasterizer->state->gstate.source_stroke.type * 117);
-#if CTX_FB
- if (!ret && !getenv ("DISPLAY"))
- {
- if ((backend==NULL) || (!strcmp (backend, "drm")))
- ret = ctx_new_fb (width, height, 1);
+ ctx_sha1_process(&sha1, (unsigned char*)&hash, 8);
- if (!ret)
- {
- if ((backend==NULL) || (!strcmp (backend, "fb")))
- ret = ctx_new_fb (width, height, 0);
- }
- }
-#endif
+ uint32_t color;
+ ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_stroke.color,
(uint8_t*)(&color));
-#if CTX_RASTERIZER
- // braille in terminal
- if (!ret)
- {
- if ((backend==NULL) || (!strcmp (backend, "braille")))
- ret = ctx_new_braille (width, height);
- }
-#endif
- if (!ret)
- {
- fprintf (stderr, "no interactive ctx backend\n");
- exit (2);
- }
- ctx_get_event (ret); // enables events
- return ret;
-}
+ ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
-#endif
-void _ctx_resized (Ctx *ctx, int width, int height, long time);
+ ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
+ _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
+ }
+ if (!rasterizer->preserve)
+ ctx_rasterizer_reset (rasterizer);
+ rasterizer->preserve = 0;
+ break;
+ /* the above cases are the painting cases and
+ * the only ones differing from the rasterizer's process switch
+ */
-void ctx_set_size (Ctx *ctx, int width, int height)
-{
-#if CTX_EVENTS
- if (ctx->events.width != width || ctx->events.height != height)
- {
- ctx->events.width = width;
- ctx->events.height = height;
- _ctx_resized (ctx, width, height, 0);
- }
+ case CTX_LINE_TO:
+ ctx_rasterizer_line_to (rasterizer, c->c.x0, c->c.y0);
+ break;
+ case CTX_REL_LINE_TO:
+ ctx_rasterizer_rel_line_to (rasterizer, c->c.x0, c->c.y0);
+ break;
+ case CTX_MOVE_TO:
+ ctx_rasterizer_move_to (rasterizer, c->c.x0, c->c.y0);
+ break;
+ case CTX_REL_MOVE_TO:
+ ctx_rasterizer_rel_move_to (rasterizer, c->c.x0, c->c.y0);
+ break;
+ case CTX_CURVE_TO:
+ ctx_rasterizer_curve_to (rasterizer, c->c.x0, c->c.y0,
+ c->c.x1, c->c.y1,
+ c->c.x2, c->c.y2);
+ break;
+ case CTX_REL_CURVE_TO:
+ ctx_rasterizer_rel_curve_to (rasterizer, c->c.x0, c->c.y0,
+ c->c.x1, c->c.y1,
+ c->c.x2, c->c.y2);
+ break;
+ case CTX_QUAD_TO:
+ ctx_rasterizer_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
+ break;
+ case CTX_REL_QUAD_TO:
+ 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);
+ break;
+ case CTX_RECTANGLE:
+ ctx_rasterizer_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
+ c->rectangle.width, c->rectangle.height);
+ break;
+ case CTX_ROUND_RECTANGLE:
+ ctx_rasterizer_round_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
+ c->rectangle.width, c->rectangle.height,
+ c->rectangle.radius);
+ break;
+ case CTX_SET_PIXEL:
+ ctx_rasterizer_set_pixel (rasterizer, c->set_pixel.x, c->set_pixel.y,
+ c->set_pixel.rgba[0],
+ c->set_pixel.rgba[1],
+ c->set_pixel.rgba[2],
+ c->set_pixel.rgba[3]);
+ break;
+ case CTX_PRESERVE:
+ rasterizer->preserve = 1;
+ break;
+ case CTX_ROTATE:
+ case CTX_SCALE:
+ case CTX_TRANSLATE:
+ case CTX_SAVE:
+ case CTX_RESTORE:
+ rasterizer->uses_transforms = 1;
+ ctx_interpret_transforms (rasterizer->state, entry, NULL);
+
+
+ break;
+ case CTX_FONT:
+ ctx_rasterizer_set_font (rasterizer, ctx_arg_string() );
+ break;
+ case CTX_BEGIN_PATH:
+ ctx_rasterizer_reset (rasterizer);
+ break;
+ case CTX_CLIP:
+ // should perhaps modify a global state to include
+ // in hash?
+ ctx_rasterizer_clip (rasterizer);
+ break;
+ case CTX_CLOSE_PATH:
+ ctx_rasterizer_finish_shape (rasterizer);
+ break;
+ case CTX_DEFINE_TEXTURE:
+ {
+ ctx_sha1_init (&hasher->sha1_fill);
+ ctx_sha1_process (&hasher->sha1_fill, (uint8_t*)c->define_texture.eid, strlen
(c->define_texture.eid));
+ ctx_sha1_process(&hasher->sha1_fill, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof
(rasterizer->state->gstate.transform));
+
+ rasterizer->comp_op = NULL; // why?
+ }
+ break;
+ case CTX_TEXTURE:
+ ctx_sha1_init (&hasher->sha1_fill);
+ ctx_sha1_process (&hasher->sha1_fill, (uint8_t*)c->texture.eid, strlen (c->texture.eid));
+ ctx_sha1_process (&hasher->sha1_fill, (uint8_t*)(&rasterizer->state->gstate.transform), sizeof
(rasterizer->state->gstate.transform));
+ rasterizer->comp_op = NULL; // why?
+ break;
+ case CTX_COLOR:
+ {
+ uint32_t color;
+ if (((int)(ctx_arg_float(0))&512))
+ {
+ ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_stroke.color,
(uint8_t*)(&color));
+ ctx_sha1_init (&hasher->sha1_stroke);
+ ctx_sha1_process(&hasher->sha1_stroke, (unsigned char*)&color, 4);
+ }
+ else
+ {
+ ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color,
(uint8_t*)(&color));
+ ctx_sha1_init (&hasher->sha1_fill);
+ ctx_sha1_process(&hasher->sha1_fill, (unsigned char*)&color, 4);
+ }
+ }
+ break;
+ case CTX_LINEAR_GRADIENT:
+ ctx_sha1_init (&hasher->sha1_fill);
+ ctx_sha1_process(&hasher->sha1_fill,
+ (uint8_t*)c, sizeof (c->linear_gradient));
+ ctx_sha1_process (&hasher->sha1_fill, (unsigned char*)(&rasterizer->state->gstate.transform),
sizeof (rasterizer->state->gstate.transform));
+ break;
+ case CTX_RADIAL_GRADIENT:
+ ctx_sha1_init (&hasher->sha1_fill);
+ ctx_sha1_process(&hasher->sha1_fill,
+ (uint8_t*)c, sizeof (c->radial_gradient));
+ ctx_sha1_process (&hasher->sha1_fill, (unsigned char*)(&rasterizer->state->gstate.transform),
sizeof (rasterizer->state->gstate.transform));
+ //ctx_state_gradient_clear_stops (rasterizer->state);
+ break;
+#if CTX_GRADIENTS
+ case CTX_GRADIENT_STOP:
+ {
+ float rgba[4]= {ctx_u8_to_float (ctx_arg_u8 (4) ),
+ ctx_u8_to_float (ctx_arg_u8 (4+1) ),
+ ctx_u8_to_float (ctx_arg_u8 (4+2) ),
+ ctx_u8_to_float (ctx_arg_u8 (4+3) )
+ };
+ ctx_sha1_process(&hasher->sha1_fill,
+ (uint8_t*) &rgba[0], sizeof(rgba));
+ }
+ break;
#endif
+ }
+ if (command->code == CTX_LINE_WIDTH)
+ {
+ float x = state->gstate.line_width;
+ /* normalize line width according to scaling factor
+ */
+ x = x * ctx_maxf (ctx_maxf (ctx_fabsf (state->gstate.transform.m[0][0]),
+ ctx_fabsf (state->gstate.transform.m[0][1]) ),
+ ctx_maxf (ctx_fabsf (state->gstate.transform.m[1][0]),
+ ctx_fabsf (state->gstate.transform.m[1][1]) ) );
+ state->gstate.line_width = x;
+ }
}
-#if CTX_EVENTS
-typedef struct CtxIdleCb {
- int (*cb) (Ctx *ctx, void *idle_data);
- void *idle_data;
+static CtxRasterizer *
+ctx_hasher_init (CtxRasterizer *rasterizer, Ctx *ctx, CtxState *state, int width, int height, int cols, int
rows)
+{
+ CtxHasher *hasher = (CtxHasher*)rasterizer;
+ ctx_memset (rasterizer, 0, sizeof (CtxHasher) );
+ rasterizer->vfuncs.process = ctx_hasher_process;
+ rasterizer->vfuncs.free = (CtxDestroyNotify)ctx_rasterizer_deinit;
+ // XXX need own destructor to not leak ->hashes
+ rasterizer->edge_list.flags |= CTX_DRAWLIST_EDGE_LIST;
+ rasterizer->state = state;
+ rasterizer->ctx = ctx;
+ ctx_state_init (rasterizer->state);
+ rasterizer->blit_x = 0;
+ rasterizer->blit_y = 0;
+ rasterizer->blit_width = width;
+ rasterizer->blit_height = height;
+ rasterizer->state->gstate.clip_min_x = 0;
+ rasterizer->state->gstate.clip_min_y = 0;
+ rasterizer->state->gstate.clip_max_x = width - 1;
+ rasterizer->state->gstate.clip_max_y = height - 1;
+ rasterizer->scan_min = 5000;
+ rasterizer->scan_max = -5000;
+ rasterizer->aa = 5;
+ rasterizer->force_aa = 0;
- void (*destroy_notify)(void *destroy_data);
- void *destroy_data;
+ hasher->rows = rows;
+ hasher->cols = cols;
- int ticks_full;
- int ticks_remaining;
- int is_idle;
- int id;
-} CtxIdleCb;
+ hasher->hashes = (uint8_t*)ctx_calloc (20, rows * cols);
+ ctx_sha1_init (&hasher->sha1_fill);
+ ctx_sha1_init (&hasher->sha1_stroke);
-void _ctx_events_init (Ctx *ctx)
+ return rasterizer;
+}
+
+Ctx *ctx_hasher_new (int width, int height, int cols, int rows)
{
- CtxEvents *events = &ctx->events;
- _ctx_init_ticks ();
- events->tap_delay_min = 40;
- events->tap_delay_max = 800;
- events->tap_delay_max = 8000000; /* quick reflexes needed making it hard for some is an argument against
very short values */
+ Ctx *ctx = ctx_new ();
+ CtxState *state = &ctx->state;
+ CtxRasterizer *rasterizer = (CtxRasterizer *) ctx_calloc (sizeof (CtxHasher), 1);
+ ctx_hasher_init (rasterizer, ctx, state, width, height, cols, rows);
+ ctx_set_renderer (ctx, (void*)rasterizer);
+ return ctx;
+}
+uint8_t *ctx_hasher_get_hash (Ctx *ctx, int col, int row)
+{
+ CtxHasher *hasher = (CtxHasher*)ctx->renderer;
+ if (row < 0) row =0;
+ if (col < 0) col =0;
+ if (row >= hasher->rows) row = hasher->rows-1;
+ if (col >= hasher->cols) col = hasher->cols-1;
- events->tap_delay_hold = 1000;
- events->tap_hysteresis = 32; /* XXX: should be ppi dependent */
+ return &hasher->hashes[(row*hasher->cols+col)*20];
}
+#endif
+#if CTX_EVENTS
-void _ctx_idle_iteration (Ctx *ctx)
-{
- static unsigned long prev_ticks = 0;
- CtxList *l;
- CtxList *to_remove = NULL;
- unsigned long ticks = _ctx_ticks ();
- unsigned long tick_delta = (prev_ticks == 0) ? 0 : ticks - prev_ticks;
- prev_ticks = ticks;
+#include <termios.h>
- if (!ctx->events.idles)
- {
- return;
- }
- for (l = ctx->events.idles; l; l = l->next)
- {
- CtxIdleCb *item = l->data;
+#include <fcntl.h>
+#include <sys/ioctl.h>
- if (item->ticks_remaining >= 0)
- item->ticks_remaining -= tick_delta;
+int ctx_terminal_width (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[14t");
+ //tcflush(STDIN_FILENO, 1);
+ tcdrain(STDIN_FILENO);
+ 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;
- if (item->ticks_remaining < 0)
- {
- if (item->cb (ctx, item->idle_data) == 0)
- ctx_list_prepend (&to_remove, item);
- else
- item->ticks_remaining = item->ticks_full;
- }
- }
- for (l = to_remove; l; l = l->next)
+ for (int n = 0; select(1, &rfds, NULL, NULL, &tv) && n < 20; n++)
{
- CtxIdleCb *item = l->data;
- if (item->destroy_notify)
- item->destroy_notify (item->destroy_data);
- ctx_list_remove (&ctx->events.idles, l->data);
+ length += read (STDIN_FILENO, &buf[length], 1);
}
-}
-
-
-void ctx_add_key_binding_full (Ctx *ctx,
- const char *key,
- const char *action,
- const char *label,
- CtxCb cb,
- void *cb_data,
- CtxDestroyNotify destroy_notify,
- void *destroy_data)
-{
- CtxEvents *events = &ctx->events;
- if (events->n_bindings +1 >= CTX_MAX_KEYBINDINGS)
+ tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
+ if (length == -1)
{
- fprintf (stderr, "warning: binding overflow\n");
- return;
+ return 0;
}
- events->bindings[events->n_bindings].nick = strdup (key);
- strcpy (events->bindings[events->n_bindings].nick, key);
-
- if (action)
- events->bindings[events->n_bindings].command = action ? strdup (action) : NULL;
- if (label)
- events->bindings[events->n_bindings].label = label ? 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;
- events->bindings[events->n_bindings].destroy_data = destroy_data;
- events->n_bindings++;
-}
-
-void ctx_add_key_binding (Ctx *ctx,
- const char *key,
- const char *action,
- const char *label,
- CtxCb cb,
- void *cb_data)
-{
- ctx_add_key_binding_full (ctx, key, action, label, cb, cb_data, NULL, NULL);
-}
-
-void ctx_clear_bindings (Ctx *ctx)
-{
- CtxEvents *events = &ctx->events;
- int i;
- for (i = 0; events->bindings[i].nick; i ++)
+ char *semi = strchr (buf, ';');
+ buf[length]=0;
+ if (semi) {semi++; semi = strchr (semi, ';');}
+ if (semi)
{
- if (events->bindings[i].destroy_notify)
- events->bindings[i].destroy_notify (events->bindings[i].destroy_data);
- free (events->bindings[i].nick);
- if (events->bindings[i].command)
- free (events->bindings[i].command);
- if (events->bindings[i].label)
- free (events->bindings[i].label);
+ return atoi(semi + 1);
}
- memset (&events->bindings, 0, sizeof (events->bindings));
- events->n_bindings = 0;
-}
-
-static void _ctx_bindings_key_down (CtxEvent *event, void *data1, void *data2)
-{
- Ctx *ctx = event->ctx;
- CtxEvents *events = &ctx->events;
- int i;
- int handled = 0;
-
- for (i = events->n_bindings-1; i>=0; i--)
- if (!strcmp (events->bindings[i].nick, event->string))
- {
- if (events->bindings[i].cb)
- {
- events->bindings[i].cb (event, events->bindings[i].cb_data, NULL);
- if (event->stop_propagate)
- return;
- handled = 1;
- }
- }
- if (!handled)
- for (i = events->n_bindings-1; i>=0; i--)
- if (!strcmp (events->bindings[i].nick, "unhandled"))
- {
- if (events->bindings[i].cb)
- {
- events->bindings[i].cb (event, events->bindings[i].cb_data, NULL);
- if (event->stop_propagate)
- return;
- }
- }
-}
-
-CtxBinding *ctx_get_bindings (Ctx *ctx)
-{
- return &ctx->events.bindings[0];
+ return 0;
}
-void ctx_remove_idle (Ctx *ctx, int handle)
+int ctx_terminal_height (void)
{
- CtxList *l;
- CtxList *to_remove = NULL;
+ 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[14t");
+ //tcflush(STDIN_FILENO, 1);
+ tcdrain(STDIN_FILENO);
+ 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;
- if (!ctx->events.idles)
+ for (int n = 0; select(1, &rfds, NULL, NULL, &tv) && n < 20; n++)
{
- return;
+ length += read (STDIN_FILENO, &buf[length], 1);
}
- for (l = ctx->events.idles; l; l = l->next)
+ tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
+ if (length == -1)
{
- CtxIdleCb *item = l->data;
- if (item->id == handle)
- ctx_list_prepend (&to_remove, item);
+ return 0;
}
- for (l = to_remove; l; l = l->next)
+ char *semi = strchr (buf, ';');
+ buf[length]=0;
+ if (semi)
{
- CtxIdleCb *item = l->data;
- if (item->destroy_notify)
- item->destroy_notify (item->destroy_data);
- ctx_list_remove (&ctx->events.idles, l->data);
+ return atoi(semi + 1);
}
+ return 0;
}
-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)
+int ctx_terminal_cols (void)
{
- CtxIdleCb *item = calloc (sizeof (CtxIdleCb), 1);
- item->cb = idle_cb;
- item->idle_data = idle_data;
- item->id = ++ctx->events.idle_id;
- item->ticks_full =
- item->ticks_remaining = ms * 1000;
- item->destroy_notify = destroy_notify;
- item->destroy_data = destroy_data;
- ctx_list_append (&ctx->events.idles, item);
- return item->id;
-}
+ struct winsize ws;
+ if (ioctl(0,TIOCGWINSZ,&ws)!=0)
+ return 80;
+ return ws.ws_col;
+}
-int ctx_add_timeout (Ctx *ctx, int ms, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data)
+int ctx_terminal_rows (void)
{
- return ctx_add_timeout_full (ctx, ms, idle_cb, idle_data, NULL, NULL);
+ struct winsize ws;
+ if (ioctl(0,TIOCGWINSZ,&ws)!=0)
+ return 25;
+ return ws.ws_row;
}
-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);
- item->cb = idle_cb;
- item->idle_data = idle_data;
- item->id = ++ctx->events.idle_id;
- item->ticks_full =
- item->ticks_remaining = -1;
- item->is_idle = 1;
- item->destroy_notify = destroy_notify;
- item->destroy_data = destroy_data;
- ctx_list_append (&ctx->events.idles, item);
- return item->id;
-}
-int ctx_add_idle (Ctx *ctx, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data)
-{
- return ctx_add_idle_full (ctx, idle_cb, idle_data, NULL, NULL);
-}
+
+
+#define DECTCEM_CURSOR_SHOW "\033[?25h"
+#define DECTCEM_CURSOR_HIDE "\033[?25l"
+#define TERMINAL_MOUSE_OFF "\033[?1000l\033[?1003l"
+#define TERMINAL_MOUSE_ON_BASIC "\033[?1000h"
+#define TERMINAL_MOUSE_ON_DRAG "\033[?1000h\033[?1003h" /* +ON_BASIC for wider */
+#define TERMINAL_MOUSE_ON_FULL "\033[?1000h\033[?1004h" /* compatibility */
+#define XTERM_ALTSCREEN_ON "\033[?47h"
+#define XTERM_ALTSCREEN_OFF "\033[?47l"
+
+/*************************** input handling *************************/
+
+#include <termios.h>
+#include <errno.h>
+#include <signal.h>
+
+#define DELAY_MS 100
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
-/* using bigger primes would be a good idea, this falls apart due to rounding
- * when zoomed in close
- */
-static inline double ctx_path_hash (void *path)
-{
- double ret = 0;
-#if 0
- int i;
- cairo_path_data_t *data;
- if (!path)
- return 0.99999;
- for (i = 0; i <path->num_data; i += path->data[i].header.length)
- {
- data = &path->data[i];
- switch (data->header.type) {
- case CAIRO_PATH_MOVE_TO:
- ret *= 17;
- ret += data[1].point.x;
- ret *= 113;
- ret += data[1].point.y;
- break;
- case CAIRO_PATH_LINE_TO:
- ret *= 121;
- ret += data[1].point.x;
- ret *= 1021;
- ret += data[1].point.y;
- break;
- case CAIRO_PATH_CURVE_TO:
- ret *= 3111;
- ret += data[1].point.x;
- ret *= 23;
- ret += data[1].point.y;
- ret *= 107;
- ret += data[2].point.x;
- ret *= 739;
- ret += data[2].point.y;
- ret *= 3;
- ret += data[3].point.x;
- ret *= 51;
- ret += data[3].point.y;
- break;
- case CAIRO_PATH_CLOSE_PATH:
- ret *= 51;
- break;
- }
- }
-#endif
- return ret;
-}
-#if CTX_EVENTS
-void _ctx_item_ref (CtxItem *item)
-{
- if (item->ref_count < 0)
- {
- fprintf (stderr, "EEEEK!\n");
- }
- item->ref_count++;
-}
+static int size_changed = 0; /* XXX: global state */
+static int signal_installed = 0; /* XXX: global state */
+static const char *mouse_modes[]=
+{TERMINAL_MOUSE_OFF,
+ TERMINAL_MOUSE_ON_BASIC,
+ TERMINAL_MOUSE_ON_DRAG,
+ TERMINAL_MOUSE_ON_FULL,
+ NULL};
-void _ctx_item_unref (CtxItem *item)
-{
- if (item->ref_count <= 0)
- {
- fprintf (stderr, "EEEEK!\n");
- return;
- }
- item->ref_count--;
- if (item->ref_count <=0)
- {
- {
- int i;
- for (i = 0; i < item->cb_count; i++)
- {
- if (item->cb[i].finalize)
- item->cb[i].finalize (item->cb[i].data1, item->cb[i].data2,
- item->cb[i].finalize_data);
- }
- }
- if (item->path)
- {
- //cairo_path_destroy (item->path);
- }
- free (item);
- }
-}
+/* note that a nick can have multiple occurences, the labels
+ * should be kept the same for all occurences of a combination. */
+typedef struct NcKeyCode {
+ const char *nick; /* programmers name for key (combo) */
+ const char *label; /* utf8 label for key */
+ const char sequence[10]; /* terminal sequence */
+} NcKeyCode;
+static const NcKeyCode keycodes[]={
+ {"up", "↑", "\033[A"},
+ {"down", "↓", "\033[B"},
+ {"right", "→", "\033[C"},
+ {"left", "←", "\033[D"},
-static int
-path_equal (void *path,
- void *path2)
-{
- // XXX
- return 0;
-}
+ {"shift-up", "⇧↑", "\033[1;2A"},
+ {"shift-down", "⇧↓", "\033[1;2B"},
+ {"shift-right", "⇧→", "\033[1;2C"},
+ {"shift-left", "⇧←", "\033[1;2D"},
-void ctx_listen_set_cursor (Ctx *ctx,
- CtxCursor cursor)
-{
- if (ctx->events.last_item)
- {
- ctx->events.last_item->cursor = cursor;
- }
-}
+ {"alt-up", "^↑", "\033[1;3A"},
+ {"alt-down", "^↓", "\033[1;3B"},
+ {"alt-right", "^→", "\033[1;3C"},
+ {"alt-left", "^←", "\033[1;3D"},
-void ctx_listen_full (Ctx *ctx,
- float x,
- float y,
- float width,
- float height,
- CtxEventType types,
- CtxCb cb,
- void *data1,
- void *data2,
- void (*finalize)(void *listen_data,
- void *listen_data2,
- void *finalize_data),
- void *finalize_data)
-{
- if (!ctx->events.frozen)
- {
- CtxItem *item;
+ {"alt-shift-up", "alt-s↑", "\033[1;4A"},
+ {"alt-shift-down", "alt-s↓", "\033[1;4B"},
+ {"alt-shift-right", "alt-s→", "\033[1;4C"},
+ {"alt-shift-left", "alt-s←", "\033[1;4D"},
- /* early bail for listeners outside screen */
- /* XXX: fixme respect clipping */
- {
- float tx = x;
- float ty = y;
- float tw = width;
- float th = height;
- _ctx_user_to_device (&ctx->state, &tx, &ty);
- _ctx_user_to_device_distance (&ctx->state, &tw, &th);
- if (ty > ctx->events.height * 2 ||
- tx > ctx->events.width * 2 ||
- tx + tw < 0 ||
- ty + th < 0)
- {
- if (finalize)
- finalize (data1, data2, finalize_data);
- return;
- }
- }
+ {"control-up", "^↑", "\033[1;5A"},
+ {"control-down", "^↓", "\033[1;5B"},
+ {"control-right", "^→", "\033[1;5C"},
+ {"control-left", "^←", "\033[1;5D"},
- item = calloc (sizeof (CtxItem), 1);
- item->x0 = x;
- item->y0 = y;
- item->x1 = x + width;
- item->y1 = y + height;
- item->cb[0].types = types;
- item->cb[0].cb = cb;
- item->cb[0].data1 = data1;
- item->cb[0].data2 = data2;
- item->cb[0].finalize = finalize;
- item->cb[0].finalize_data = finalize_data;
- item->cb_count = 1;
- item->types = types;
- //item->path = cairo_copy_path (cr); // XXX
- item->path_hash = ctx_path_hash (item->path);
- ctx_get_matrix (ctx, &item->inv_matrix);
- ctx_matrix_invert (&item->inv_matrix);
+ /* putty */
+ {"control-up", "^↑", "\033OA"},
+ {"control-down", "^↓", "\033OB"},
+ {"control-right", "^→", "\033OC"},
+ {"control-left", "^←", "\033OD"},
- if (ctx->events.items)
- {
- CtxList *l;
- for (l = ctx->events.items; l; l = l->next)
- {
- CtxItem *item2 = l->data;
+ {"control-shift-up", "^⇧↑", "\033[1;6A"},
+ {"control-shift-down", "^⇧↓", "\033[1;6B"},
+ {"control-shift-right", "^⇧→", "\033[1;6C"},
+ {"control-shift-left", "^⇧←", "\033[1;6D"},
- /* store multiple callbacks for one entry when the paths
- * are exact matches, reducing per event traversal checks at the
- * cost of a little paint-hit (XXX: is this the right tradeoff,
- * perhaps it is better to spend more time during event processing
- * than during paint?)
- */
- if (item->path_hash == item2->path_hash &&
- path_equal (item->path, item2->path))
- {
- /* found an item, copy over cb data */
- item2->cb[item2->cb_count] = item->cb[0];
- free (item);
- item2->cb_count++;
- item2->types |= types;
- return;
- }
- }
- }
- item->ref_count = 1;
- ctx->events.last_item = item;
- ctx_list_prepend_full (&ctx->events.items, item, (void*)_ctx_item_unref, NULL);
- }
-}
+ {"control-up", "^↑", "\033Oa"},
+ {"control-down", "^↓", "\033Ob"},
+ {"control-right", "^→", "\033Oc"},
+ {"control-left", "^←", "\033Od"},
-void ctx_event_stop_propagate (CtxEvent *event)
-{
- if (event)
- event->stop_propagate = 1;
-}
+ {"shift-up", "⇧↑", "\033[a"},
+ {"shift-down", "⇧↓", "\033[b"},
+ {"shift-right", "⇧→", "\033[c"},
+ {"shift-left", "⇧←", "\033[d"},
-void ctx_listen (Ctx *ctx,
- CtxEventType types,
- CtxCb cb,
- void* data1,
- void* data2)
-{
- float x, y, width, height;
- /* generate bounding box of what to listen for - from current cairo path */
- if (types & CTX_KEY)
- {
- x = 0;
- y = 0;
- width = 0;
- height = 0;
- }
- else
- {
- float ex1,ey1,ex2,ey2;
- ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
- x = ex1;
- y = ey1;
- width = ex2 - ex1;
- height = ey2 - ey1;
- }
-
- if (types == CTX_DRAG_MOTION)
- types = CTX_DRAG_MOTION | CTX_DRAG_PRESS;
- return ctx_listen_full (ctx, x, y, width, height, types, cb, data1, data2, NULL, NULL);
-}
-
-void ctx_listen_with_finalize (Ctx *ctx,
- CtxEventType types,
- CtxCb cb,
- void* data1,
- void* data2,
- void (*finalize)(void *listen_data, void *listen_data2,
- void *finalize_data),
- void *finalize_data)
-{
- float x, y, width, height;
- /* generate bounding box of what to listen for - from current cairo path */
- if (types & CTX_KEY)
- {
- x = 0;
- y = 0;
- width = 0;
- height = 0;
- }
- else
- {
- float ex1,ey1,ex2,ey2;
- ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
- x = ex1;
- y = ey1;
- width = ex2 - ex1;
- height = ey2 - ey1;
- }
+ {"insert", "ins", "\033[2~"},
+ {"delete", "del", "\033[3~"},
+ {"page-up", "PgUp", "\033[5~"},
+ {"page-down", "PdDn", "\033[6~"},
+ {"home", "Home", "\033OH"},
+ {"end", "End", "\033OF"},
+ {"home", "Home", "\033[H"},
+ {"end", "End", "\033[F"},
+ {"control-delete", "^del", "\033[3;5~"},
+ {"shift-delete", "⇧del", "\033[3;2~"},
+ {"control-shift-delete","^⇧del", "\033[3;6~"},
- if (types == CTX_DRAG_MOTION)
- types = CTX_DRAG_MOTION | CTX_DRAG_PRESS;
- return ctx_listen_full (ctx, x, y, width, height, types, cb, data1, data2, finalize, finalize_data);
-}
+ {"F1", "F1", "\033[11~"},
+ {"F2", "F2", "\033[12~"},
+ {"F3", "F3", "\033[13~"},
+ {"F4", "F4", "\033[14~"},
+ {"F1", "F1", "\033OP"},
+ {"F2", "F2", "\033OQ"},
+ {"F3", "F3", "\033OR"},
+ {"F4", "F4", "\033OS"},
+ {"F5", "F5", "\033[15~"},
+ {"F6", "F6", "\033[16~"},
+ {"F7", "F7", "\033[17~"},
+ {"F8", "F8", "\033[18~"},
+ {"F9", "F9", "\033[19~"},
+ {"F9", "F9", "\033[20~"},
+ {"F10", "F10", "\033[21~"},
+ {"F11", "F11", "\033[22~"},
+ {"F12", "F12", "\033[23~"},
+ {"tab", "↹", {9, '\0'}},
+ {"shift-tab", "shift+↹", "\033[Z"},
+ {"backspace", "⌫", {127, '\0'}},
+ {"space", "␣", " "},
+ {"esc", "␛", "\033"},
+ {"return", "⏎", {10,0}},
+ {"return", "⏎", {13,0}},
+ /* this section could be autogenerated by code */
+ {"control-a", "^A", {1,0}},
+ {"control-b", "^B", {2,0}},
+ {"control-c", "^C", {3,0}},
+ {"control-d", "^D", {4,0}},
+ {"control-e", "^E", {5,0}},
+ {"control-f", "^F", {6,0}},
+ {"control-g", "^G", {7,0}},
+ {"control-h", "^H", {8,0}}, /* backspace? */
+ {"control-i", "^I", {9,0}}, /* tab */
+ {"control-j", "^J", {10,0}},
+ {"control-k", "^K", {11,0}},
+ {"control-l", "^L", {12,0}},
+ {"control-n", "^N", {14,0}},
+ {"control-o", "^O", {15,0}},
+ {"control-p", "^P", {16,0}},
+ {"control-q", "^Q", {17,0}},
+ {"control-r", "^R", {18,0}},
+ {"control-s", "^S", {19,0}},
+ {"control-t", "^T", {20,0}},
+ {"control-u", "^U", {21,0}},
+ {"control-v", "^V", {22,0}},
+ {"control-w", "^W", {23,0}},
+ {"control-x", "^X", {24,0}},
+ {"control-y", "^Y", {25,0}},
+ {"control-z", "^Z", {26,0}},
+ {"alt-0", "%0", "\0330"},
+ {"alt-1", "%1", "\0331"},
+ {"alt-2", "%2", "\0332"},
+ {"alt-3", "%3", "\0333"},
+ {"alt-4", "%4", "\0334"},
+ {"alt-5", "%5", "\0335"},
+ {"alt-6", "%6", "\0336"},
+ {"alt-7", "%7", "\0337"}, /* backspace? */
+ {"alt-8", "%8", "\0338"},
+ {"alt-9", "%9", "\0339"},
+ {"alt-+", "%+", "\033+"},
+ {"alt--", "%-", "\033-"},
+ {"alt-/", "%/", "\033/"},
+ {"alt-a", "%A", "\033a"},
+ {"alt-b", "%B", "\033b"},
+ {"alt-c", "%C", "\033c"},
+ {"alt-d", "%D", "\033d"},
+ {"alt-e", "%E", "\033e"},
+ {"alt-f", "%F", "\033f"},
+ {"alt-g", "%G", "\033g"},
+ {"alt-h", "%H", "\033h"}, /* backspace? */
+ {"alt-i", "%I", "\033i"},
+ {"alt-j", "%J", "\033j"},
+ {"alt-k", "%K", "\033k"},
+ {"alt-l", "%L", "\033l"},
+ {"alt-n", "%N", "\033m"},
+ {"alt-n", "%N", "\033n"},
+ {"alt-o", "%O", "\033o"},
+ {"alt-p", "%P", "\033p"},
+ {"alt-q", "%Q", "\033q"},
+ {"alt-r", "%R", "\033r"},
+ {"alt-s", "%S", "\033s"},
+ {"alt-t", "%T", "\033t"},
+ {"alt-u", "%U", "\033u"},
+ {"alt-v", "%V", "\033v"},
+ {"alt-w", "%W", "\033w"},
+ {"alt-x", "%X", "\033x"},
+ {"alt-y", "%Y", "\033y"},
+ {"alt-z", "%Z", "\033z"},
+ {"shift-tab", "shift-↹", {27, 9, 0}},
+ /* Linux Console */
+ {"home", "Home", "\033[1~"},
+ {"end", "End", "\033[4~"},
+ {"F1", "F1", "\033[[A"},
+ {"F2", "F2", "\033[[B"},
+ {"F3", "F3", "\033[[C"},
+ {"F4", "F4", "\033[[D"},
+ {"F5", "F5", "\033[[E"},
+ {"F6", "F6", "\033[[F"},
+ {"F7", "F7", "\033[[G"},
+ {"F8", "F8", "\033[[H"},
+ {"F9", "F9", "\033[[I"},
+ {"F10", "F10", "\033[[J"},
+ {"F11", "F11", "\033[[K"},
+ {"F12", "F12", "\033[[L"},
+ {"ok", "", "\033[0n"},
+ {NULL, }
+};
+static struct termios orig_attr; /* in order to restore at exit */
+static int nc_is_raw = 0;
+static int atexit_registered = 0;
+static int mouse_mode = NC_MOUSE_NONE;
-static void ctx_report_hit_region (CtxEvent *event,
- void *data,
- void *data2)
+static void _nc_noraw (void)
{
- const char *id = data;
-
- fprintf (stderr, "hit region %s\n", id);
- // XXX: NYI
+ if (nc_is_raw && tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr) != -1)
+ nc_is_raw = 0;
}
-void ctx_add_hit_region (Ctx *ctx, const char *id)
+void
+nc_at_exit (void)
{
- char *id_copy = strdup (id);
- float x, y, width, height;
- /* generate bounding box of what to listen for - from current cairo path */
- {
- float ex1,ey1,ex2,ey2;
- ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
- x = ex1;
- y = ey1;
- width = ex2 - ex1;
- height = ey2 - ey1;
- }
-
- return ctx_listen_full (ctx, x, y, width, height, CTX_POINTER, ctx_report_hit_region, id_copy, NULL,
(void*)free, NULL);
+ printf (TERMINAL_MOUSE_OFF);
+ printf (XTERM_ALTSCREEN_OFF);
+ _nc_noraw();
+ fprintf (stdout, "\e[?25h");
+ //if (ctx_native_events)
+ fprintf (stdout, "\e[?201l");
+ fprintf (stdout, "\e[?1049l");
}
-typedef struct _CtxGrab CtxGrab;
-
-struct _CtxGrab
+static const char *mouse_get_event_int (Ctx *n, int *x, int *y)
{
- CtxItem *item;
- int device_no;
- int timeout_id;
- int start_time;
- float x; // for tap and hold
- float y;
- CtxEventType type;
-};
+ static int prev_state = 0;
+ const char *ret = "mouse-motion";
+ float relx, rely;
+ signed char buf[3];
+ read (n->mouse_fd, buf, 3);
+ relx = buf[1];
+ rely = -buf[2];
-static void grab_free (Ctx *ctx, CtxGrab *grab)
-{
- if (grab->timeout_id)
- {
- ctx_remove_idle (ctx, grab->timeout_id);
- grab->timeout_id = 0;
- }
- _ctx_item_unref (grab->item);
- free (grab);
-}
+ n->mouse_x += relx * 0.1;
+ n->mouse_y += rely * 0.1;
-static void device_remove_grab (Ctx *ctx, CtxGrab *grab)
-{
- ctx_list_remove (&ctx->events.grabs, grab);
- grab_free (ctx, grab);
-}
+ if (n->mouse_x < 1) n->mouse_x = 1;
+ if (n->mouse_y < 1) n->mouse_y = 1;
+ if (n->mouse_x >= n->events.width) n->mouse_x = n->events.width;
+ if (n->mouse_y >= n->events.height) n->mouse_y = n->events.height;
-static CtxGrab *device_add_grab (Ctx *ctx, int device_no, CtxItem *item, CtxEventType type)
-{
- CtxGrab *grab = calloc (1, sizeof (CtxGrab));
- grab->item = item;
- grab->type = type;
- _ctx_item_ref (item);
- grab->device_no = device_no;
- ctx_list_append (&ctx->events.grabs, grab);
- return grab;
-}
+ if (x) *x = n->mouse_x;
+ if (y) *y = n->mouse_y;
-CtxList *device_get_grabs (Ctx *ctx, int device_no)
-{
- CtxList *ret = NULL;
- CtxList *l;
- for (l = ctx->events.grabs; l; l = l->next)
- {
- CtxGrab *grab = l->data;
- if (grab->device_no == device_no)
- ctx_list_append (&ret, grab);
- }
- return ret;
-}
-
-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);
-}
-
-CtxList *_ctx_detect_list (Ctx *ctx, float x, float y, CtxEventType type)
-{
- CtxList *a;
- CtxList *ret = NULL;
-
- if (type == CTX_KEY_DOWN ||
- type == CTX_KEY_UP ||
- type == CTX_MESSAGE ||
- type == (CTX_KEY_DOWN|CTX_MESSAGE) ||
- type == (CTX_KEY_DOWN|CTX_KEY_UP) ||
- type == (CTX_KEY_DOWN|CTX_KEY_UP|CTX_MESSAGE))
- {
- for (a = ctx->events.items; a; a = a->next)
+ if ((prev_state & 1) != (buf[0] & 1))
{
- CtxItem *item = a->data;
- if (item->types & type)
- {
- ctx_list_prepend (&ret, item);
- return ret;
- }
+ if (buf[0] & 1) ret = "mouse-press";
}
- return NULL;
- }
+ else if (buf[0] & 1)
+ ret = "mouse-drag";
- for (a = ctx->events.items; a; a = a->next)
- {
- CtxItem *item= a->data;
-
- float u, v;
- u = x;
- v = y;
- ctx_matrix_apply_transform (&item->inv_matrix, &u, &v);
+ if ((prev_state & 2) != (buf[0] & 2))
+ {
+ if (buf[0] & 2) ret = "mouse2-press";
+ }
+ else if (buf[0] & 2)
+ ret = "mouse2-drag";
- if (u >= item->x0 && v >= item->y0 &&
- u < item->x1 && v < item->y1 &&
- ((item->types & type) || ((type == CTX_SET_CURSOR) &&
- item->cursor)))
+ if ((prev_state & 4) != (buf[0] & 4))
{
- if (item->path)
- {
- _mrg_restore_path (ctx, item->path);
- if (ctx_in_fill (ctx, u, v))
- {
- ctx_begin_path (ctx);
- ctx_list_prepend (&ret, item);
- }
- ctx_begin_path (ctx);
- }
- else
- {
- ctx_list_prepend (&ret, item);
- }
+ if (buf[0] & 4) ret = "mouse1-press";
}
- }
+ else if (buf[0] & 4)
+ ret = "mouse1-drag";
+
+ prev_state = buf[0];
return ret;
}
-CtxItem *_ctx_detect (Ctx *ctx, float x, float y, CtxEventType type)
+static const char *mev_type = NULL;
+static int mev_x = 0;
+static int mev_y = 0;
+static int mev_q = 0;
+
+static const char *mouse_get_event (Ctx *n, int *x, int *y)
{
- CtxList *l = _ctx_detect_list (ctx, x, y, type);
- if (l)
- {
- ctx_list_reverse (&l);
- CtxItem *ret = l->data;
- ctx_list_free (&l);
- return ret;
- }
- return NULL;
+ if (!mev_q)
+ return NULL;
+ *x = mev_x;
+ *y = mev_y;
+ mev_q = 0;
+ return mev_type;
}
-static int
-_ctx_emit_cb_item (Ctx *ctx, CtxItem *item, CtxEvent *event, CtxEventType type, float x, float y)
+static int mouse_has_event (Ctx *n)
{
- static CtxEvent s_event;
- CtxEvent transformed_event;
- int i;
+ struct timeval tv;
+ int retval;
+
+ if (mouse_mode == NC_MOUSE_NONE)
+ return 0;
+ if (mev_q)
+ return 1;
- if (!event)
- {
- event = &s_event;
- event->type = type;
- event->x = x;
- event->y = y;
- }
- event->ctx = ctx;
- transformed_event = *event;
- transformed_event.device_x = event->x;
- transformed_event.device_y = event->y;
+ if (n->mouse_fd == 0)
+ return 0;
+ return 0;
{
- float tx, ty;
- tx = transformed_event.x;
- ty = transformed_event.y;
- ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
- transformed_event.x = tx;
- transformed_event.y = ty;
+ fd_set rfds;
+ FD_ZERO (&rfds);
+ FD_SET(n->mouse_fd, &rfds);
+ tv.tv_sec = 0; tv.tv_usec = 0;
+ retval = select (n->mouse_fd+1, &rfds, NULL, NULL, &tv);
+ }
- if ((type & CTX_DRAG_PRESS) ||
- (type & CTX_DRAG_MOTION) ||
- (type & CTX_MOTION)) /* probably a worthwhile check for the performance
- benefit
- */
+ if (retval != 0)
{
- tx = transformed_event.start_x;
- ty = transformed_event.start_y;
- ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
- transformed_event.start_x = tx;
- transformed_event.start_y = ty;
- }
+ int nx = 0, ny = 0;
+ const char *type = mouse_get_event_int (n, &nx, &ny);
+ if ((mouse_mode < NC_MOUSE_DRAG && mev_type && !strcmp (mev_type, "drag")) ||
+ (mouse_mode < NC_MOUSE_ALL && mev_type && !strcmp (mev_type, "motion")))
+ {
+ mev_q = 0;
+ return mouse_has_event (n);
+ }
- tx = transformed_event.delta_x;
- ty = transformed_event.delta_y;
- ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
- transformed_event.delta_x = tx;
- transformed_event.delta_y = ty;
- }
+ if ((mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse-motion")) ||
+ (mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse1-drag")) ||
+ (mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse2-drag")))
+ {
+ if (nx == mev_x && ny == mev_y)
+ {
+ mev_q = 0;
+ return mouse_has_event (n);
+ }
+ }
+ mev_x = nx;
+ mev_y = ny;
+ mev_type = type;
+ mev_q = 1;
+ }
+ return retval != 0;
+}
- transformed_event.state = ctx->events.modifier_state;
- transformed_event.type = type;
- for (i = item->cb_count-1; i >= 0; i--)
- {
- if (item->cb[i].types & type)
+static int _nc_raw (void)
+{
+ struct termios raw;
+ if (!isatty (STDIN_FILENO))
+ return -1;
+ if (!atexit_registered)
{
- item->cb[i].cb (&transformed_event, item->cb[i].data1, item->cb[i].data2);
- event->stop_propagate = transformed_event.stop_propagate; /* copy back the response */
- if (event->stop_propagate)
- return event->stop_propagate;
+ atexit (nc_at_exit);
+ atexit_registered = 1;
}
- }
+ if (tcgetattr (STDIN_FILENO, &orig_attr) == -1)
+ return -1;
+ raw = orig_attr; /* modify the original mode */
+ 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 -1;
+ nc_is_raw = 1;
+ tcdrain(STDIN_FILENO);
+ tcflush(STDIN_FILENO, 1);
return 0;
}
-#endif
-
-#if CTX_EVENTS
-
-#include <stdatomic.h>
-int ctx_native_events = 0;
-#if CTX_SDL
-int ctx_sdl_events = 0;
-int ctx_sdl_consume_events (Ctx *ctx);
-#endif
+static int match_keycode (const char *buf, int length, const NcKeyCode **ret)
+{
+ int i;
+ int matches = 0;
-#if CTX_FB
-int ctx_fb_events = 0;
-int ctx_fb_consume_events (Ctx *ctx);
-#endif
+ if (!strncmp (buf, "\033[M", MIN(length,3)))
+ {
+ if (length >= 6)
+ return 9001;
+ return 2342;
+ }
+ for (i = 0; keycodes[i].nick; i++)
+ if (!strncmp (buf, keycodes[i].sequence, length))
+ {
+ matches ++;
+ if ((int)strlen (keycodes[i].sequence) == length && ret)
+ {
+ *ret = &keycodes[i];
+ return 1;
+ }
+ }
+ if (matches != 1 && ret)
+ *ret = NULL;
+ return matches==1?2:matches;
+}
+static void nc_resize_term (int dummy)
+{
+ size_changed = 1;
+}
-int ctx_nct_consume_events (Ctx *ctx);
-int ctx_ctx_consume_events (Ctx *ctx);
-#if CTX_SDL
-#endif
-
-void ctx_consume_events (Ctx *ctx)
+int ctx_has_event (Ctx *n, int delay_ms)
{
-#if CTX_SDL
- if (ctx_sdl_events)
- ctx_sdl_consume_events (ctx);
- else
-#endif
-#if CTX_FB
- if (ctx_fb_events)
- ctx_fb_consume_events (ctx);
- else
-#endif
- if (ctx_native_events)
- ctx_ctx_consume_events (ctx);
- else
- ctx_nct_consume_events (ctx);
+ struct timeval tv;
+ int retval;
+ fd_set rfds;
+
+ if (size_changed)
+ return 1;
+ FD_ZERO (&rfds);
+ FD_SET (STDIN_FILENO, &rfds);
+ tv.tv_sec = 0; tv.tv_usec = delay_ms * 1000;
+ retval = select (1, &rfds, NULL, NULL, &tv);
+ if (size_changed)
+ return 1;
+ return retval == 1 && retval != -1;
}
-CtxEvent *ctx_get_event (Ctx *ctx)
+const char *ctx_nct_get_event (Ctx *n, int timeoutms, int *x, int *y)
{
- static CtxEvent event_copy;
- _ctx_idle_iteration (ctx);
- if (!ctx->events.ctx_get_event_enabled)
- ctx->events.ctx_get_event_enabled = 1;
+ unsigned char buf[20];
+ int length;
- ctx_consume_events (ctx);
- if (ctx->events.events)
+ if (x) *x = -1;
+ if (y) *y = -1;
+
+ if (!signal_installed)
{
- event_copy = *((CtxEvent*)(ctx->events.events->data));
- ctx_list_remove (&ctx->events.events, ctx->events.events->data);
- return &event_copy;
+ _nc_raw ();
+ signal_installed = 1;
+ signal (SIGWINCH, nc_resize_term);
}
- return NULL;
-}
+ if (mouse_mode) // XXX too often to do it all the time!
+ printf("%s", mouse_modes[mouse_mode]);
-static int
-_ctx_emit_cb (Ctx *ctx, CtxList *items, CtxEvent *event, CtxEventType type, float x, float y)
-{
- CtxList *l;
- event->stop_propagate = 0;
- for (l = items; l; l = l->next)
{
- _ctx_emit_cb_item (ctx, l->data, event, type, x, y);
- if (event->stop_propagate)
- return event->stop_propagate;
+ int elapsed = 0;
+ int got_event = 0;
+
+ do {
+ if (size_changed)
+ {
+ size_changed = 0;
+ return "size-changed";
+ }
+ got_event = mouse_has_event (n);
+ if (!got_event)
+ got_event = ctx_has_event (n, MIN(DELAY_MS, timeoutms-elapsed));
+ if (size_changed)
+ {
+ size_changed = 0;
+ return "size-changed";
+ }
+ /* only do this if the client has asked for idle events,
+ * and perhaps programmed the ms timer?
+ */
+ elapsed += MIN(DELAY_MS, timeoutms-elapsed);
+ if (!got_event && timeoutms && elapsed >= timeoutms)
+ return "idle";
+ } while (!got_event);
}
- return 0;
+
+ if (mouse_has_event (n))
+ return mouse_get_event (n, x, y);
+
+ for (length = 0; length < 10; length ++)
+ if (read (STDIN_FILENO, &buf[length], 1) != -1)
+ {
+ const NcKeyCode *match = NULL;
+
+ /* special case ESC, so that we can use it alone in keybindings */
+ if (length == 0 && buf[0] == 27)
+ {
+ struct timeval tv;
+ fd_set rfds;
+ FD_ZERO (&rfds);
+ FD_SET (STDIN_FILENO, &rfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000 * DELAY_MS;
+ if (select (1, &rfds, NULL, NULL, &tv) == 0)
+ return "esc";
+ }
+
+ switch (match_keycode ((const char*)buf, length + 1, &match))
+ {
+ case 1: /* unique match */
+ if (!match)
+ return NULL;
+ if (!strcmp(match->nick, "ok"))
+ {
+ ctx_frame_ack = 1;
+ return NULL;
+ }
+ 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;
+ switch (buf[3])
+ {
+ /* XXX : todo reduce this to less string constants */
+ case 32: return "mouse-press";
+ case 33: return "mouse1-press";
+ case 34: return "mouse2-press";
+ case 40: return "alt-mouse-press";
+ case 41: return "alt-mouse1-press";
+ case 42: return "alt-mouse2-press";
+ case 48: return "control-mouse-press";
+ case 49: return "control-mouse1-press";
+ case 50: return "control-mouse2-press";
+ case 56: return "alt-control-mouse-press";
+ case 57: return "alt-control-mouse1-press";
+ case 58: return "alt-control-mouse2-press";
+ case 64: return "mouse-drag";
+ case 65: return "mouse1-drag";
+ case 66: return "mouse2-drag";
+ case 71: return "mouse-motion"; /* shift+motion */
+ case 72: return "alt-mouse-drag";
+ case 73: return "alt-mouse1-drag";
+ case 74: return "alt-mouse2-drag";
+ case 75: return "mouse-motion"; /* alt+motion */
+ case 80: return "control-mouse-drag";
+ case 81: return "control-mouse1-drag";
+ case 82: return "control-mouse2-drag";
+ case 83: return "mouse-motion"; /* ctrl+motion */
+ case 91: return "mouse-motion"; /* ctrl+alt+motion */
+ case 95: return "mouse-motion"; /* ctrl+alt+shift+motion */
+ case 96: return "scroll-up";
+ case 97: return "scroll-down";
+ case 100: return "shift-scroll-up";
+ case 101: return "shift-scroll-down";
+ case 104: return "alt-scroll-up";
+ case 105: return "alt-scroll-down";
+ case 112: return "control-scroll-up";
+ case 113: return "control-scroll-down";
+ case 116: return "control-shift-scroll-up";
+ case 117: return "control-shift-scroll-down";
+ case 35: /* (or release) */
+ case 51: /* (or ctrl-release) */
+ case 43: /* (or alt-release) */
+ case 67: return "mouse-motion";
+ /* have a separate mouse-drag ? */
+ default: {
+ static char rbuf[100];
+ sprintf (rbuf, "mouse (unhandled state: %i)", buf[3]);
+ return rbuf;
+ }
+ }
+ case 0: /* no matches, bail*/
+ {
+ static char ret[256];
+ if (length == 0 && ctx_utf8_len (buf[0])>1) /* single unicode
+ char */
+ {
+ int n_read =
+ read (STDIN_FILENO, &buf[length+1], ctx_utf8_len(buf[0])-1);
+ if (n_read)
+ {
+ buf[ctx_utf8_len(buf[0])]=0;
+ strcpy (ret, (const char*)buf);
+ }
+ return ret;
+ }
+ if (length == 0) /* ascii */
+ {
+ buf[1]=0;
+ strcpy (ret, (const char*)buf);
+ return ret;
+ }
+ sprintf (ret, "unhandled %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c'",
+ length>=0? buf[0]: 0, length>=0? buf[0]>31?buf[0]:'?': ' ',
+ length>=1? buf[1]: 0, length>=1? buf[1]>31?buf[1]:'?': ' ',
+ length>=2? buf[2]: 0, length>=2? buf[2]>31?buf[2]:'?': ' ',
+ length>=3? buf[3]: 0, length>=3? buf[3]>31?buf[3]:'?': ' ',
+ length>=4? buf[4]: 0, length>=4? buf[4]>31?buf[4]:'?': ' ',
+ length>=5? buf[5]: 0, length>=5? buf[5]>31?buf[5]:'?': ' ',
+ length>=6? buf[6]: 0, length>=6? buf[6]>31?buf[6]:'?': ' ');
+ return ret;
+ }
+ return NULL;
+ default: /* continue */
+ break;
+ }
+ }
+ else
+ return "key read eek";
+ return "fail";
}
-/*
- * update what is the currently hovered item and returns it.. and the list of hits
- * a well.
- *
- */
-static CtxItem *_ctx_update_item (Ctx *ctx, int device_no, float x, float y, CtxEventType type, CtxList
**hitlist)
+int ctx_nct_consume_events (Ctx *ctx)
{
- CtxItem *current = NULL;
-
- CtxList *l = _ctx_detect_list (ctx, x, y, type);
- if (l)
- {
- ctx_list_reverse (&l);
- current = l->data;
- }
- if (hitlist)
- *hitlist = l;
- else
- ctx_list_free (&l);
+ int ix, iy;
+ CtxCtx *ctxctx = (CtxCtx*)ctx->renderer;
+ const char *event = NULL;
- if (ctx->events.prev[device_no] == NULL || current == NULL || (current->path_hash !=
ctx->events.prev[device_no]->path_hash))
{
-// enter/leave should snapshot chain to root
-// and compare with previous snapshotted chain to root
-// and emit/enter/leave as appropriate..
-//
-// leave might be registered for emission on enter..emission?
-
+ float x, y;
+ event = ctx_nct_get_event (ctx, 50, &ix, &iy);
- //int focus_radius = 2;
- if (current)
- _ctx_item_ref (current);
+ x = (ix - 1.0 + 0.5) / ctxctx->cols * ctx->events.width;
+ y = (iy - 1.0) / ctxctx->rows * ctx->events.height;
- if (ctx->events.prev[device_no])
+ if (!strcmp (event, "mouse-press"))
{
- {
-#if 0
- CtxRectangle rect = {floor(ctx->events.prev[device_no]->x0-focus_radius),
- floor(ctx->events.prev[device_no]->y0-focus_radius),
- ceil(ctx->events.prev[device_no]->x1)-floor(ctx->events.prev[device_no]->x0) +
focus_radius * 2,
- ceil(ctx->events.prev[device_no]->y1)-floor(ctx->events.prev[device_no]->y0) +
focus_radius * 2};
- mrg_queue_draw (mrg, &rect);
-#endif
+ ctx_pointer_press (ctx, x, y, 0, 0);
+ ctxctx->was_down = 1;
+ } else if (!strcmp (event, "mouse-release"))
+ {
+ ctx_pointer_release (ctx, x, y, 0, 0);
+ ctxctx->was_down = 0;
+ } else if (!strcmp (event, "mouse-motion"))
+ {
+ //nct_set_cursor_pos (backend->term, ix, iy);
+ //nct_flush (backend->term);
+ if (ctxctx->was_down)
+ {
+ ctx_pointer_release (ctx, x, y, 0, 0);
+ ctxctx->was_down = 0;
}
+ ctx_pointer_motion (ctx, x, y, 0, 0);
+ } else if (!strcmp (event, "mouse-drag"))
+ {
+ ctx_pointer_motion (ctx, x, y, 0, 0);
+ } else if (!strcmp (event, "size-changed"))
+ {
+#if 0
+ int width = nct_sys_terminal_width ();
+ int height = nct_sys_terminal_height ();
+ 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);
+ mrg_set_size (mrg, width, height);
+ mrg_queue_draw (mrg, NULL);
+#endif
- _ctx_emit_cb_item (ctx, ctx->events.prev[device_no], NULL, CTX_LEAVE, x, y);
- _ctx_item_unref (ctx->events.prev[device_no]);
- ctx->events.prev[device_no] = NULL;
}
- if (current)
+ else
{
-#if 0
+ if (!strcmp (event, "esc"))
+ ctx_key_press (ctx, 0, "escape", 0);
+ else if (!strcmp (event, "space"))
+ ctx_key_press (ctx, 0, "space", 0);
+ else if (!strcmp (event, "enter"))
+ ctx_key_press (ctx, 0, "\n", 0);
+ else if (!strcmp (event, "return"))
+ ctx_key_press (ctx, 0, "return", 0);
+ else if (!strcmp (event, "idle"))
{
- CtxRectangle rect = {floor(current->x0-focus_radius),
- floor(current->y0-focus_radius),
- ceil(current->x1)-floor(current->x0) + focus_radius * 2,
- ceil(current->y1)-floor(current->y0) + focus_radius * 2};
- mrg_queue_draw (mrg, &rect);
}
-#endif
- _ctx_emit_cb_item (ctx, current, NULL, CTX_ENTER, x, y);
- ctx->events.prev[device_no] = current;
+ else
+ ctx_key_press (ctx, 0, event, 0);
}
}
- current = _ctx_detect (ctx, x, y, type);
- //fprintf (stderr, "%p\n", current);
- return current;
+
+ return 1;
}
-static int tap_and_hold_fire (Ctx *ctx, void *data)
+const char *ctx_native_get_event (Ctx *n, int timeoutms)
{
- CtxGrab *grab = data;
- CtxList *list = NULL;
- ctx_list_prepend (&list, grab->item);
- CtxEvent event = {0, };
-
- event.ctx = ctx;
- event.time = ctx_ms (ctx);
-
- event.device_x =
- event.x = ctx->events.pointer_x[grab->device_no];
- event.device_y =
- event.y = ctx->events.pointer_y[grab->device_no];
-
- // XXX: x and y coordinates
- int ret = _ctx_emit_cb (ctx, list, &event, CTX_TAP_AND_HOLD,
- ctx->events.pointer_x[grab->device_no], ctx->events.pointer_y[grab->device_no]);
+ static unsigned char buf[256];
+ int length;
- ctx_list_free (&list);
+ if (!signal_installed)
+ {
+ _nc_raw ();
+ signal_installed = 1;
+ signal (SIGWINCH, nc_resize_term);
+ }
+//if (mouse_mode) // XXX too often to do it all the time!
+// printf("%s", mouse_modes[mouse_mode]);
- grab->timeout_id = 0;
+ int got_event = 0;
+ {
+ int elapsed = 0;
- return 0;
+ do {
+ if (size_changed)
+ {
+ size_changed = 0;
+ return "size-changed";
+ }
+ got_event = ctx_has_event (n, MIN(DELAY_MS, timeoutms-elapsed));
+ if (size_changed)
+ {
+ size_changed = 0;
+ return "size-changed";
+ }
+ /* only do this if the client has asked for idle events,
+ * and perhaps programmed the ms timer?
+ */
+ elapsed += MIN(DELAY_MS, timeoutms-elapsed);
+ if (!got_event && timeoutms && elapsed >= timeoutms)
+ {
+ return "idle";
+ }
+ } while (!got_event);
+ }
- return ret;
+ for (length = 0; got_event && length < 200; length ++)
+ {
+ if (read (STDIN_FILENO, &buf[length], 1) != -1)
+ {
+ buf[length+1] = 0;
+ if (!strcmp ((char*)buf, "\e[0n"))
+ {
+ ctx_frame_ack = 1;
+ return NULL;
+ }
+ else if (buf[length]=='\n')
+ {
+ buf[length]=0;
+ return (const char*)buf;
+ }
+ }
+ got_event = ctx_has_event (n, 5);
+ }
+ return NULL;
}
-int ctx_pointer_drop (Ctx *ctx, float x, float y, int device_no, uint32_t time,
- char *string)
+const char *ctx_key_get_label (Ctx *n, const char *nick)
{
- CtxList *l;
- CtxList *hitlist = NULL;
+ int j;
+ int found = -1;
+ for (j = 0; keycodes[j].nick; j++)
+ if (found == -1 && !strcmp (keycodes[j].nick, nick))
+ return keycodes[j].label;
+ return NULL;
+}
- ctx->events.pointer_x[device_no] = x;
- ctx->events.pointer_y[device_no] = y;
- if (device_no <= 3)
+void _ctx_mouse (Ctx *term, int mode)
+{
+ //if (term->is_st && mode > 1)
+ // mode = 1;
+ if (mode != mouse_mode)
{
- ctx->events.pointer_x[0] = x;
- ctx->events.pointer_y[0] = y;
+ printf ("%s", mouse_modes[mode]);
+ fflush (stdout);
}
+ mouse_mode = mode;
+}
- if (device_no < 0) device_no = 0;
- if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
- CtxEvent *event = &ctx->events.drag_event[device_no];
-
- if (time == 0)
- time = ctx_ms (ctx);
- event->ctx = ctx;
- event->x = x;
- event->y = y;
+#endif
- event->delta_x = event->delta_y = 0;
+#include <sys/time.h>
- event->device_no = device_no;
- event->string = string;
- event->time = time;
- event->stop_propagate = 0;
- _ctx_update_item (ctx, device_no, x, y, CTX_DROP, &hitlist);
+#define usecs(time) ((uint64_t)(time.tv_sec - start_time.tv_sec) * 1000000 + time. tv_usec)
- for (l = hitlist; l; l = l?l->next:NULL)
- {
- CtxItem *item = l->data;
- _ctx_emit_cb_item (ctx, item, event, CTX_DROP, x, y);
+#if CTX_EVENTS
+#include <threads.h>
+static struct timeval start_time;
- if (event->stop_propagate)
- {
- ctx_list_free (&hitlist);
- return 0;
- }
- }
+static void
+_ctx_init_ticks (void)
+{
+ static int done = 0;
+ if (done)
+ return;
+ done = 1;
+ gettimeofday (&start_time, NULL);
+}
- //mrg_queue_draw (mrg, NULL); /* in case of style change, and more */
- ctx_list_free (&hitlist);
+static inline unsigned long
+_ctx_ticks (void)
+{
+ struct timeval measure_time;
+ gettimeofday (&measure_time, NULL);
+ return usecs (measure_time) - usecs (start_time);
+}
- return 0;
+unsigned long
+ctx_ticks (void)
+{
+ _ctx_init_ticks ();
+ return _ctx_ticks ();
}
-int ctx_pointer_press (Ctx *ctx, float x, float y, int device_no, uint32_t time)
+uint32_t ctx_ms (Ctx *ctx)
{
- CtxEvents *events = &ctx->events;
- CtxList *hitlist = NULL;
- events->pointer_x[device_no] = x;
- events->pointer_y[device_no] = y;
- if (device_no <= 3)
- {
- events->pointer_x[0] = x;
- events->pointer_y[0] = y;
- }
+ return _ctx_ticks () / 1000;
+}
- if (device_no < 0) device_no = 0;
- if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
- CtxEvent *event = &events->drag_event[device_no];
- if (time == 0)
- time = ctx_ms (ctx);
+typedef enum _CtxFlags CtxFlags;
- event->x = event->start_x = event->prev_x = x;
- event->y = event->start_y = event->prev_y = y;
+enum _CtxFlags {
+ CTX_FLAG_DIRECT = (1<<0),
+};
- event->delta_x = event->delta_y = 0;
- event->device_no = device_no;
- event->time = time;
- event->stop_propagate = 0;
+int _ctx_max_threads = 1;
+int _ctx_enable_hash_cache = 1;
- if (events->pointer_down[device_no] == 1)
- {
- fprintf (stderr, "events thought device %i was already down\n", device_no);
- }
- /* doing just one of these two should be enough? */
- events->pointer_down[device_no] = 1;
- switch (device_no)
- {
- case 1:
- events->modifier_state |= CTX_MODIFIER_STATE_BUTTON1;
- break;
- case 2:
- events->modifier_state |= CTX_MODIFIER_STATE_BUTTON2;
- break;
- case 3:
- events->modifier_state |= CTX_MODIFIER_STATE_BUTTON3;
- break;
- default:
- break;
- }
-
- CtxGrab *grab = NULL;
- CtxList *l;
+static mtx_t _ctx_texture_mtx;
- _ctx_update_item (ctx, device_no, x, y,
- CTX_PRESS | CTX_DRAG_PRESS | CTX_TAP | CTX_TAP_AND_HOLD, &hitlist);
+void _ctx_texture_lock (void)
+{
+ mtx_lock (&_ctx_texture_mtx);
+}
- for (l = hitlist; l; l = l?l->next:NULL)
- {
- CtxItem *item = l->data;
- if (item &&
- ((item->types & CTX_DRAG)||
- (item->types & CTX_TAP) ||
- (item->types & CTX_TAP_AND_HOLD)))
- {
- grab = device_add_grab (ctx, device_no, item, item->types);
- grab->start_time = time;
+void _ctx_texture_unlock (void)
+{
+ mtx_unlock (&_ctx_texture_mtx);
+}
- if (item->types & CTX_TAP_AND_HOLD)
- {
- grab->timeout_id = ctx_add_timeout (ctx, events->tap_delay_hold, tap_and_hold_fire, grab);
- }
- }
- _ctx_emit_cb_item (ctx, item, event, CTX_PRESS, x, y);
- if (!event->stop_propagate)
- _ctx_emit_cb_item (ctx, item, event, CTX_DRAG_PRESS, x, y);
- if (event->stop_propagate)
+void
+ctx_init (int *argc, char ***argv)
+{
+#if 0
+ if (!getenv ("CTX_VERSION"))
+ {
+ int i;
+ char *new_argv[*argc+3];
+ new_argv[0] = "ctx";
+ for (i = 0; i < *argc; i++)
{
- ctx_list_free (&hitlist);
- return 0;
+ new_argv[i+1] = *argv[i];
}
+ new_argv[i+1] = NULL;
+ execvp (new_argv[0], new_argv);
+ // if this fails .. we continue normal startup
+ // and end up in self-hosted braille
}
-
- //events_queue_draw (mrg, NULL); /* in case of style change, and more */
- ctx_list_free (&hitlist);
- return 0;
+#endif
}
-void _ctx_resized (Ctx *ctx, int width, int height, long time)
+int ctx_count (Ctx *ctx)
{
- CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_DOWN);
- CtxEvent event = {0, };
+ return ctx->drawlist.count;
+}
- if (!time)
- time = ctx_ms (ctx);
+
+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);
+ tcdrain(STDIN_FILENO);
+ 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;
- event.ctx = ctx;
- event.time = time;
- event.string = "resize-event"; /* gets delivered to clients as a key_down event, maybe message shouldbe
used instead?
- */
+ FD_ZERO(&rfds);
+ FD_SET(0, &rfds);
+ tv.tv_usec = 1000 * 5;
- if (item)
+ for (int n = 0; select(1, &rfds, NULL, NULL, &tv) && n < 20; n++)
{
- event.stop_propagate = 0;
- _ctx_emit_cb_item (ctx, item, &event, CTX_KEY_DOWN, 0, 0);
+ 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;
}
-int ctx_pointer_release (Ctx *ctx, float x, float y, int device_no, uint32_t time)
+Ctx *ctx_new_ui (int width, int height)
{
- CtxEvents *events = &ctx->events;
- if (time == 0)
- time = ctx_ms (ctx);
-
- if (device_no < 0) device_no = 0;
- if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
- CtxEvent *event = &events->drag_event[device_no];
+ if (getenv ("CTX_HASH_CACHE"))
+ {
+ const char * val = getenv ("CTX_HASH_CACHE");
+ if (!strcmp (val, "0"))
+ _ctx_enable_hash_cache = 0;
+ if (!strcmp (val, "off"))
+ _ctx_enable_hash_cache = 0;
+ }
- event->time = time;
- event->x = x;
- event->ctx = ctx;
- event->y = y;
- event->device_no = device_no;
- event->stop_propagate = 0;
- switch (device_no)
+ if (getenv ("CTX_THREADS"))
{
- case 1:
- if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON1)
- events->modifier_state -= CTX_MODIFIER_STATE_BUTTON1;
- break;
- case 2:
- if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON2)
- events->modifier_state -= CTX_MODIFIER_STATE_BUTTON2;
- break;
- case 3:
- if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON3)
- events->modifier_state -= CTX_MODIFIER_STATE_BUTTON3;
- break;
- default:
- break;
+ int val = atoi (getenv ("CTX_THREADS"));
+ _ctx_max_threads = val;
+ }
+ else
+ {
+ _ctx_max_threads = 2;
+#ifdef _SC_NPROCESSORS_ONLN
+ _ctx_max_threads = sysconf (_SC_NPROCESSORS_ONLN) / 2;
+#endif
}
+
+#if CTX_EVENTS
+ mtx_init (&_ctx_texture_mtx, mtx_plain);
+#endif
- //events_queue_draw (mrg, NULL); /* in case of style change */
+ if (_ctx_max_threads < 1) _ctx_max_threads = 1;
+ if (_ctx_max_threads > CTX_MAX_THREADS) _ctx_max_threads = CTX_MAX_THREADS;
- if (events->pointer_down[device_no] == 0)
+ //fprintf (stderr, "ctx using %i threads\n", _ctx_max_threads);
+ const char *backend = getenv ("CTX_BACKEND");
+
+ if (backend && !strcmp (backend, ""))
+ backend = NULL;
+ if (backend && !strcmp (backend, "auto"))
+ backend = NULL;
+ if (backend && !strcmp (backend, "list"))
{
- fprintf (stderr, "device %i already up\n", device_no);
+ fprintf (stderr, "possible values for CTX_BACKEND:\n");
+ fprintf (stderr, " ctx");
+#if CTX_SDL
+ fprintf (stderr, " SDL");
+#endif
+#if CTX_FB
+ fprintf (stderr, " fb");
+ fprintf (stderr, " drm");
+#endif
+ fprintf (stderr, " term");
+ fprintf (stderr, " termimg");
+ fprintf (stderr, "\n");
+ exit (-1);
}
- events->pointer_down[device_no] = 0;
- events->pointer_x[device_no] = x;
- events->pointer_y[device_no] = y;
- if (device_no <= 3)
+ Ctx *ret = NULL;
+
+ /* we do the query on auto but not on directly set ctx
+ *
+ */
+ if ((backend && !strcmp(backend, "ctx")) ||
+ (backend == NULL && is_in_ctx ()))
{
- events->pointer_x[0] = x;
- events->pointer_y[0] = y;
+ if (!backend || !strcmp (backend, "ctx"))
+ {
+ // full blown ctx protocol - in terminal or standalone
+ ret = ctx_new_ctx (width, height);
+ }
}
- CtxList *hitlist = NULL;
- CtxList *grablist = NULL , *g= NULL;
- CtxGrab *grab;
- _ctx_update_item (ctx, device_no, x, y, CTX_RELEASE | CTX_DRAG_RELEASE, &hitlist);
- grablist = device_get_grabs (ctx, device_no);
+#if CTX_SDL
+ if (!ret && getenv ("DISPLAY"))
+ {
+ if ((backend==NULL) || (!strcmp (backend, "SDL")))
+ ret = ctx_new_sdl (width, height);
+ }
+#endif
- for (g = grablist; g; g = g->next)
+#if CTX_FB
+ if (!ret && !getenv ("DISPLAY"))
{
- grab = g->data;
+ if ((backend==NULL) || (!strcmp (backend, "drm")))
+ ret = ctx_new_fb (width, height, 1);
- if (!event->stop_propagate)
+ if (!ret)
{
- if (grab->item->types & CTX_TAP)
- {
- long delay = time - grab->start_time;
-
- if (delay > events->tap_delay_min &&
- delay < events->tap_delay_max &&
- (
- (event->start_x - x) * (event->start_x - x) +
- (event->start_y - y) * (event->start_y - y)) < ctx_pow2(events->tap_hysteresis)
- )
- {
- _ctx_emit_cb_item (ctx, grab->item, event, CTX_TAP, x, y);
- }
- }
-
- if (!event->stop_propagate && grab->item->types & CTX_DRAG_RELEASE)
- {
- _ctx_emit_cb_item (ctx, grab->item, event, CTX_DRAG_RELEASE, x, y);
- }
+ if ((backend==NULL) || (!strcmp (backend, "fb")))
+ ret = ctx_new_fb (width, height, 0);
}
-
- device_remove_grab (ctx, grab);
}
+#endif
- if (hitlist)
+#if CTX_RASTERIZER
+ // braille in terminal
+ if (!ret)
{
- if (!event->stop_propagate)
- _ctx_emit_cb (ctx, hitlist, event, CTX_RELEASE, x, y);
- ctx_list_free (&hitlist);
+ if ((backend==NULL) || (!strcmp (backend, "term")))
+ ret = ctx_new_term (width, height);
}
- ctx_list_free (&grablist);
- return 0;
+ if (!ret)
+ {
+ if ((backend==NULL) || (!strcmp (backend, "termimg")))
+ ret = ctx_new_termimg (width, height);
+ }
+#endif
+ if (!ret)
+ {
+ fprintf (stderr, "no interactive ctx backend\n");
+ exit (2);
+ }
+ ctx_get_event (ret); // enables events
+ return ret;
}
-
-/* for multi-touch, we use a list of active grabs - thus a grab corresponds to
- * a device id. even during drag-grabs events propagate; to stop that stop
- * propagation.
- */
-int ctx_pointer_motion (Ctx *ctx, float x, float y, int device_no, uint32_t time)
+#else
+void _ctx_texture_unlock (void)
{
- CtxList *hitlist = NULL;
- CtxList *grablist = NULL, *g;
- CtxGrab *grab;
-
- if (device_no < 0) device_no = 0;
- if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
- CtxEvent *event = &ctx->events.drag_event[device_no];
-
- if (time == 0)
- time = ctx_ms (ctx);
+}
+void _ctx_texture_lock (void)
+{
+}
- event->ctx = ctx;
- event->x = x;
- event->y = y;
- event->time = time;
- event->device_no = device_no;
- event->stop_propagate = 0;
-
- ctx->events.pointer_x[device_no] = x;
- ctx->events.pointer_y[device_no] = y;
+#endif
+void _ctx_resized (Ctx *ctx, int width, int height, long time);
- if (device_no <= 3)
+void ctx_set_size (Ctx *ctx, int width, int height)
+{
+#if CTX_EVENTS
+ if (ctx->events.width != width || ctx->events.height != height)
{
- ctx->events.pointer_x[0] = x;
- ctx->events.pointer_y[0] = y;
+ ctx->events.width = width;
+ ctx->events.height = height;
+ _ctx_resized (ctx, width, height, 0);
}
+#endif
+}
- grablist = device_get_grabs (ctx, device_no);
- _ctx_update_item (ctx, device_no, x, y, CTX_MOTION, &hitlist);
+#if CTX_EVENTS
+typedef struct CtxIdleCb {
+ int (*cb) (Ctx *ctx, void *idle_data);
+ void *idle_data;
- {
- CtxItem *cursor_item = _ctx_detect (ctx, x, y, CTX_SET_CURSOR);
- if (cursor_item)
- {
- ctx_set_cursor (ctx, cursor_item->cursor);
- }
- else
- {
- ctx_set_cursor (ctx, CTX_CURSOR_ARROW);
- }
- CtxItem *hovered_item = _ctx_detect (ctx, x, y, CTX_ANY);
- static CtxItem *prev_hovered_item = NULL;
- if (prev_hovered_item != hovered_item)
- {
- ctx_set_dirty (ctx, 1);
- }
- prev_hovered_item = hovered_item;
- }
+ void (*destroy_notify)(void *destroy_data);
+ void *destroy_data;
- event->delta_x = x - event->prev_x;
- event->delta_y = y - event->prev_y;
- event->prev_x = x;
- event->prev_y = y;
+ int ticks_full;
+ int ticks_remaining;
+ int is_idle;
+ int id;
+} CtxIdleCb;
- CtxList *remove_grabs = NULL;
+void _ctx_events_init (Ctx *ctx)
+{
+ CtxEvents *events = &ctx->events;
+ _ctx_init_ticks ();
+ events->tap_delay_min = 40;
+ events->tap_delay_max = 800;
+ events->tap_delay_max = 8000000; /* quick reflexes needed making it hard for some is an argument against
very short values */
- for (g = grablist; g; g = g->next)
+ events->tap_delay_hold = 1000;
+ events->tap_hysteresis = 32; /* XXX: should be ppi dependent */
+}
+
+
+void _ctx_idle_iteration (Ctx *ctx)
+{
+ static unsigned long prev_ticks = 0;
+ CtxList *l;
+ CtxList *to_remove = NULL;
+ unsigned long ticks = _ctx_ticks ();
+ unsigned long tick_delta = (prev_ticks == 0) ? 0 : ticks - prev_ticks;
+ prev_ticks = ticks;
+
+ if (!ctx->events.idles)
{
- grab = g->data;
+ return;
+ }
+ for (l = ctx->events.idles; l; l = l->next)
+ {
+ CtxIdleCb *item = l->data;
- if ((grab->type & CTX_TAP) ||
- (grab->type & CTX_TAP_AND_HOLD))
- {
- if (
- (
- (event->start_x - x) * (event->start_x - x) +
- (event->start_y - y) * (event->start_y - y)) >
- ctx_pow2(ctx->events.tap_hysteresis)
- )
- {
- //fprintf (stderr, "-");
- ctx_list_prepend (&remove_grabs, grab);
- }
- else
- {
- //fprintf (stderr, ":");
- }
- }
+ if (item->ticks_remaining >= 0)
+ item->ticks_remaining -= tick_delta;
- if (grab->type & CTX_DRAG_MOTION)
+ if (item->ticks_remaining < 0)
{
- _ctx_emit_cb_item (ctx, grab->item, event, CTX_DRAG_MOTION, x, y);
- if (event->stop_propagate)
- break;
+ if (item->cb (ctx, item->idle_data) == 0)
+ ctx_list_prepend (&to_remove, item);
+ else
+ item->ticks_remaining = item->ticks_full;
}
}
- if (remove_grabs)
+ for (l = to_remove; l; l = l->next)
{
- for (g = remove_grabs; g; g = g->next)
- device_remove_grab (ctx, g->data);
- ctx_list_free (&remove_grabs);
+ CtxIdleCb *item = l->data;
+ if (item->destroy_notify)
+ item->destroy_notify (item->destroy_data);
+ ctx_list_remove (&ctx->events.idles, l->data);
}
- if (hitlist)
+}
+
+
+void ctx_add_key_binding_full (Ctx *ctx,
+ const char *key,
+ const char *action,
+ const char *label,
+ CtxCb cb,
+ void *cb_data,
+ CtxDestroyNotify destroy_notify,
+ void *destroy_data)
+{
+ CtxEvents *events = &ctx->events;
+ if (events->n_bindings +1 >= CTX_MAX_KEYBINDINGS)
{
- if (!event->stop_propagate)
- _ctx_emit_cb (ctx, hitlist, event, CTX_MOTION, x, y);
- ctx_list_free (&hitlist);
+ fprintf (stderr, "warning: binding overflow\n");
+ return;
}
- ctx_list_free (&grablist);
- return 0;
+ events->bindings[events->n_bindings].nick = strdup (key);
+ strcpy (events->bindings[events->n_bindings].nick, key);
+
+ if (action)
+ events->bindings[events->n_bindings].command = action ? strdup (action) : NULL;
+ if (label)
+ events->bindings[events->n_bindings].label = label ? 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;
+ events->bindings[events->n_bindings].destroy_data = destroy_data;
+ events->n_bindings++;
}
-void ctx_incoming_message (Ctx *ctx, const char *message, long time)
+void ctx_add_key_binding (Ctx *ctx,
+ const char *key,
+ const char *action,
+ const char *label,
+ CtxCb cb,
+ void *cb_data)
{
- CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_MESSAGE);
- CtxEvent event = {0, };
-
- if (!time)
- time = ctx_ms (ctx);
+ ctx_add_key_binding_full (ctx, key, action, label, cb, cb_data, NULL, NULL);
+}
- if (item)
+void ctx_clear_bindings (Ctx *ctx)
+{
+ CtxEvents *events = &ctx->events;
+ int i;
+ for (i = 0; events->bindings[i].nick; i ++)
{
- int i;
- event.ctx = ctx;
- event.type = CTX_MESSAGE;
- event.time = time;
- event.string = message;
+ if (events->bindings[i].destroy_notify)
+ events->bindings[i].destroy_notify (events->bindings[i].destroy_data);
+ free (events->bindings[i].nick);
+ if (events->bindings[i].command)
+ free (events->bindings[i].command);
+ if (events->bindings[i].label)
+ free (events->bindings[i].label);
+ }
+ memset (&events->bindings, 0, sizeof (events->bindings));
+ events->n_bindings = 0;
+}
- fprintf (stderr, "{%s|\n", message);
+static void
+ctx_collect_events (CtxEvent *event, void *data, void *data2);
+static void _ctx_bindings_key_press (CtxEvent *event, void *data1, void *data2)
+{
+ Ctx *ctx = event->ctx;
+ CtxEvents *events = &ctx->events;
+ int i;
+ int handled = 0;
- for (i = 0; i < item->cb_count; i++)
+ for (i = events->n_bindings-1; i>=0; i--)
+ if (!strcmp (events->bindings[i].nick, event->string))
+ {
+ if (events->bindings[i].cb)
{
- if (item->cb[i].types & (CTX_MESSAGE))
- {
- event.state = ctx->events.modifier_state;
- item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
- if (event.stop_propagate)
- return;// event.stop_propagate;
- }
+ events->bindings[i].cb (event, events->bindings[i].cb_data, NULL);
+ if (event->stop_propagate)
+ return;
+ handled = 1;
}
- }
+ }
+ if (!handled)
+ for (i = events->n_bindings-1; i>=0; i--)
+ if (!strcmp (events->bindings[i].nick, "unhandled"))
+ {
+ if (events->bindings[i].cb)
+ {
+ events->bindings[i].cb (event, events->bindings[i].cb_data, NULL);
+ if (event->stop_propagate)
+ return;
+ }
+ }
+ ctx_collect_events (event, data1, data2);
}
-int ctx_scrolled (Ctx *ctx, float x, float y, CtxScrollDirection scroll_direction, uint32_t time)
+CtxBinding *ctx_get_bindings (Ctx *ctx)
{
- CtxList *hitlist = NULL;
- CtxList *l;
+ return &ctx->events.bindings[0];
+}
- int device_no = 0;
- ctx->events.pointer_x[device_no] = x;
- ctx->events.pointer_y[device_no] = y;
+void ctx_remove_idle (Ctx *ctx, int handle)
+{
+ CtxList *l;
+ CtxList *to_remove = NULL;
- CtxEvent *event = &ctx->events.drag_event[device_no]; /* XXX: might
- conflict with other code
- create a sibling member
- of drag_event?*/
- if (time == 0)
- time = ctx_ms (ctx);
-
- event->x = event->start_x = event->prev_x = x;
- event->y = event->start_y = event->prev_y = y;
- event->delta_x = event->delta_y = 0;
- event->device_no = device_no;
- event->time = time;
- event->stop_propagate = 0;
- event->scroll_direction = scroll_direction;
-
- _ctx_update_item (ctx, device_no, x, y, CTX_SCROLL, &hitlist);
-
- for (l = hitlist; l; l = l?l->next:NULL)
- {
- CtxItem *item = l->data;
-
- _ctx_emit_cb_item (ctx, item, event, CTX_SCROLL, x, y);
-
- if (event->stop_propagate)
- l = NULL;
- }
-
- //mrg_queue_draw (mrg, NULL); /* in case of style change, and more */
- ctx_list_free (&hitlist);
- return 0;
-}
-
-int ctx_key_press (Ctx *ctx, unsigned int keyval,
- const char *string, uint32_t time)
-{
- char event_type[128]="";
- float x, y; int b;
- sscanf (string, "%s %f %f %i", event_type, &x, &y, &b);
- if (!strcmp (event_type, "mouse-motion") ||
- !strcmp (event_type, "mouse-drag"))
- {
- ctx_pointer_motion (ctx, x, y, b, 0);
- return 0;
- }
- else if (!strcmp (event_type, "mouse-press"))
+ if (!ctx->events.idles)
{
- ctx_pointer_press (ctx, x, y, b, 0);
- return 0;
+ return;
}
- else if (!strcmp (event_type, "mouse-release"))
+ for (l = ctx->events.idles; l; l = l->next)
{
- ctx_pointer_release (ctx, x, y, b, 0);
- return 0;
+ CtxIdleCb *item = l->data;
+ if (item->id == handle)
+ ctx_list_prepend (&to_remove, item);
}
-
-
- CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_DOWN);
- CtxEvent event = {0,};
-
- if (time == 0)
- time = ctx_ms (ctx);
- if (item)
+ for (l = to_remove; l; l = l->next)
{
- int i;
- event.ctx = ctx;
- event.type = CTX_KEY_DOWN;
- event.unicode = keyval;
- event.string = strdup(string);
- event.stop_propagate = 0;
- event.time = time;
-
- for (i = 0; i < item->cb_count; i++)
- {
- if (item->cb[i].types & (CTX_KEY_DOWN))
- {
- event.state = ctx->events.modifier_state;
- item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
-#if 0
- char buf[256];
- ctx_set (ctx, ctx_strhash ("title", 0), buf, strlen(buf));
- ctx_flush (ctx);
-#endif
- if (event.stop_propagate)
- {
- free ((void*)event.string);
- return event.stop_propagate;
- }
- }
- }
- free ((void*)event.string);
+ CtxIdleCb *item = l->data;
+ if (item->destroy_notify)
+ item->destroy_notify (item->destroy_data);
+ ctx_list_remove (&ctx->events.idles, l->data);
}
- return 0;
}
-void ctx_freeze (Ctx *ctx)
+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)
{
- ctx->events.frozen ++;
+ CtxIdleCb *item = calloc (sizeof (CtxIdleCb), 1);
+ item->cb = idle_cb;
+ item->idle_data = idle_data;
+ item->id = ++ctx->events.idle_id;
+ item->ticks_full =
+ item->ticks_remaining = ms * 1000;
+ item->destroy_notify = destroy_notify;
+ item->destroy_data = destroy_data;
+ ctx_list_append (&ctx->events.idles, item);
+ return item->id;
}
-void ctx_thaw (Ctx *ctx)
-{
- ctx->events.frozen --;
-}
-int ctx_events_frozen (Ctx *ctx)
-{
- return ctx && ctx->events.frozen;
-}
-void ctx_events_clear_items (Ctx *ctx)
-{
- ctx_list_free (&ctx->events.items);
-}
-int ctx_events_width (Ctx *ctx)
-{
- return ctx->events.width;
-}
-int ctx_events_height (Ctx *ctx)
+int ctx_add_timeout (Ctx *ctx, int ms, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data)
{
- return ctx->events.height;
+ return ctx_add_timeout_full (ctx, ms, idle_cb, idle_data, NULL, NULL);
}
-float ctx_pointer_x (Ctx *ctx)
+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)
{
- return ctx->events.pointer_x[0];
+ CtxIdleCb *item = calloc (sizeof (CtxIdleCb), 1);
+ item->cb = idle_cb;
+ item->idle_data = idle_data;
+ item->id = ++ctx->events.idle_id;
+ item->ticks_full =
+ item->ticks_remaining = -1;
+ item->is_idle = 1;
+ item->destroy_notify = destroy_notify;
+ item->destroy_data = destroy_data;
+ ctx_list_append (&ctx->events.idles, item);
+ return item->id;
}
-float ctx_pointer_y (Ctx *ctx)
+int ctx_add_idle (Ctx *ctx, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data)
{
- return ctx->events.pointer_y[0];
+ return ctx_add_idle_full (ctx, idle_cb, idle_data, NULL, NULL);
}
-int ctx_pointer_is_down (Ctx *ctx, int no)
+#endif
+/* using bigger primes would be a good idea, this falls apart due to rounding
+ * when zoomed in close
+ */
+static inline double ctx_path_hash (void *path)
{
- if (no < 0 || no > CTX_MAX_DEVICES) return 0;
- return ctx->events.pointer_down[no];
+ double ret = 0;
+#if 0
+ int i;
+ cairo_path_data_t *data;
+ if (!path)
+ return 0.99999;
+ for (i = 0; i <path->num_data; i += path->data[i].header.length)
+ {
+ data = &path->data[i];
+ switch (data->header.type) {
+ case CAIRO_PATH_MOVE_TO:
+ ret *= 17;
+ ret += data[1].point.x;
+ ret *= 113;
+ ret += data[1].point.y;
+ break;
+ case CAIRO_PATH_LINE_TO:
+ ret *= 121;
+ ret += data[1].point.x;
+ ret *= 1021;
+ ret += data[1].point.y;
+ break;
+ case CAIRO_PATH_CURVE_TO:
+ ret *= 3111;
+ ret += data[1].point.x;
+ ret *= 23;
+ ret += data[1].point.y;
+ ret *= 107;
+ ret += data[2].point.x;
+ ret *= 739;
+ ret += data[2].point.y;
+ ret *= 3;
+ ret += data[3].point.x;
+ ret *= 51;
+ ret += data[3].point.y;
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ ret *= 51;
+ break;
+ }
+ }
+#endif
+ return ret;
}
-void _ctx_debug_overlays (Ctx *ctx)
+#if CTX_EVENTS
+void _ctx_item_ref (CtxItem *item)
{
- CtxList *a;
- ctx_save (ctx);
-
- ctx_line_width (ctx, 2);
- ctx_rgba (ctx, 0,0,0.8,0.5);
- for (a = ctx->events.items; a; a = a->next)
+ if (item->ref_count < 0)
{
- float current_x = ctx_pointer_x (ctx);
- float current_y = ctx_pointer_y (ctx);
- CtxItem *item = a->data;
- CtxMatrix matrix = item->inv_matrix;
+ fprintf (stderr, "EEEEK!\n");
+ }
+ item->ref_count++;
+}
- ctx_matrix_apply_transform (&matrix, ¤t_x, ¤t_y);
- if (current_x >= item->x0 && current_x < item->x1 &&
- current_y >= item->y0 && current_y < item->y1)
+void _ctx_item_unref (CtxItem *item)
+{
+ if (item->ref_count <= 0)
+ {
+ fprintf (stderr, "EEEEK!\n");
+ return;
+ }
+ item->ref_count--;
+ if (item->ref_count <=0)
+ {
{
- ctx_matrix_invert (&matrix);
- ctx_set_matrix (ctx, &matrix);
- _mrg_restore_path (ctx, item->path);
- ctx_stroke (ctx);
+ int i;
+ for (i = 0; i < item->cb_count; i++)
+ {
+ if (item->cb[i].finalize)
+ item->cb[i].finalize (item->cb[i].data1, item->cb[i].data2,
+ item->cb[i].finalize_data);
+ }
+ }
+ if (item->path)
+ {
+ //cairo_path_destroy (item->path);
}
+ free (item);
}
- ctx_restore (ctx);
}
-void ctx_set_render_threads (Ctx *ctx, int n_threads)
+
+static int
+path_equal (void *path,
+ void *path2)
{
- // XXX
+ // XXX
+ return 0;
}
-int ctx_get_render_threads (Ctx *ctx)
+
+void ctx_listen_set_cursor (Ctx *ctx,
+ CtxCursor cursor)
{
- return _ctx_max_threads;
-}
-void ctx_set_hash_cache (Ctx *ctx, int enable_hash_cache)
-{
- _ctx_enable_hash_cache = enable_hash_cache;
-}
-int ctx_get_hash_cache (Ctx *ctx)
-{
- return _ctx_enable_hash_cache;
+ if (ctx->events.last_item)
+ {
+ ctx->events.last_item->cursor = cursor;
+ }
}
-int ctx_is_dirty (Ctx *ctx)
-{
- return ctx->dirty;
-}
-void ctx_set_dirty (Ctx *ctx, int dirty)
+void ctx_listen_full (Ctx *ctx,
+ float x,
+ float y,
+ float width,
+ float height,
+ CtxEventType types,
+ CtxCb cb,
+ void *data1,
+ void *data2,
+ void (*finalize)(void *listen_data,
+ void *listen_data2,
+ void *finalize_data),
+ void *finalize_data)
{
- ctx->dirty = dirty;
-}
+ if (!ctx->events.frozen)
+ {
+ CtxItem *item;
-/*
- * centralized global API for managing file descriptors that
- * wake us up, this to remove sleeping and polling
- */
+ /* early bail for listeners outside screen */
+ /* XXX: fixme respect clipping */
+ {
+ float tx = x;
+ float ty = y;
+ float tw = width;
+ float th = height;
+ _ctx_user_to_device (&ctx->state, &tx, &ty);
+ _ctx_user_to_device_distance (&ctx->state, &tw, &th);
+ if (ty > ctx->events.height * 2 ||
+ tx > ctx->events.width * 2 ||
+ tx + tw < 0 ||
+ ty + th < 0)
+ {
+ if (finalize)
+ finalize (data1, data2, finalize_data);
+ return;
+ }
+ }
-#define CTX_MAX_LISTEN_FDS 8
-static int _ctx_listen_fd[CTX_MAX_LISTEN_FDS];
-static int _ctx_listen_fds = 0;
-static int _ctx_listen_max_fd = 0;
+ item = calloc (sizeof (CtxItem), 1);
+ item->x0 = x;
+ item->y0 = y;
+ item->x1 = x + width;
+ item->y1 = y + height;
+ item->cb[0].types = types;
+ item->cb[0].cb = cb;
+ item->cb[0].data1 = data1;
+ item->cb[0].data2 = data2;
+ item->cb[0].finalize = finalize;
+ item->cb[0].finalize_data = finalize_data;
+ item->cb_count = 1;
+ item->types = types;
+ //item->path = cairo_copy_path (cr); // XXX
+ item->path_hash = ctx_path_hash (item->path);
+ ctx_get_matrix (ctx, &item->inv_matrix);
+ ctx_matrix_invert (&item->inv_matrix);
-void _ctx_add_listen_fd (int fd)
+ if (ctx->events.items)
+ {
+ CtxList *l;
+ for (l = ctx->events.items; l; l = l->next)
+ {
+ CtxItem *item2 = l->data;
+
+ /* store multiple callbacks for one entry when the paths
+ * are exact matches, reducing per event traversal checks at the
+ * cost of a little paint-hit (XXX: is this the right tradeoff,
+ * perhaps it is better to spend more time during event processing
+ * than during paint?)
+ */
+ if (item->path_hash == item2->path_hash &&
+ path_equal (item->path, item2->path))
+ {
+ /* found an item, copy over cb data */
+ item2->cb[item2->cb_count] = item->cb[0];
+ free (item);
+ item2->cb_count++;
+ item2->types |= types;
+ return;
+ }
+ }
+ }
+ item->ref_count = 1;
+ ctx->events.last_item = item;
+ ctx_list_prepend_full (&ctx->events.items, item, (void*)_ctx_item_unref, NULL);
+ }
+}
+
+void ctx_event_stop_propagate (CtxEvent *event)
{
- _ctx_listen_fd[_ctx_listen_fds++]=fd;
- if (fd > _ctx_listen_max_fd)
- _ctx_listen_max_fd = fd;
+ if (event)
+ event->stop_propagate = 1;
}
-void _ctx_remove_listen_fd (int fd)
+void ctx_listen (Ctx *ctx,
+ CtxEventType types,
+ CtxCb cb,
+ void* data1,
+ void* data2)
{
- for (int i = 0; i < _ctx_listen_fds; i++)
+ float x, y, width, height;
+ /* generate bounding box of what to listen for - from current cairo path */
+ if (types & CTX_KEY)
{
- if (_ctx_listen_fd[i] == fd)
- {
- _ctx_listen_fd[i] = _ctx_listen_fd[_ctx_listen_fds-1];
- _ctx_listen_fds--;
- return;
- }
+ x = 0;
+ y = 0;
+ width = 0;
+ height = 0;
+ }
+ else
+ {
+ float ex1,ey1,ex2,ey2;
+ ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
+ x = ex1;
+ y = ey1;
+ width = ex2 - ex1;
+ height = ey2 - ey1;
}
+
+ if (types == CTX_DRAG_MOTION)
+ types = CTX_DRAG_MOTION | CTX_DRAG_PRESS;
+ return ctx_listen_full (ctx, x, y, width, height, types, cb, data1, data2, NULL, NULL);
}
-int _ctx_data_pending (int timeout)
+void ctx_listen_with_finalize (Ctx *ctx,
+ CtxEventType types,
+ CtxCb cb,
+ void* data1,
+ void* data2,
+ void (*finalize)(void *listen_data, void *listen_data2,
+ void *finalize_data),
+ void *finalize_data)
{
- struct timeval tv;
- fd_set fdset;
- FD_ZERO (&fdset);
- for (int i = 0; i < _ctx_listen_fds; i++)
+ float x, y, width, height;
+ /* generate bounding box of what to listen for - from current cairo path */
+ if (types & CTX_KEY)
{
- FD_SET (_ctx_listen_fd[i], &fdset);
+ x = 0;
+ y = 0;
+ width = 0;
+ height = 0;
}
- tv.tv_sec = 0;
- tv.tv_usec = timeout;
- tv.tv_sec = timeout / 1000000;
- tv.tv_usec = timeout % 1000000;
- int retval = select (_ctx_listen_max_fd, &fdset, NULL, NULL, &tv);
- if (retval == -1)
+ else
{
- perror ("select");
- return 0;
+ float ex1,ey1,ex2,ey2;
+ ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
+ x = ex1;
+ y = ey1;
+ width = ex2 - ex1;
+ height = ey2 - ey1;
}
- return retval;
+
+ if (types == CTX_DRAG_MOTION)
+ types = CTX_DRAG_MOTION | CTX_DRAG_PRESS;
+ return ctx_listen_full (ctx, x, y, width, height, types, cb, data1, data2, finalize, finalize_data);
}
-#endif
-/* the parser comes in the end, nothing in ctx knows about the parser */
-#if CTX_PARSER
+static void ctx_report_hit_region (CtxEvent *event,
+ void *data,
+ void *data2)
+{
+ const char *id = data;
-/* ctx parser, */
+ fprintf (stderr, "hit region %s\n", id);
+ // XXX: NYI
+}
-struct
- _CtxParser
+void ctx_add_hit_region (Ctx *ctx, const char *id)
{
- int t_args; // total number of arguments seen for current command
- Ctx *ctx;
- int state;
- uint8_t holding[CTX_PARSER_MAXLEN]; /* */
- int line; /* for error reporting */
- int col; /* for error reporting */
- int pos;
- float numbers[CTX_PARSER_MAX_ARGS+1];
- int n_numbers;
- int decimal;
- CtxCode command;
- int expected_args; /* low digits are literal higher values
- carry special meaning */
- int n_args;
- uint32_t set_key_hash;
- float pcx;
- float pcy;
- int color_components;
- int color_model; // 1 gray 3 rgb 4 cmyk
- float left_margin; // set by last user provided move_to
- int width; // <- maybe should be float
- int height;
- float cell_width;
- float cell_height;
- int cursor_x; // <- leaking in from terminal
- int cursor_y;
-
- int color_space_slot;
+ char *id_copy = strdup (id);
+ float x, y, width, height;
+ /* generate bounding box of what to listen for - from current cairo path */
+ {
+ float ex1,ey1,ex2,ey2;
+ ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
+ x = ex1;
+ y = ey1;
+ width = ex2 - ex1;
+ height = ey2 - ey1;
+ }
+
+ return ctx_listen_full (ctx, x, y, width, height,
+ CTX_POINTER, ctx_report_hit_region,
+ id_copy, NULL, (void*)free, NULL);
+}
- void (*exit) (void *exit_data);
- void *exit_data;
- int (*set_prop)(void *prop_data, uint32_t key, const char *data, int len);
- int (*get_prop)(void *prop_data, const char *key, char **data, int *len);
- void *prop_data;
-};
+typedef struct _CtxGrab CtxGrab;
-void
-ctx_parser_set_size (CtxParser *parser,
- int width,
- int height,
- float cell_width,
- float cell_height)
+struct _CtxGrab
{
- if (cell_width > 0)
- parser->cell_width = cell_width;
- if (cell_height > 0)
- parser->cell_height = cell_height;
- if (width > 0)
- parser->width = width;
- if (height > 0)
- parser->height = height;
-}
+ CtxItem *item;
+ int device_no;
+ int timeout_id;
+ int start_time;
+ float x; // for tap and hold
+ float y;
+ CtxEventType type;
+};
-static CtxParser *
-ctx_parser_init (CtxParser *parser,
- Ctx *ctx,
- int width,
- int height,
- float cell_width,
- float cell_height,
- int cursor_x,
- int cursor_y,
- int (*set_prop)(void *prop_data, uint32_t key, const char *data, int len),
- int (*get_prop)(void *prop_Data, const char *key, char **data, int *len),
- void *prop_data,
- void (*exit) (void *exit_data),
- void *exit_data
- )
+static void grab_free (Ctx *ctx, CtxGrab *grab)
{
- ctx_memset (parser, 0, sizeof (CtxParser) );
- parser->line = 1;
- parser->ctx = ctx;
- parser->cell_width = cell_width;
- parser->cell_height = cell_height;
- parser->cursor_x = cursor_x;
- parser->cursor_y = cursor_y;
- parser->width = width;
- parser->height = height;
- parser->exit = exit;
- parser->exit_data = exit_data;
- parser->color_model = CTX_RGBA;
- parser->color_components = 4;
- parser->command = CTX_MOVE_TO;
- parser->set_prop = set_prop;
- parser->get_prop = get_prop;
- parser->prop_data = prop_data;
- return parser;
+ if (grab->timeout_id)
+ {
+ ctx_remove_idle (ctx, grab->timeout_id);
+ grab->timeout_id = 0;
+ }
+ _ctx_item_unref (grab->item);
+ free (grab);
}
-CtxParser *ctx_parser_new (
- Ctx *ctx,
- int width,
- int height,
- float cell_width,
- float cell_height,
- int cursor_x,
- int cursor_y,
- int (*set_prop)(void *prop_data, uint32_t key, const char *data, int len),
- int (*get_prop)(void *prop_Data, const char *key, char **data, int *len),
- void *prop_data,
- void (*exit) (void *exit_data),
- void *exit_data)
+static void device_remove_grab (Ctx *ctx, CtxGrab *grab)
{
- return ctx_parser_init ( (CtxParser *) ctx_calloc (sizeof (CtxParser), 1),
- ctx,
- width, height,
- cell_width, cell_height,
- cursor_x, cursor_y, set_prop, get_prop, prop_data,
- exit, exit_data);
+ ctx_list_remove (&ctx->events.grabs, grab);
+ grab_free (ctx, grab);
}
-void ctx_parser_free (CtxParser *parser)
+static CtxGrab *device_add_grab (Ctx *ctx, int device_no, CtxItem *item, CtxEventType type)
{
- free (parser);
+ CtxGrab *grab = calloc (1, sizeof (CtxGrab));
+ grab->item = item;
+ grab->type = type;
+ _ctx_item_ref (item);
+ grab->device_no = device_no;
+ ctx_list_append (&ctx->events.grabs, grab);
+ return grab;
}
-#define CTX_ARG_COLLECT_NUMBERS 50
-#define CTX_ARG_STRING_OR_NUMBER 100
-#define CTX_ARG_NUMBER_OF_COMPONENTS 200
-#define CTX_ARG_NUMBER_OF_COMPONENTS_PLUS_1 201
-
-static int ctx_arguments_for_code (CtxCode code)
+CtxList *device_get_grabs (Ctx *ctx, int device_no)
{
- switch (code)
- {
- case CTX_SAVE:
- case CTX_START_GROUP:
- case CTX_END_GROUP:
- case CTX_IDENTITY:
- case CTX_CLOSE_PATH:
- case CTX_BEGIN_PATH:
- case CTX_RESET:
- case CTX_FLUSH:
- case CTX_RESTORE:
- case CTX_STROKE:
- case CTX_FILL:
- case CTX_NEW_PAGE:
- case CTX_CLIP:
- case CTX_EXIT:
- return 0;
- case CTX_GLOBAL_ALPHA:
- case CTX_COMPOSITING_MODE:
- case CTX_BLEND_MODE:
- case CTX_FONT_SIZE:
- case CTX_LINE_JOIN:
- case CTX_LINE_CAP:
- case CTX_LINE_WIDTH:
- case CTX_SHADOW_BLUR:
- case CTX_SHADOW_OFFSET_X:
- case CTX_SHADOW_OFFSET_Y:
- case CTX_FILL_RULE:
- case CTX_TEXT_ALIGN:
- case CTX_TEXT_BASELINE:
- case CTX_TEXT_DIRECTION:
- case CTX_MITER_LIMIT:
- case CTX_REL_VER_LINE_TO:
- case CTX_REL_HOR_LINE_TO:
- case CTX_HOR_LINE_TO:
- case CTX_VER_LINE_TO:
- case CTX_FONT:
- case CTX_ROTATE:
- case CTX_GLYPH:
- return 1;
- case CTX_TRANSLATE:
- case CTX_REL_SMOOTHQ_TO:
- case CTX_LINE_TO:
- case CTX_MOVE_TO:
- case CTX_SCALE:
- case CTX_REL_LINE_TO:
- case CTX_REL_MOVE_TO:
- case CTX_SMOOTHQ_TO:
- return 2;
- case CTX_LINEAR_GRADIENT:
- case CTX_REL_QUAD_TO:
- case CTX_QUAD_TO:
- case CTX_RECTANGLE:
- case CTX_REL_SMOOTH_TO:
- case CTX_VIEW_BOX:
- case CTX_SMOOTH_TO:
- return 4;
- case CTX_ARC_TO:
- case CTX_REL_ARC_TO:
- case CTX_ROUND_RECTANGLE:
- return 5;
- case CTX_ARC:
- case CTX_CURVE_TO:
- case CTX_REL_CURVE_TO:
- case CTX_APPLY_TRANSFORM:
- case CTX_RADIAL_GRADIENT:
- return 6;
- case CTX_TEXT_STROKE:
- case CTX_TEXT: // special case
- case CTX_COLOR_SPACE:
- case CTX_DEFINE_GLYPH:
- case CTX_KERNING_PAIR:
- return CTX_ARG_STRING_OR_NUMBER;
- case CTX_LINE_DASH: /* append to current dashes for each argument encountered */
- return CTX_ARG_COLLECT_NUMBERS;
- //case CTX_SET_KEY:
- case CTX_COLOR:
- case CTX_SHADOW_COLOR:
- return CTX_ARG_NUMBER_OF_COMPONENTS;
- case CTX_GRADIENT_STOP:
- return CTX_ARG_NUMBER_OF_COMPONENTS_PLUS_1;
+ CtxList *ret = NULL;
+ CtxList *l;
+ for (l = ctx->events.grabs; l; l = l->next)
+ {
+ CtxGrab *grab = l->data;
+ if (grab->device_no == device_no)
+ ctx_list_append (&ret, grab);
+ }
+ return ret;
+}
- default:
-#if 1
- case CTX_TEXTURE:
- case CTX_SET_RGBA_U8:
- case CTX_BITPIX:
- case CTX_NOP:
- case CTX_NEW_EDGE:
- case CTX_EDGE:
- case CTX_EDGE_FLIPPED:
- case CTX_CONT:
- case CTX_DATA:
- case CTX_DATA_REV:
- case CTX_SET_PIXEL:
- case CTX_REL_LINE_TO_X4:
- case CTX_REL_LINE_TO_REL_CURVE_TO:
- case CTX_REL_CURVE_TO_REL_LINE_TO:
- case CTX_REL_CURVE_TO_REL_MOVE_TO:
- case CTX_REL_LINE_TO_X2:
- case CTX_MOVE_TO_REL_LINE_TO:
- case CTX_REL_LINE_TO_REL_MOVE_TO:
- case CTX_FILL_MOVE_TO:
- case CTX_REL_QUAD_TO_REL_QUAD_TO:
- case CTX_REL_QUAD_TO_S16:
-#endif
- return 0;
- }
+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);
}
-static int ctx_parser_set_command (CtxParser *parser, CtxCode code)
+CtxList *_ctx_detect_list (Ctx *ctx, float x, float y, CtxEventType type)
{
- if (code < 150 && code >= 32)
+ CtxList *a;
+ CtxList *ret = NULL;
+
+ if (type == CTX_KEY_DOWN ||
+ type == CTX_KEY_UP ||
+ type == CTX_KEY_PRESS ||
+ type == CTX_MESSAGE ||
+ type == (CTX_KEY_DOWN|CTX_MESSAGE) ||
+ type == (CTX_KEY_DOWN|CTX_KEY_UP) ||
+ type == (CTX_KEY_DOWN|CTX_KEY_UP|CTX_MESSAGE))
{
- parser->expected_args = ctx_arguments_for_code (code);
- parser->n_args = 0;
- if (parser->expected_args >= CTX_ARG_NUMBER_OF_COMPONENTS)
+ for (a = ctx->events.items; a; a = a->next)
{
- parser->expected_args = (parser->expected_args % 100) + parser->color_components;
+ CtxItem *item = a->data;
+ if (item->types & type)
+ {
+ ctx_list_prepend (&ret, item);
+ return ret;
+ }
}
+ return NULL;
}
- return code;
-}
-
-static void ctx_parser_set_color_model (CtxParser *parser, CtxColorModel color_model);
-
-static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
-{
- uint32_t ret = str[0]; /* if it is single char it already is the CtxCode */
- /* this is handled outside the hashing to make it possible to be case insensitive
- * with the rest.
- */
- if (str[0] == CTX_SET_KEY && str[1] && str[2] == 0)
+ for (a = ctx->events.items; a; a = a->next)
{
- switch (str[1])
- {
- case 'm': return ctx_parser_set_command (parser, CTX_COMPOSITING_MODE);
- case 'B': return ctx_parser_set_command (parser, CTX_BLEND_MODE);
- case 'l': return ctx_parser_set_command (parser, CTX_MITER_LIMIT);
- case 't': return ctx_parser_set_command (parser, CTX_TEXT_ALIGN);
- case 'b': return ctx_parser_set_command (parser, CTX_TEXT_BASELINE);
- case 'd': return ctx_parser_set_command (parser, CTX_TEXT_DIRECTION);
- case 'j': return ctx_parser_set_command (parser, CTX_LINE_JOIN);
- case 'c': return ctx_parser_set_command (parser, CTX_LINE_CAP);
- case 'w': return ctx_parser_set_command (parser, CTX_LINE_WIDTH);
- case 'C': return ctx_parser_set_command (parser, CTX_SHADOW_COLOR);
- case 's': return ctx_parser_set_command (parser, CTX_SHADOW_BLUR);
- case 'x': return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_X);
- case 'y': return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_Y);
- case 'a': return ctx_parser_set_command (parser, CTX_GLOBAL_ALPHA);
- case 'f': return ctx_parser_set_command (parser, CTX_FONT_SIZE);
- case 'r': return ctx_parser_set_command (parser, CTX_FILL_RULE);
- }
- }
+ CtxItem *item= a->data;
+
+ float u, v;
+ u = x;
+ v = y;
+ ctx_matrix_apply_transform (&item->inv_matrix, &u, &v);
- if (str[0] && str[1])
+ if (u >= item->x0 && v >= item->y0 &&
+ u < item->x1 && v < item->y1 &&
+ ((item->types & type) || ((type == CTX_SET_CURSOR) &&
+ item->cursor)))
{
- uint32_t str_hash;
- /* trim ctx_ and CTX_ prefix */
- if ( (str[0] == 'c' && str[1] == 't' && str[2] == 'x' && str[3] == '_') ||
- (str[0] == 'C' && str[1] == 'T' && str[2] == 'X' && str[3] == '_') )
- {
- str += 4;
- }
- if ( (str[0] == 's' && str[1] == 'e' && str[2] == 't' && str[3] == '_') )
- { str += 4; }
- str_hash = ctx_strhash ( (char *) str, 0);
- switch (str_hash)
+ if (item->path)
+ {
+ _mrg_restore_path (ctx, item->path);
+ if (ctx_in_fill (ctx, u, v))
{
- /* first a list of mappings to one_char hashes, handled in a
- * separate fast path switch without hashing
- */
- case CTX_arcTo: ret = CTX_ARC_TO; break;
- case CTX_arc: ret = CTX_ARC; break;
- case CTX_curveTo: ret = CTX_CURVE_TO; break;
- case CTX_restore: ret = CTX_RESTORE; break;
- case CTX_stroke: ret = CTX_STROKE; break;
- case CTX_fill: ret = CTX_FILL; break;
- case CTX_flush: ret = CTX_FLUSH; break;
- case CTX_horLineTo: ret = CTX_HOR_LINE_TO; break;
- case CTX_rotate: ret = CTX_ROTATE; break;
- case CTX_color: ret = CTX_COLOR; break;
- case CTX_lineTo: ret = CTX_LINE_TO; break;
- case CTX_moveTo: ret = CTX_MOVE_TO; break;
- case CTX_scale: ret = CTX_SCALE; break;
- 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_clear: ret = CTX_COMPOSITE_CLEAR; break;
- case CTX_copy: ret = CTX_COMPOSITE_COPY; break;
- case CTX_destinationOver: ret = CTX_COMPOSITE_DESTINATION_OVER; break;
- case CTX_destinationIn: ret = CTX_COMPOSITE_DESTINATION_IN; break;
- case CTX_destinationOut: ret = CTX_COMPOSITE_DESTINATION_OUT; break;
- case CTX_sourceOver: ret = CTX_COMPOSITE_SOURCE_OVER; break;
- case CTX_sourceAtop: ret = CTX_COMPOSITE_SOURCE_ATOP; break;
- case CTX_destinationAtop: ret = CTX_COMPOSITE_DESTINATION_ATOP; break;
- case CTX_sourceOut: ret = CTX_COMPOSITE_SOURCE_OUT; break;
- case CTX_sourceIn: ret = CTX_COMPOSITE_SOURCE_IN; break;
- case CTX_xor: ret = CTX_COMPOSITE_XOR; break;
- case CTX_darken: ret = CTX_BLEND_DARKEN; break;
- case CTX_lighten: ret = CTX_BLEND_LIGHTEN; break;
- //case CTX_color: ret = CTX_BLEND_COLOR; break;
- //
- // XXX check that he special casing for color works
- // it is the first collision and it is due to our own
- // color, not w3c for now unique use of it
- //
- case CTX_hue: ret = CTX_BLEND_HUE; break;
- case CTX_multiply: ret = CTX_BLEND_MULTIPLY; break;
- 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_verLineTo: ret = CTX_VER_LINE_TO; break;
- case CTX_exit:
- case CTX_done: ret = CTX_EXIT; break;
- case CTX_closePath: ret = CTX_CLOSE_PATH; break;
- case CTX_beginPath:
- case CTX_newPath: ret = CTX_BEGIN_PATH; break;
- case CTX_relArcTo: ret = CTX_REL_ARC_TO; break;
- case CTX_clip: ret = CTX_CLIP; break;
- case CTX_relCurveTo: ret = CTX_REL_CURVE_TO; break;
- case CTX_startGroup: ret = CTX_START_GROUP; break;
- case CTX_endGroup: ret = CTX_END_GROUP; break;
- case CTX_save: ret = CTX_SAVE; break;
- case CTX_translate: ret = CTX_TRANSLATE; break;
- case CTX_linearGradient: ret = CTX_LINEAR_GRADIENT; break;
- case CTX_relHorLineTo: ret = CTX_REL_HOR_LINE_TO; break;
- case CTX_relLineTo: ret = CTX_REL_LINE_TO; break;
- case CTX_relMoveTo: ret = CTX_REL_MOVE_TO; break;
- case CTX_font: ret = CTX_FONT; break;
- case CTX_radialGradient:ret = CTX_RADIAL_GRADIENT; break;
- case CTX_gradientAddStop:
- case CTX_addStop: ret = CTX_GRADIENT_STOP; break;
- case CTX_relQuadTo: ret = CTX_REL_QUAD_TO; break;
- case CTX_rectangle:
- case CTX_rect: ret = CTX_RECTANGLE; break;
- case CTX_roundRectangle: ret = CTX_ROUND_RECTANGLE; break;
- case CTX_relSmoothTo: ret = CTX_REL_SMOOTH_TO; break;
- case CTX_relSmoothqTo: ret = CTX_REL_SMOOTHQ_TO; break;
- case CTX_textStroke: ret = CTX_TEXT_STROKE; break;
- case CTX_relVerLineTo: ret = CTX_REL_VER_LINE_TO; break;
- case CTX_text: ret = CTX_TEXT; break;
- case CTX_identity: ret = CTX_IDENTITY; break;
- case CTX_transform: ret = CTX_APPLY_TRANSFORM; break;
- case CTX_texture: ret = CTX_TEXTURE; break;
-#if 0
- case CTX_rgbSpace:
- return ctx_parser_set_command (parser, CTX_SET_RGB_SPACE);
- case CTX_cmykSpace:
- return ctx_parser_set_command (parser, CTX_SET_CMYK_SPACE);
- case CTX_drgbSpace:
- return ctx_parser_set_command (parser, CTX_SET_DRGB_SPACE);
-#endif
- case CTX_defineGlyph:
- return ctx_parser_set_command (parser, CTX_DEFINE_GLYPH);
- case CTX_kerningPair:
- return ctx_parser_set_command (parser, CTX_KERNING_PAIR);
-
- case CTX_colorSpace:
- return ctx_parser_set_command (parser, CTX_COLOR_SPACE);
- case CTX_fillRule:
- return ctx_parser_set_command (parser, CTX_FILL_RULE);
- case CTX_fontSize:
- case CTX_setFontSize:
- return ctx_parser_set_command (parser, CTX_FONT_SIZE);
- case CTX_compositingMode:
- return ctx_parser_set_command (parser, CTX_COMPOSITING_MODE);
-
- case CTX_blend:
- case CTX_blending:
- case CTX_blendMode:
- return ctx_parser_set_command (parser, CTX_BLEND_MODE);
-
- case CTX_miterLimit:
- return ctx_parser_set_command (parser, CTX_MITER_LIMIT);
- case CTX_textAlign:
- return ctx_parser_set_command (parser, CTX_TEXT_ALIGN);
- case CTX_textBaseline:
- return ctx_parser_set_command (parser, CTX_TEXT_BASELINE);
- case CTX_textDirection:
- return ctx_parser_set_command (parser, CTX_TEXT_DIRECTION);
- case CTX_join:
- case CTX_lineJoin:
- case CTX_setLineJoin:
- return ctx_parser_set_command (parser, CTX_LINE_JOIN);
- case CTX_glyph:
- return ctx_parser_set_command (parser, CTX_GLYPH);
- case CTX_cap:
- case CTX_lineCap:
- case CTX_setLineCap:
- return ctx_parser_set_command (parser, CTX_LINE_CAP);
- case CTX_lineDash:
- return ctx_parser_set_command (parser, CTX_LINE_DASH);
- case CTX_lineWidth:
- case CTX_setLineWidth:
- return ctx_parser_set_command (parser, CTX_LINE_WIDTH);
- case CTX_shadowColor:
- return ctx_parser_set_command (parser, CTX_SHADOW_COLOR);
- case CTX_shadowBlur:
- return ctx_parser_set_command (parser, CTX_SHADOW_BLUR);
- case CTX_shadowOffsetX:
- return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_X);
- case CTX_shadowOffsetY:
- return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_Y);
- case CTX_globalAlpha:
- return ctx_parser_set_command (parser, CTX_GLOBAL_ALPHA);
- /* strings are handled directly here,
- * instead of in the one-char handler, using return instead of break
- */
- case CTX_gray:
- ctx_parser_set_color_model (parser, CTX_GRAY);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_graya:
- ctx_parser_set_color_model (parser, CTX_GRAYA);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_rgb:
- ctx_parser_set_color_model (parser, CTX_RGB);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_drgb:
- ctx_parser_set_color_model (parser, CTX_DRGB);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_rgba:
- ctx_parser_set_color_model (parser, CTX_RGBA);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_drgba:
- ctx_parser_set_color_model (parser, CTX_DRGBA);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_cmyk:
- ctx_parser_set_color_model (parser, CTX_CMYK);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_cmyka:
- ctx_parser_set_color_model (parser, CTX_CMYKA);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_lab:
- ctx_parser_set_color_model (parser, CTX_LAB);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_laba:
- ctx_parser_set_color_model (parser, CTX_LABA);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_lch:
- ctx_parser_set_color_model (parser, CTX_LCH);
- return ctx_parser_set_command (parser, CTX_COLOR);
- case CTX_lcha:
- ctx_parser_set_color_model (parser, CTX_LCHA);
- return ctx_parser_set_command (parser, CTX_COLOR);
- /* words that correspond to low integer constants
- */
- case CTX_winding: return CTX_FILL_RULE_WINDING;
- case CTX_evenOdd:
- case CTX_even_odd: 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;
- case CTX_none: return CTX_CAP_NONE;
- case CTX_square: return CTX_CAP_SQUARE;
- case CTX_start: return CTX_TEXT_ALIGN_START;
- case CTX_end: return CTX_TEXT_ALIGN_END;
- case CTX_left: return CTX_TEXT_ALIGN_LEFT;
- case CTX_right: return CTX_TEXT_ALIGN_RIGHT;
- case CTX_center: return CTX_TEXT_ALIGN_CENTER;
- case CTX_top: return CTX_TEXT_BASELINE_TOP;
- case CTX_bottom : return CTX_TEXT_BASELINE_BOTTOM;
- case CTX_middle: return CTX_TEXT_BASELINE_MIDDLE;
- case CTX_alphabetic: return CTX_TEXT_BASELINE_ALPHABETIC;
- case CTX_hanging: return CTX_TEXT_BASELINE_HANGING;
- case CTX_ideographic: return CTX_TEXT_BASELINE_IDEOGRAPHIC;
-
- case CTX_userRGB: return CTX_COLOR_SPACE_USER_RGB;
- case CTX_deviceRGB: return CTX_COLOR_SPACE_DEVICE_RGB;
- case CTX_userCMYK: return CTX_COLOR_SPACE_USER_CMYK;
- case CTX_deviceCMYK: return CTX_COLOR_SPACE_DEVICE_CMYK;
-#undef STR
-#undef LOWER
- default:
- ret = str_hash;
+ ctx_begin_path (ctx);
+ ctx_list_prepend (&ret, item);
}
+ ctx_begin_path (ctx);
+ }
+ else
+ {
+ ctx_list_prepend (&ret, item);
+ }
}
- if (ret == CTX_CLOSE_PATH2)
- { ret = CTX_CLOSE_PATH; }
- /* handling single char, and ret = foo; break; in cases above*/
- return ctx_parser_set_command (parser, (CtxCode) ret);
+ }
+ return ret;
}
-enum
+CtxItem *_ctx_detect (Ctx *ctx, float x, float y, CtxEventType type)
{
- CTX_PARSER_NEUTRAL = 0,
- CTX_PARSER_NUMBER,
- CTX_PARSER_NEGATIVE_NUMBER,
- CTX_PARSER_WORD,
- CTX_PARSER_COMMENT,
- CTX_PARSER_STRING_APOS,
- CTX_PARSER_STRING_QUOT,
- CTX_PARSER_STRING_APOS_ESCAPED,
- CTX_PARSER_STRING_QUOT_ESCAPED,
- CTX_PARSER_STRING_A85,
-} CTX_STATE;
+ CtxList *l = _ctx_detect_list (ctx, x, y, type);
+ if (l)
+ {
+ ctx_list_reverse (&l);
+ CtxItem *ret = l->data;
+ ctx_list_free (&l);
+ return ret;
+ }
+ return NULL;
+}
-static void ctx_parser_set_color_model (CtxParser *parser, CtxColorModel color_model)
+static int
+_ctx_emit_cb_item (Ctx *ctx, CtxItem *item, CtxEvent *event, CtxEventType type, float x, float y)
{
- parser->color_model = color_model;
- parser->color_components = ctx_color_model_get_components (color_model);
+ static CtxEvent s_event;
+ CtxEvent transformed_event;
+ int i;
+
+
+ if (!event)
+ {
+ event = &s_event;
+ event->type = type;
+ event->x = x;
+ event->y = y;
+ }
+ event->ctx = ctx;
+ transformed_event = *event;
+ transformed_event.device_x = event->x;
+ transformed_event.device_y = event->y;
+
+ {
+ float tx, ty;
+ tx = transformed_event.x;
+ ty = transformed_event.y;
+ ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
+ transformed_event.x = tx;
+ transformed_event.y = ty;
+
+ if ((type & CTX_DRAG_PRESS) ||
+ (type & CTX_DRAG_MOTION) ||
+ (type & CTX_MOTION)) /* probably a worthwhile check for the performance
+ benefit
+ */
+ {
+ tx = transformed_event.start_x;
+ ty = transformed_event.start_y;
+ ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
+ transformed_event.start_x = tx;
+ transformed_event.start_y = ty;
+ }
+
+
+ tx = transformed_event.delta_x;
+ ty = transformed_event.delta_y;
+ ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
+ transformed_event.delta_x = tx;
+ transformed_event.delta_y = ty;
+ }
+
+ transformed_event.state = ctx->events.modifier_state;
+ transformed_event.type = type;
+
+ for (i = item->cb_count-1; i >= 0; i--)
+ {
+ if (item->cb[i].types & type)
+ {
+ item->cb[i].cb (&transformed_event, item->cb[i].data1, item->cb[i].data2);
+ event->stop_propagate = transformed_event.stop_propagate; /* copy back the response */
+ if (event->stop_propagate)
+ return event->stop_propagate;
+ }
+ }
+ return 0;
}
+#endif
-static void ctx_parser_get_color_rgba (CtxParser *parser, int offset, float *red, float *green, float *blue,
float *alpha)
+#if CTX_EVENTS
+
+#include <stdatomic.h>
+
+int ctx_native_events = 0;
+#if CTX_SDL
+int ctx_sdl_events = 0;
+int ctx_sdl_consume_events (Ctx *ctx);
+#endif
+
+#if CTX_FB
+int ctx_fb_events = 0;
+int ctx_fb_consume_events (Ctx *ctx);
+#endif
+
+int ctx_nct_consume_events (Ctx *ctx);
+int ctx_ctx_consume_events (Ctx *ctx);
+
+void ctx_consume_events (Ctx *ctx)
{
- /* XXX - this function is to be deprecated */
- *alpha = 1.0;
- switch (parser->color_model)
+#if CTX_SDL
+ if (ctx_sdl_events)
+ ctx_sdl_consume_events (ctx);
+ else
+#endif
+#if CTX_FB
+ if (ctx_fb_events)
+ ctx_fb_consume_events (ctx);
+ else
+#endif
+ if (ctx_native_events)
+ ctx_ctx_consume_events (ctx);
+ else
+ ctx_nct_consume_events (ctx);
+}
+
+CtxEvent *ctx_get_event (Ctx *ctx)
+{
+ static CtxEvent event_copy;
+ _ctx_idle_iteration (ctx);
+ if (!ctx->events.ctx_get_event_enabled)
+ ctx->events.ctx_get_event_enabled = 1;
+
+ ctx_consume_events (ctx);
+
+ if (ctx->events.events)
{
- case CTX_GRAYA:
- *alpha = parser->numbers[offset + 1];
- /* FALLTHROUGH */
- case CTX_GRAY:
- *red = *green = *blue = parser->numbers[offset + 0];
- break;
- default:
- case CTX_LABA: // NYI - needs RGB profile
- case CTX_LCHA: // NYI - needs RGB profile
- case CTX_RGBA:
- *alpha = parser->numbers[offset + 3];
- /* FALLTHROUGH */
- case CTX_LAB: // NYI
- case CTX_LCH: // NYI
- case CTX_RGB:
- *red = parser->numbers[offset + 0];
- *green = parser->numbers[offset + 1];
- *blue = parser->numbers[offset + 2];
- break;
- case CTX_CMYKA:
- *alpha = parser->numbers[offset + 4];
- /* 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]);
- break;
+ event_copy = *((CtxEvent*)(ctx->events.events->data));
+ ctx_list_remove (&ctx->events.events, ctx->events.events->data);
+ return &event_copy;
}
+ return NULL;
}
-static void ctx_parser_dispatch_command (CtxParser *parser)
+static int
+_ctx_emit_cb (Ctx *ctx, CtxList *items, CtxEvent *event, CtxEventType type, float x, float y)
{
- CtxCode cmd = parser->command;
- Ctx *ctx = parser->ctx;
- if (parser->expected_args != CTX_ARG_STRING_OR_NUMBER &&
- parser->expected_args != CTX_ARG_COLLECT_NUMBERS &&
- parser->expected_args != parser->n_numbers)
+ CtxList *l;
+ event->stop_propagate = 0;
+ for (l = items; l; l = l->next)
+ {
+ _ctx_emit_cb_item (ctx, l->data, event, type, x, y);
+ if (event->stop_propagate)
+ return event->stop_propagate;
+ }
+ return 0;
+}
+
+/*
+ * update what is the currently hovered item and returns it.. and the list of hits
+ * a well.
+ *
+ */
+static CtxItem *_ctx_update_item (Ctx *ctx, int device_no, float x, float y, CtxEventType type, CtxList
**hitlist)
+{
+ CtxItem *current = NULL;
+
+ CtxList *l = _ctx_detect_list (ctx, x, y, type);
+ if (l)
+ {
+ ctx_list_reverse (&l);
+ current = l->data;
+ }
+ if (hitlist)
+ *hitlist = l;
+ else
+ ctx_list_free (&l);
+
+ if (ctx->events.prev[device_no] == NULL || current == NULL || (current->path_hash !=
ctx->events.prev[device_no]->path_hash))
+ {
+// enter/leave should snapshot chain to root
+// and compare with previous snapshotted chain to root
+// and emit/enter/leave as appropriate..
+//
+// leave might be registered for emission on enter..emission?
+
+
+ //int focus_radius = 2;
+ if (current)
+ _ctx_item_ref (current);
+
+ if (ctx->events.prev[device_no])
{
- ctx_log ("ctx:%i:%i %c got %i instead of %i args\n",
- parser->line, parser->col,
- cmd, parser->n_numbers, parser->expected_args);
+ {
+#if 0
+ CtxIntRectangle rect = {floor(ctx->events.prev[device_no]->x0-focus_radius),
+ floor(ctx->events.prev[device_no]->y0-focus_radius),
+ ceil(ctx->events.prev[device_no]->x1)-floor(ctx->events.prev[device_no]->x0) +
focus_radius * 2,
+ ceil(ctx->events.prev[device_no]->y1)-floor(ctx->events.prev[device_no]->y0) +
focus_radius * 2};
+ mrg_queue_draw (mrg, &rect);
+#endif
+ }
+
+ _ctx_emit_cb_item (ctx, ctx->events.prev[device_no], NULL, CTX_LEAVE, x, y);
+ _ctx_item_unref (ctx->events.prev[device_no]);
+ ctx->events.prev[device_no] = NULL;
}
-#define arg(a) (parser->numbers[a])
- parser->command = CTX_NOP;
- switch (cmd)
+ if (current)
{
- default:
- break; // to silence warnings about missing ones
- case CTX_PRESERVE:
- ctx_preserve (ctx);
- break;
- case CTX_FILL:
- ctx_fill (ctx);
- break;
- case CTX_SAVE:
- ctx_save (ctx);
- break;
- case CTX_START_GROUP:
- ctx_start_group (ctx);
- break;
- case CTX_END_GROUP:
- ctx_end_group (ctx);
- break;
- case CTX_STROKE:
- ctx_stroke (ctx);
- break;
- case CTX_RESTORE:
- ctx_restore (ctx);
- break;
-#if CTX_ENABLE_CM
- case CTX_COLOR_SPACE:
- if (parser->n_numbers == 1)
- {
- parser->color_space_slot = arg(0);
- parser->command = CTX_COLOR_SPACE; // did this work without?
- }
- else
- {
- ctx_colorspace (ctx, parser->color_space_slot,
- parser->holding, parser->pos);
- }
- break;
+#if 0
+ {
+ CtxIntRectangle rect = {floor(current->x0-focus_radius),
+ floor(current->y0-focus_radius),
+ ceil(current->x1)-floor(current->x0) + focus_radius * 2,
+ ceil(current->y1)-floor(current->y0) + focus_radius * 2};
+ mrg_queue_draw (mrg, &rect);
+ }
#endif
- case CTX_KERNING_PAIR:
- switch (parser->n_args)
- {
- case 0:
- parser->numbers[0] = ctx_utf8_to_unichar ((char*)parser->holding);
- break;
- case 1:
- parser->numbers[1] = ctx_utf8_to_unichar ((char*)parser->holding);
- break;
- case 2:
- parser->numbers[2] = ctx_utf8_to_unichar ((char*)parser->holding);
- {
- CtxEntry e = {CTX_KERNING_PAIR, };
- e.data.u16[0] = parser->numbers[0];
- e.data.u16[1] = parser->numbers[1];
- e.data.s32[2] = parser->numbers[2] * 256;
- ctx_process (ctx, &e);
- }
- break;
- }
- parser->command = CTX_KERNING_PAIR;
- parser->n_args ++; // make this more generic?
- break;
- case CTX_DEFINE_GLYPH:
- /* XXX : reuse n_args logic - to enforce order */
- if (parser->n_numbers == 1)
- {
- CtxEntry e = {CTX_DEFINE_GLYPH, };
- e.data.u32[0] = parser->color_space_slot;
- e.data.u32[1] = arg(0) * 256;
- ctx_process (ctx, &e);
- }
- else
- {
- int unichar = ctx_utf8_to_unichar ((char*)parser->holding);
- parser->color_space_slot = unichar;
- }
- parser->command = CTX_DEFINE_GLYPH;
- break;
+ _ctx_emit_cb_item (ctx, current, NULL, CTX_ENTER, x, y);
+ ctx->events.prev[device_no] = current;
+ }
+ }
+ current = _ctx_detect (ctx, x, y, type);
+ //fprintf (stderr, "%p\n", current);
+ return current;
+}
- case CTX_COLOR:
- {
- switch (parser->color_model)
- {
- case CTX_GRAY:
- ctx_gray (ctx, arg (0) );
- break;
- case CTX_GRAYA:
- ctx_rgba (ctx, arg (0), arg (0), arg (0), arg (1) );
- break;
- case CTX_RGB:
- ctx_rgb (ctx, arg (0), arg (1), arg (2) );
- break;
-#if CTX_ENABLE_CMYK
- case CTX_CMYK:
- ctx_cmyk (ctx, arg (0), arg (1), arg (2), arg (3) );
- break;
- case CTX_CMYKA:
- ctx_cmyka (ctx, arg (0), arg (1), arg (2), arg (3), arg (4) );
- break;
-#else
- /* when there is no cmyk support at all in rasterizer
- * do a naive mapping to RGB on input.
- */
- case CTX_CMYK:
- case CTX_CMYKA:
- {
- float r,g,b,a = 1.0f;
- ctx_cmyk_to_rgb (arg (0), arg (1), arg (2), arg (3), &r, &g, &b);
- if (parser->color_model == CTX_CMYKA)
- { a = arg (4); }
- ctx_rgba (ctx, r, g, b, a);
- }
- break;
-#endif
- case CTX_RGBA:
- ctx_rgba (ctx, arg (0), arg (1), arg (2), arg (3) );
- break;
- case CTX_DRGB:
- ctx_drgba (ctx, arg (0), arg (1), arg (2), 1.0);
- break;
- case CTX_DRGBA:
- ctx_drgba (ctx, arg (0), arg (1), arg (2), arg (3) );
- break;
- }
- }
- break;
- case CTX_LINE_DASH:
- if (parser->n_numbers)
- {
- ctx_line_dash (ctx, parser->numbers, parser->n_numbers);
- }
- else
- {
- ctx_line_dash (ctx, NULL, 0);
- }
- //append_dash_val (ctx, arg(0));
- break;
- case CTX_ARC_TO:
- ctx_arc_to (ctx, arg (0), arg (1), arg (2), arg (3), arg (4) );
- break;
- case CTX_REL_ARC_TO:
- ctx_rel_arc_to (ctx, arg (0), arg (1), arg (2), arg (3), arg (4) );
- break;
- case CTX_REL_SMOOTH_TO:
- {
- float cx = parser->pcx;
- float cy = parser->pcy;
- float ax = 2 * ctx_x (ctx) - cx;
- float ay = 2 * ctx_y (ctx) - cy;
- ctx_curve_to (ctx, ax, ay, arg (0) + cx, arg (1) + cy,
- arg (2) + cx, arg (3) + cy);
- parser->pcx = arg (0) + cx;
- parser->pcy = arg (1) + cy;
- }
- break;
- case CTX_SMOOTH_TO:
- {
- float ax = 2 * ctx_x (ctx) - parser->pcx;
- float ay = 2 * ctx_y (ctx) - parser->pcy;
- ctx_curve_to (ctx, ax, ay, arg (0), arg (1),
- arg (2), arg (3) );
- parser->pcx = arg (0);
- parser->pcx = arg (1);
- }
- break;
- case CTX_SMOOTHQ_TO:
- ctx_quad_to (ctx, parser->pcx, parser->pcy, arg (0), arg (1) );
- break;
- case CTX_REL_SMOOTHQ_TO:
- {
- float cx = parser->pcx;
- float cy = parser->pcy;
- parser->pcx = 2 * ctx_x (ctx) - parser->pcx;
- parser->pcy = 2 * ctx_y (ctx) - parser->pcy;
- ctx_quad_to (ctx, parser->pcx, parser->pcy, arg (0) + cx, arg (1) + cy);
- }
- break;
- case CTX_VER_LINE_TO:
- ctx_line_to (ctx, ctx_x (ctx), arg (0) );
- parser->command = CTX_VER_LINE_TO;
- parser->pcx = ctx_x (ctx);
- parser->pcy = ctx_y (ctx);
- break;
- case CTX_HOR_LINE_TO:
- ctx_line_to (ctx, arg (0), ctx_y (ctx) );
- parser->command = CTX_HOR_LINE_TO;
- parser->pcx = ctx_x (ctx);
- parser->pcy = ctx_y (ctx);
- break;
- case CTX_REL_HOR_LINE_TO:
- ctx_rel_line_to (ctx, arg (0), 0.0f);
- parser->command = CTX_REL_HOR_LINE_TO;
- parser->pcx = ctx_x (ctx);
- parser->pcy = ctx_y (ctx);
- break;
- case CTX_REL_VER_LINE_TO:
- ctx_rel_line_to (ctx, 0.0f, arg (0) );
- parser->command = CTX_REL_VER_LINE_TO;
- parser->pcx = ctx_x (ctx);
- parser->pcy = ctx_y (ctx);
- break;
- case CTX_ARC:
- ctx_arc (ctx, arg (0), arg (1), arg (2), arg (3), arg (4), arg (5) );
- break;
- case CTX_APPLY_TRANSFORM:
- ctx_apply_transform (ctx, arg (0), arg (1), arg (2), arg (3), arg (4), arg (5) );
- break;
- case CTX_CURVE_TO:
- ctx_curve_to (ctx, arg (0), arg (1), arg (2), arg (3), arg (4), arg (5) );
- parser->pcx = arg (2);
- parser->pcy = arg (3);
- parser->command = CTX_CURVE_TO;
- break;
- case CTX_REL_CURVE_TO:
- parser->pcx = arg (2) + ctx_x (ctx);
- parser->pcy = arg (3) + ctx_y (ctx);
- ctx_rel_curve_to (ctx, arg (0), arg (1), arg (2), arg (3), arg (4), arg (5) );
- parser->command = CTX_REL_CURVE_TO;
- break;
- case CTX_LINE_TO:
- ctx_line_to (ctx, arg (0), arg (1) );
- parser->command = CTX_LINE_TO;
- parser->pcx = arg (0);
- parser->pcy = arg (1);
- break;
- case CTX_MOVE_TO:
- ctx_move_to (ctx, arg (0), arg (1) );
- parser->command = CTX_LINE_TO;
- parser->pcx = arg (0);
- parser->pcy = arg (1);
- parser->left_margin = parser->pcx;
- break;
- case CTX_FONT_SIZE:
- ctx_font_size (ctx, arg (0) );
- break;
- case CTX_MITER_LIMIT:
- ctx_miter_limit (ctx, arg (0) );
- break;
- case CTX_SCALE:
- ctx_scale (ctx, arg (0), arg (1) );
- break;
- case CTX_QUAD_TO:
- parser->pcx = arg (0);
- parser->pcy = arg (1);
- ctx_quad_to (ctx, arg (0), arg (1), arg (2), arg (3) );
- parser->command = CTX_QUAD_TO;
- break;
- case CTX_REL_QUAD_TO:
- parser->pcx = arg (0) + ctx_x (ctx);
- parser->pcy = arg (1) + ctx_y (ctx);
- ctx_rel_quad_to (ctx, arg (0), arg (1), arg (2), arg (3) );
- parser->command = CTX_REL_QUAD_TO;
- break;
- case CTX_CLIP:
- ctx_clip (ctx);
- break;
- case CTX_TRANSLATE:
- ctx_translate (ctx, arg (0), arg (1) );
- break;
- case CTX_ROTATE:
- ctx_rotate (ctx, arg (0) );
- break;
- case CTX_FONT:
- ctx_font (ctx, (char *) parser->holding);
- break;
+static int tap_and_hold_fire (Ctx *ctx, void *data)
+{
+ CtxGrab *grab = data;
+ CtxList *list = NULL;
+ ctx_list_prepend (&list, grab->item);
+ CtxEvent event = {0, };
- case CTX_TEXT_STROKE:
- case CTX_TEXT:
- if (parser->n_numbers == 1)
- { ctx_rel_move_to (ctx, -parser->numbers[0], 0.0); } // XXX : scale by font(size)
- else
- {
- for (char *c = (char *) parser->holding; c; )
- {
- char *next_nl = ctx_strchr (c, '\n');
- if (next_nl)
- { *next_nl = 0; }
- /* do our own layouting on a per-word basis?, to get justified
- * margins? then we'd want explict margins rather than the
- * implicit ones from move_to's .. making move_to work within
- * margins.
- */
- if (cmd == CTX_TEXT_STROKE)
- { ctx_text_stroke (ctx, c); }
- else
- { ctx_text (ctx, c); }
- if (next_nl)
- {
- *next_nl = '\n'; // swap it newline back in
- ctx_move_to (ctx, parser->left_margin, ctx_y (ctx) +
- ctx_get_font_size (ctx) );
- c = next_nl + 1;
- if (c[0] == 0)
- { c = NULL; }
- }
- else
- {
- c = NULL;
- }
- }
- }
- if (cmd == CTX_TEXT_STROKE)
- { parser->command = CTX_TEXT_STROKE; }
- else
- { parser->command = CTX_TEXT; }
- break;
- case CTX_REL_LINE_TO:
- ctx_rel_line_to (ctx, arg(0), arg(1) );
- parser->pcx += arg(0);
- parser->pcy += arg(1);
- break;
- case CTX_REL_MOVE_TO:
- ctx_rel_move_to (ctx, arg(0), arg(1) );
- parser->pcx += arg(0);
- parser->pcy += arg(1);
- parser->left_margin = ctx_x (ctx);
- break;
- case CTX_LINE_WIDTH:
- ctx_line_width (ctx, arg(0) );
- break;
- case CTX_SHADOW_COLOR:
- ctx_shadow_rgba (ctx, arg(0), arg(1), arg(2), arg(3));
- break;
- case CTX_SHADOW_BLUR:
- ctx_shadow_blur (ctx, arg(0) );
- break;
- case CTX_SHADOW_OFFSET_X:
- ctx_shadow_offset_x (ctx, arg(0) );
- break;
- case CTX_SHADOW_OFFSET_Y:
- ctx_shadow_offset_y (ctx, arg(0) );
- break;
- case CTX_LINE_JOIN:
- ctx_line_join (ctx, (CtxLineJoin) arg(0) );
- break;
- case CTX_LINE_CAP:
- ctx_line_cap (ctx, (CtxLineCap) arg(0) );
- break;
- case CTX_COMPOSITING_MODE:
- ctx_compositing_mode (ctx, (CtxCompositingMode) arg(0) );
- break;
- case CTX_BLEND_MODE:
- {
- int blend_mode = arg(0);
- if (blend_mode == CTX_COLOR) blend_mode = CTX_BLEND_COLOR;
- ctx_blend_mode (ctx, (CtxBlend)blend_mode);
- }
- break;
- case CTX_FILL_RULE:
- ctx_fill_rule (ctx, (CtxFillRule) arg(0) );
- break;
- case CTX_TEXT_ALIGN:
- ctx_text_align (ctx, (CtxTextAlign) arg(0) );
- break;
- case CTX_TEXT_BASELINE:
- ctx_text_baseline (ctx, (CtxTextBaseline) arg(0) );
- break;
- case CTX_TEXT_DIRECTION:
- ctx_text_direction (ctx, (CtxTextDirection) arg(0) );
- break;
- case CTX_IDENTITY:
- ctx_identity (ctx);
- break;
- case CTX_RECTANGLE:
- ctx_rectangle (ctx, arg(0), arg(1), arg(2), arg(3) );
- break;
- case CTX_ROUND_RECTANGLE:
- ctx_round_rectangle (ctx, arg(0), arg(1), arg(2), arg(3), arg(4));
- break;
- case CTX_VIEW_BOX:
- ctx_view_box (ctx, arg(0), arg(1), arg(2), arg(3) );
- break;
- case CTX_LINEAR_GRADIENT:
- ctx_linear_gradient (ctx, arg(0), arg(1), arg(2), arg(3) );
- break;
- case CTX_RADIAL_GRADIENT:
- ctx_radial_gradient (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
- break;
- case CTX_GRADIENT_STOP:
- {
- float red, green, blue, alpha;
- ctx_parser_get_color_rgba (parser, 1, &red, &green, &blue, &alpha);
- ctx_gradient_add_stop (ctx, arg(0), red, green, blue, alpha);
- }
- break;
- case CTX_GLOBAL_ALPHA:
- ctx_global_alpha (ctx, arg(0) );
- break;
- case CTX_TEXTURE:
- ctx_texture (ctx, arg(0), arg(1), arg(2));
- break;
- case CTX_BEGIN_PATH:
- ctx_begin_path (ctx);
- break;
- case CTX_GLYPH:
- ctx_glyph (ctx, arg(0), 0);
- break;
- case CTX_CLOSE_PATH:
- ctx_close_path (ctx);
- break;
- case CTX_EXIT:
- if (parser->exit)
- { parser->exit (parser->exit_data);
- return;
- }
- break;
- case CTX_FLUSH:
- //ctx_flush (ctx);
- break;
- case CTX_RESET:
- ctx_reset (ctx);
- ctx_translate (ctx,
- (parser->cursor_x-1) * parser->cell_width * 1.0,
- (parser->cursor_y-1) * parser->cell_height * 1.0);
- break;
- }
-#undef arg
- parser->n_numbers = 0;
-}
+ event.ctx = ctx;
+ event.time = ctx_ms (ctx);
-static void ctx_parser_holding_append (CtxParser *parser, int byte)
-{
- parser->holding[parser->pos++]=byte;
- if (parser->pos > (int) sizeof (parser->holding)-2)
- { parser->pos = sizeof (parser->holding)-2; }
- parser->holding[parser->pos]=0;
+ event.device_x =
+ event.x = ctx->events.pointer_x[grab->device_no];
+ event.device_y =
+ event.y = ctx->events.pointer_y[grab->device_no];
+
+ // XXX: x and y coordinates
+ int ret = _ctx_emit_cb (ctx, list, &event, CTX_TAP_AND_HOLD,
+ ctx->events.pointer_x[grab->device_no], ctx->events.pointer_y[grab->device_no]);
+
+ ctx_list_free (&list);
+
+ grab->timeout_id = 0;
+
+ return 0;
+
+ return ret;
}
-static void ctx_parser_transform_percent (CtxParser *parser, CtxCode code, int arg_no, float *value)
+int ctx_pointer_drop (Ctx *ctx, float x, float y, int device_no, uint32_t time,
+ char *string)
{
- int big = parser->width;
- int small = parser->height;
- if (big < small)
- {
- small = parser->width;
- big = parser->height;
- }
- switch (code)
+ CtxList *l;
+ CtxList *hitlist = NULL;
+
+ ctx->events.pointer_x[device_no] = x;
+ ctx->events.pointer_y[device_no] = y;
+ if (device_no <= 3)
+ {
+ ctx->events.pointer_x[0] = x;
+ ctx->events.pointer_y[0] = y;
+ }
+
+ if (device_no < 0) device_no = 0;
+ if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
+ CtxEvent *event = &ctx->events.drag_event[device_no];
+
+ if (time == 0)
+ time = ctx_ms (ctx);
+
+ event->ctx = ctx;
+ event->x = x;
+ event->y = y;
+
+ event->delta_x = event->delta_y = 0;
+
+ event->device_no = device_no;
+ event->string = string;
+ event->time = time;
+ event->stop_propagate = 0;
+
+ _ctx_update_item (ctx, device_no, x, y, CTX_DROP, &hitlist);
+
+ for (l = hitlist; l; l = l?l->next:NULL)
+ {
+ CtxItem *item = l->data;
+ _ctx_emit_cb_item (ctx, item, event, CTX_DROP, x, y);
+
+ if (event->stop_propagate)
{
- case CTX_RADIAL_GRADIENT:
- case CTX_ARC:
- switch (arg_no)
- {
- case 0:
- case 3:
- *value *= (parser->width/100.0);
- break;
- case 1:
- case 4:
- *value *= (parser->height/100.0);
- break;
- case 2:
- case 5:
- *value *= small/100.0;
- break;
- }
- break;
- case CTX_FONT_SIZE:
- case CTX_MITER_LIMIT:
- case CTX_LINE_WIDTH:
- {
- *value *= (small/100.0);
- }
- break;
- case CTX_ARC_TO:
- case CTX_REL_ARC_TO:
- if (arg_no > 3)
- {
- *value *= (small/100.0);
- }
- else
- {
- if (arg_no % 2 == 0)
- { *value *= ( (parser->width) /100.0); }
- else
- { *value *= ( (parser->height) /100.0); }
- }
- break;
- case CTX_ROUND_RECTANGLE:
- if (arg_no == 4)
- {
- { *value *= ((parser->height)/100.0); }
- return;
- }
- /* FALLTHROUGH */
- default: // even means x coord
- if (arg_no % 2 == 0)
- { *value *= ((parser->width)/100.0); }
- else
- { *value *= ((parser->height)/100.0); }
- break;
+ ctx_list_free (&hitlist);
+ return 0;
}
-}
+ }
-static void ctx_parser_transform_percent_height (CtxParser *parser, CtxCode code, int arg_no, float *value)
-{
- *value *= (parser->height/100.0);
-}
+ //mrg_queue_draw (mrg, NULL); /* in case of style change, and more */
+ ctx_list_free (&hitlist);
-static void ctx_parser_transform_percent_width (CtxParser *parser, CtxCode code, int arg_no, float *value)
-{
- *value *= (parser->height/100.0);
+ return 0;
}
-static void ctx_parser_transform_cell (CtxParser *parser, CtxCode code, int arg_no, float *value)
+int ctx_pointer_press (Ctx *ctx, float x, float y, int device_no, uint32_t time)
{
- float small = parser->cell_width;
- if (small > parser->cell_height)
- { small = parser->cell_height; }
- switch (code)
- {
- case CTX_RADIAL_GRADIENT:
- case CTX_ARC:
- switch (arg_no)
- {
- case 0:
- case 3:
- *value *= parser->cell_width;
- break;
- case 1:
- case 4:
- *value *= parser->cell_height;
- break;
- case 2:
- case 5:
- *value *= small; // use height?
- break;
- }
- break;
- case CTX_MITER_LIMIT:
- case CTX_FONT_SIZE:
- case CTX_LINE_WIDTH:
- {
- *value *= parser->cell_height;
- }
- break;
- case CTX_ARC_TO:
- case CTX_REL_ARC_TO:
- if (arg_no > 3)
- {
- *value *= small;
- }
- else
- {
- *value *= (arg_no%2==0) ?parser->cell_width:parser->cell_height;
- }
- break;
- case CTX_RECTANGLE:
- if (arg_no % 2 == 0)
- { *value *= parser->cell_width; }
- else
- {
- if (! (arg_no > 1) )
- { (*value) -= 1.0f; }
- *value *= parser->cell_height;
- }
- break;
- default: // even means x coord odd means y coord
- *value *= (arg_no%2==0) ?parser->cell_width:parser->cell_height;
- break;
- }
-}
+ CtxEvents *events = &ctx->events;
+ CtxList *hitlist = NULL;
+ events->pointer_x[device_no] = x;
+ events->pointer_y[device_no] = y;
+ if (device_no <= 3)
+ {
+ events->pointer_x[0] = x;
+ events->pointer_y[0] = y;
+ }
-// %h %v %m %M
+ if (device_no < 0) device_no = 0;
+ if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
+ CtxEvent *event = &events->drag_event[device_no];
-static void ctx_parser_word_done (CtxParser *parser)
-{
- parser->holding[parser->pos]=0;
- int old_args = parser->expected_args;
- int command = ctx_parser_resolve_command (parser, parser->holding);
- if ((command >= 0 && command < 32)
- || (command > 150) || (command < 0)
- ) // special case low enum values
- { // and enum values too high to be
- // commands - permitting passing words
- // for strings in some cases
- parser->numbers[parser->n_numbers] = command;
+ if (time == 0)
+ time = ctx_ms (ctx);
- // trigger transition from number
- parser->state = CTX_PARSER_NUMBER;
- ctx_parser_feed_byte (parser, ',');
- }
- else if (command > 0)
+ event->x = event->start_x = event->prev_x = x;
+ event->y = event->start_y = event->prev_y = y;
+
+ event->delta_x = event->delta_y = 0;
+
+ event->device_no = device_no;
+ event->time = time;
+ event->stop_propagate = 0;
+
+ if (events->pointer_down[device_no] == 1)
+ {
+ fprintf (stderr, "events thought device %i was already down\n", device_no);
+ }
+ /* doing just one of these two should be enough? */
+ events->pointer_down[device_no] = 1;
+ switch (device_no)
+ {
+ case 1:
+ events->modifier_state |= CTX_MODIFIER_STATE_BUTTON1;
+ break;
+ case 2:
+ events->modifier_state |= CTX_MODIFIER_STATE_BUTTON2;
+ break;
+ case 3:
+ events->modifier_state |= CTX_MODIFIER_STATE_BUTTON3;
+ break;
+ default:
+ break;
+ }
+
+ CtxGrab *grab = NULL;
+ CtxList *l;
+
+ _ctx_update_item (ctx, device_no, x, y,
+ CTX_PRESS | CTX_DRAG_PRESS | CTX_TAP | CTX_TAP_AND_HOLD, &hitlist);
+
+ for (l = hitlist; l; l = l?l->next:NULL)
+ {
+ CtxItem *item = l->data;
+ if (item &&
+ ((item->types & CTX_DRAG)||
+ (item->types & CTX_TAP) ||
+ (item->types & CTX_TAP_AND_HOLD)))
{
- if (old_args == CTX_ARG_COLLECT_NUMBERS)
+ grab = device_add_grab (ctx, device_no, item, item->types);
+ grab->start_time = time;
+
+ if (item->types & CTX_TAP_AND_HOLD)
{
- int tmp1 = parser->command;
- int tmp2 = parser->expected_args;
- ctx_parser_dispatch_command (parser);
- parser->command = (CtxCode)tmp1;
- parser->expected_args = tmp2;
+ grab->timeout_id = ctx_add_timeout (ctx, events->tap_delay_hold, tap_and_hold_fire, grab);
}
-
- parser->command = (CtxCode) command;
- if (parser->expected_args == 0)
- {
- ctx_parser_dispatch_command (parser);
- }
}
- else
+ _ctx_emit_cb_item (ctx, item, event, CTX_PRESS, x, y);
+ if (!event->stop_propagate)
+ _ctx_emit_cb_item (ctx, item, event, CTX_DRAG_PRESS, x, y);
+
+ if (event->stop_propagate)
{
- /* interpret char by char */
- uint8_t buf[16]=" ";
- for (int i = 0; parser->pos && parser->holding[i] > ' '; i++)
- {
- buf[0] = parser->holding[i];
- parser->command = (CtxCode) ctx_parser_resolve_command (parser, buf);
- if (parser->command > 0)
- {
- if (parser->expected_args == 0)
- {
- ctx_parser_dispatch_command (parser);
- }
- }
- else
- {
- ctx_log ("unhandled command '%c'\n", buf[0]);
- }
- }
+ ctx_list_free (&hitlist);
+ return 0;
}
- parser->n_numbers = 0;
- parser->n_args = 0;
+ }
+
+ //events_queue_draw (mrg, NULL); /* in case of style change, and more */
+ ctx_list_free (&hitlist);
+ return 0;
}
-static void ctx_parser_string_done (CtxParser *parser)
+void _ctx_resized (Ctx *ctx, int width, int height, long time)
{
- ctx_parser_dispatch_command (parser);
+ CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_PRESS);
+ CtxEvent event = {0, };
+
+ if (!time)
+ time = ctx_ms (ctx);
+
+ event.ctx = ctx;
+ event.time = time;
+ event.string = "resize-event"; /* gets delivered to clients as a key_down event, maybe message shouldbe
used instead?
+ */
+
+ if (item)
+ {
+ event.stop_propagate = 0;
+ _ctx_emit_cb_item (ctx, item, &event, CTX_KEY_PRESS, 0, 0);
+ }
+
}
-void ctx_parser_feed_byte (CtxParser *parser, int byte)
+int ctx_pointer_release (Ctx *ctx, float x, float y, int device_no, uint32_t time)
{
- switch (byte)
- {
- case '\n':
- parser->col=0;
- parser->line++;
- break;
- default:
- parser->col++;
- }
- switch (parser->state)
+ CtxEvents *events = &ctx->events;
+ if (time == 0)
+ time = ctx_ms (ctx);
+
+ if (device_no < 0) device_no = 0;
+ if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
+ CtxEvent *event = &events->drag_event[device_no];
+
+ event->time = time;
+ event->x = x;
+ event->ctx = ctx;
+ event->y = y;
+ event->device_no = device_no;
+ event->stop_propagate = 0;
+
+ switch (device_no)
+ {
+ case 1:
+ if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON1)
+ events->modifier_state -= CTX_MODIFIER_STATE_BUTTON1;
+ break;
+ case 2:
+ if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON2)
+ events->modifier_state -= CTX_MODIFIER_STATE_BUTTON2;
+ break;
+ case 3:
+ if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON3)
+ events->modifier_state -= CTX_MODIFIER_STATE_BUTTON3;
+ break;
+ default:
+ break;
+ }
+
+ //events_queue_draw (mrg, NULL); /* in case of style change */
+
+ if (events->pointer_down[device_no] == 0)
+ {
+ fprintf (stderr, "device %i already up\n", device_no);
+ }
+ events->pointer_down[device_no] = 0;
+
+ events->pointer_x[device_no] = x;
+ events->pointer_y[device_no] = y;
+ if (device_no <= 3)
+ {
+ events->pointer_x[0] = x;
+ events->pointer_y[0] = y;
+ }
+ CtxList *hitlist = NULL;
+ CtxList *grablist = NULL , *g= NULL;
+ CtxGrab *grab;
+
+ _ctx_update_item (ctx, device_no, x, y, CTX_RELEASE | CTX_DRAG_RELEASE, &hitlist);
+ grablist = device_get_grabs (ctx, device_no);
+
+ for (g = grablist; g; g = g->next)
+ {
+ grab = g->data;
+
+ if (!event->stop_propagate)
{
- case CTX_PARSER_NEUTRAL:
- switch (byte)
- {
- case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 11: case 12: case
14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case
26: case 27: case 28: case 29: case 30: case 31:
- break;
- case ' ': case '\t': case '\r': case '\n':
- case ';': case ',':
- case '(': case ')':
- case '{': case '}':
- case '=':
+ if (grab->item->types & CTX_TAP)
+ {
+ long delay = time - grab->start_time;
+
+ if (delay > events->tap_delay_min &&
+ delay < events->tap_delay_max &&
+ (
+ (event->start_x - x) * (event->start_x - x) +
+ (event->start_y - y) * (event->start_y - y)) < ctx_pow2(events->tap_hysteresis)
+ )
+ {
+ _ctx_emit_cb_item (ctx, grab->item, event, CTX_TAP, x, y);
+ }
+ }
+
+ if (!event->stop_propagate && grab->item->types & CTX_DRAG_RELEASE)
+ {
+ _ctx_emit_cb_item (ctx, grab->item, event, CTX_DRAG_RELEASE, x, y);
+ }
+ }
+
+ device_remove_grab (ctx, grab);
+ }
+
+ if (hitlist)
+ {
+ if (!event->stop_propagate)
+ _ctx_emit_cb (ctx, hitlist, event, CTX_RELEASE, x, y);
+ ctx_list_free (&hitlist);
+ }
+ ctx_list_free (&grablist);
+ return 0;
+}
+
+/* for multi-touch, we use a list of active grabs - thus a grab corresponds to
+ * a device id. even during drag-grabs events propagate; to stop that stop
+ * propagation.
+ */
+int ctx_pointer_motion (Ctx *ctx, float x, float y, int device_no, uint32_t time)
+{
+ CtxList *hitlist = NULL;
+ CtxList *grablist = NULL, *g;
+ CtxGrab *grab;
+
+ if (device_no < 0) device_no = 0;
+ if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
+ CtxEvent *event = &ctx->events.drag_event[device_no];
+
+ if (time == 0)
+ time = ctx_ms (ctx);
+
+ event->ctx = ctx;
+ event->x = x;
+ event->y = y;
+ event->time = time;
+ event->device_no = device_no;
+ event->stop_propagate = 0;
+
+ ctx->events.pointer_x[device_no] = x;
+ ctx->events.pointer_y[device_no] = y;
+
+ if (device_no <= 3)
+ {
+ ctx->events.pointer_x[0] = x;
+ ctx->events.pointer_y[0] = y;
+ }
+
+ grablist = device_get_grabs (ctx, device_no);
+ _ctx_update_item (ctx, device_no, x, y, CTX_MOTION, &hitlist);
+
+ {
+ CtxItem *cursor_item = _ctx_detect (ctx, x, y, CTX_SET_CURSOR);
+ if (cursor_item)
+ {
+ ctx_set_cursor (ctx, cursor_item->cursor);
+ }
+ else
+ {
+ ctx_set_cursor (ctx, CTX_CURSOR_ARROW);
+ }
+ CtxItem *hovered_item = _ctx_detect (ctx, x, y, CTX_ANY);
+ static CtxItem *prev_hovered_item = NULL;
+ if (prev_hovered_item != hovered_item)
+ {
+ ctx_set_dirty (ctx, 1);
+ }
+ prev_hovered_item = hovered_item;
+ }
+
+ event->delta_x = x - event->prev_x;
+ event->delta_y = y - event->prev_y;
+ event->prev_x = x;
+ event->prev_y = y;
+
+ CtxList *remove_grabs = NULL;
+
+ for (g = grablist; g; g = g->next)
+ {
+ grab = g->data;
+
+ if ((grab->type & CTX_TAP) ||
+ (grab->type & CTX_TAP_AND_HOLD))
+ {
+ if (
+ (
+ (event->start_x - x) * (event->start_x - x) +
+ (event->start_y - y) * (event->start_y - y)) >
+ ctx_pow2(ctx->events.tap_hysteresis)
+ )
+ {
+ //fprintf (stderr, "-");
+ ctx_list_prepend (&remove_grabs, grab);
+ }
+ else
+ {
+ //fprintf (stderr, ":");
+ }
+ }
+
+ if (grab->type & CTX_DRAG_MOTION)
+ {
+ _ctx_emit_cb_item (ctx, grab->item, event, CTX_DRAG_MOTION, x, y);
+ if (event->stop_propagate)
+ break;
+ }
+ }
+ if (remove_grabs)
+ {
+ for (g = remove_grabs; g; g = g->next)
+ device_remove_grab (ctx, g->data);
+ ctx_list_free (&remove_grabs);
+ }
+ if (hitlist)
+ {
+ if (!event->stop_propagate)
+ _ctx_emit_cb (ctx, hitlist, event, CTX_MOTION, x, y);
+ ctx_list_free (&hitlist);
+ }
+ ctx_list_free (&grablist);
+ return 0;
+}
+
+void ctx_incoming_message (Ctx *ctx, const char *message, long time)
+{
+ CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_MESSAGE);
+ CtxEvent event = {0, };
+
+ if (!time)
+ time = ctx_ms (ctx);
+
+ if (item)
+ {
+ int i;
+ event.ctx = ctx;
+ event.type = CTX_MESSAGE;
+ event.time = time;
+ event.string = message;
+
+ fprintf (stderr, "{%s|\n", message);
+
+ for (i = 0; i < item->cb_count; i++)
+ {
+ if (item->cb[i].types & (CTX_MESSAGE))
+ {
+ event.state = ctx->events.modifier_state;
+ item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
+ if (event.stop_propagate)
+ return;// event.stop_propagate;
+ }
+ }
+ }
+}
+
+int ctx_scrolled (Ctx *ctx, float x, float y, CtxScrollDirection scroll_direction, uint32_t time)
+{
+ CtxList *hitlist = NULL;
+ CtxList *l;
+
+ int device_no = 0;
+ ctx->events.pointer_x[device_no] = x;
+ ctx->events.pointer_y[device_no] = y;
+
+ CtxEvent *event = &ctx->events.drag_event[device_no]; /* XXX: might
+ conflict with other code
+ create a sibling member
+ of drag_event?*/
+ if (time == 0)
+ time = ctx_ms (ctx);
+
+ event->x = event->start_x = event->prev_x = x;
+ event->y = event->start_y = event->prev_y = y;
+ event->delta_x = event->delta_y = 0;
+ event->device_no = device_no;
+ event->time = time;
+ event->stop_propagate = 0;
+ event->scroll_direction = scroll_direction;
+
+ _ctx_update_item (ctx, device_no, x, y, CTX_SCROLL, &hitlist);
+
+ for (l = hitlist; l; l = l?l->next:NULL)
+ {
+ CtxItem *item = l->data;
+
+ _ctx_emit_cb_item (ctx, item, event, CTX_SCROLL, x, y);
+
+ if (event->stop_propagate)
+ l = NULL;
+ }
+
+ //mrg_queue_draw (mrg, NULL); /* in case of style change, and more */
+ ctx_list_free (&hitlist);
+ return 0;
+}
+
+static int ctx_str_has_prefix (const char *string, const char *prefix)
+{
+ for (int i = 0; prefix[i]; i++)
+ {
+ if (!string[i]) return 0;
+ if (string[i] != prefix[i]) return 0;
+ }
+ return 0;
+}
+
+int ctx_key_press (Ctx *ctx, unsigned int keyval,
+ const char *string, uint32_t time)
+{
+ char event_type[128]="";
+ float x, y; int b;
+ sscanf (string, "%s %f %f %i", event_type, &x, &y, &b);
+ if (!strcmp (event_type, "mouse-motion") ||
+ !strcmp (event_type, "mouse-drag"))
+ return ctx_pointer_motion (ctx, x, y, b, 0);
+ else if (!strcmp (event_type, "mouse-press"))
+ return ctx_pointer_press (ctx, x, y, b, 0);
+ else if (!strcmp (event_type, "mouse-release"))
+ return ctx_pointer_release (ctx, x, y, b, 0);
+ //else if (!strcmp (event_type, "keydown"))
+ // return ctx_key_down (ctx, keyval, string + 8, time);
+ //else if (!strcmp (event_type, "keyup"))
+ // return ctx_key_up (ctx, keyval, string + 6, time);
+
+ CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_PRESS);
+ CtxEvent event = {0,};
+
+ if (time == 0)
+ time = ctx_ms (ctx);
+ if (item)
+ {
+ int i;
+ event.ctx = ctx;
+ event.type = CTX_KEY_PRESS;
+ event.unicode = keyval;
+ event.string = strdup(string);
+ event.stop_propagate = 0;
+ event.time = time;
+
+ for (i = 0; i < item->cb_count; i++)
+ {
+ if (item->cb[i].types & (CTX_KEY_PRESS))
+ {
+ event.state = ctx->events.modifier_state;
+ item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
+ if (event.stop_propagate)
+ {
+ free ((void*)event.string);
+ return event.stop_propagate;
+ }
+ }
+ }
+ free ((void*)event.string);
+ }
+ return 0;
+}
+
+int ctx_key_down (Ctx *ctx, unsigned int keyval,
+ const char *string, uint32_t time)
+{
+ CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_DOWN);
+ CtxEvent event = {0,};
+
+ if (time == 0)
+ time = ctx_ms (ctx);
+ if (item)
+ {
+ int i;
+ event.ctx = ctx;
+ event.type = CTX_KEY_DOWN;
+ event.unicode = keyval;
+ event.string = strdup(string);
+ event.stop_propagate = 0;
+ event.time = time;
+
+ for (i = 0; i < item->cb_count; i++)
+ {
+ if (item->cb[i].types & (CTX_KEY_DOWN))
+ {
+ event.state = ctx->events.modifier_state;
+ item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
+ if (event.stop_propagate)
+ {
+ free ((void*)event.string);
+ return event.stop_propagate;
+ }
+ }
+ }
+ free ((void*)event.string);
+ }
+ return 0;
+}
+
+int ctx_key_up (Ctx *ctx, unsigned int keyval,
+ const char *string, uint32_t time)
+{
+ CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_UP);
+ CtxEvent event = {0,};
+
+ if (time == 0)
+ time = ctx_ms (ctx);
+ if (item)
+ {
+ int i;
+ event.ctx = ctx;
+ event.type = CTX_KEY_UP;
+ event.unicode = keyval;
+ event.string = strdup(string);
+ event.stop_propagate = 0;
+ event.time = time;
+
+ for (i = 0; i < item->cb_count; i++)
+ {
+ if (item->cb[i].types & (CTX_KEY_UP))
+ {
+ event.state = ctx->events.modifier_state;
+ item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
+ if (event.stop_propagate)
+ {
+ free ((void*)event.string);
+ return event.stop_propagate;
+ }
+ }
+ }
+ free ((void*)event.string);
+ }
+ return 0;
+
+ return 0;
+}
+
+void ctx_freeze (Ctx *ctx)
+{
+ ctx->events.frozen ++;
+}
+
+void ctx_thaw (Ctx *ctx)
+{
+ ctx->events.frozen --;
+}
+int ctx_events_frozen (Ctx *ctx)
+{
+ return ctx && ctx->events.frozen;
+}
+void ctx_events_clear_items (Ctx *ctx)
+{
+ ctx_list_free (&ctx->events.items);
+}
+int ctx_events_width (Ctx *ctx)
+{
+ return ctx->events.width;
+}
+int ctx_events_height (Ctx *ctx)
+{
+ return ctx->events.height;
+}
+
+float ctx_pointer_x (Ctx *ctx)
+{
+ return ctx->events.pointer_x[0];
+}
+
+float ctx_pointer_y (Ctx *ctx)
+{
+ return ctx->events.pointer_y[0];
+}
+
+int ctx_pointer_is_down (Ctx *ctx, int no)
+{
+ if (no < 0 || no > CTX_MAX_DEVICES) return 0;
+ return ctx->events.pointer_down[no];
+}
+
+void _ctx_debug_overlays (Ctx *ctx)
+{
+ CtxList *a;
+ ctx_save (ctx);
+
+ ctx_line_width (ctx, 2);
+ ctx_rgba (ctx, 0,0,0.8,0.5);
+ for (a = ctx->events.items; a; a = a->next)
+ {
+ float current_x = ctx_pointer_x (ctx);
+ float current_y = ctx_pointer_y (ctx);
+ CtxItem *item = a->data;
+ CtxMatrix matrix = item->inv_matrix;
+
+ ctx_matrix_apply_transform (&matrix, ¤t_x, ¤t_y);
+
+ if (current_x >= item->x0 && current_x < item->x1 &&
+ current_y >= item->y0 && current_y < item->y1)
+ {
+ ctx_matrix_invert (&matrix);
+ ctx_set_matrix (ctx, &matrix);
+ _mrg_restore_path (ctx, item->path);
+ ctx_stroke (ctx);
+ }
+ }
+ ctx_restore (ctx);
+}
+
+void ctx_set_render_threads (Ctx *ctx, int n_threads)
+{
+ // XXX
+}
+int ctx_get_render_threads (Ctx *ctx)
+{
+ return _ctx_max_threads;
+}
+void ctx_set_hash_cache (Ctx *ctx, int enable_hash_cache)
+{
+ _ctx_enable_hash_cache = enable_hash_cache;
+}
+int ctx_get_hash_cache (Ctx *ctx)
+{
+ return _ctx_enable_hash_cache;
+}
+
+int ctx_is_dirty (Ctx *ctx)
+{
+ return ctx->dirty;
+}
+void ctx_set_dirty (Ctx *ctx, int dirty)
+{
+ ctx->dirty = dirty;
+}
+
+/*
+ * centralized global API for managing file descriptors that
+ * wake us up, this to remove sleeping and polling
+ */
+
+#define CTX_MAX_LISTEN_FDS 8
+static int _ctx_listen_fd[CTX_MAX_LISTEN_FDS];
+static int _ctx_listen_fds = 0;
+static int _ctx_listen_max_fd = 0;
+
+void _ctx_add_listen_fd (int fd)
+{
+ _ctx_listen_fd[_ctx_listen_fds++]=fd;
+ if (fd > _ctx_listen_max_fd)
+ _ctx_listen_max_fd = fd;
+}
+
+void _ctx_remove_listen_fd (int fd)
+{
+ for (int i = 0; i < _ctx_listen_fds; i++)
+ {
+ if (_ctx_listen_fd[i] == fd)
+ {
+ _ctx_listen_fd[i] = _ctx_listen_fd[_ctx_listen_fds-1];
+ _ctx_listen_fds--;
+ return;
+ }
+ }
+}
+
+int _ctx_data_pending (int timeout)
+{
+ struct timeval tv;
+ fd_set fdset;
+ FD_ZERO (&fdset);
+ for (int i = 0; i < _ctx_listen_fds; i++)
+ {
+ FD_SET (_ctx_listen_fd[i], &fdset);
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = timeout;
+ tv.tv_sec = timeout / 1000000;
+ tv.tv_usec = timeout % 1000000;
+ int retval = select (_ctx_listen_max_fd, &fdset, NULL, NULL, &tv);
+ if (retval == -1)
+ {
+ perror ("select");
+ return 0;
+ }
+ return retval;
+}
+
+void ctx_sdl_set_title (void *self, const char *new_title);
+void ctx_set_title (Ctx *ctx, const char *title)
+{
+#if CTX_SDL
+ // XXX also check we're first/only client?
+ if (ctx_renderer_is_sdl (ctx))
+ ctx_sdl_set_title (ctx_get_renderer (ctx), title);
+#endif
+}
+
+#endif
+/* the parser comes in the end, nothing in ctx knows about the parser */
+
+#if CTX_PARSER
+
+/* ctx parser, */
+
+#define CTX_ID_MAXLEN 64 // in use should not be more than 40!
+ // to offer headroom for multiplexing
+
+
+struct
+ _CtxParser
+{
+ Ctx *ctx;
+ int t_args; // total number of arguments seen for current command
+ int state;
+#if CTX_PARSER_FIXED_TEMP
+ uint8_t holding[CTX_PARSER_MAXLEN]; /* */
+#else
+ uint8_t *holding;
+#endif
+ int hold_len;
+ int pos;
+
+
+ int line; /* for error reporting */
+ int col; /* for error reporting */
+ float numbers[CTX_PARSER_MAX_ARGS+1];
+ int n_numbers;
+ int decimal;
+ CtxCode command;
+ int expected_args; /* low digits are literal higher values
+ carry special meaning */
+ int n_args;
+ int texture_done;
+ uint8_t texture_id[CTX_ID_MAXLEN]; // used in defineTexture only
+ uint64_t set_key_hash;
+ float pcx;
+ float pcy;
+ int color_components;
+ int color_stroke; // 0 is fill source 1 is stroke source
+ int color_model; // 1 gray 3 rgb 4 cmyk
+ float left_margin; // set by last user provided move_to
+ int width; // <- maybe should be float
+ int height;
+ float cell_width;
+ float cell_height;
+ int cursor_x; // <- leaking in from terminal
+ int cursor_y;
+
+ int color_space_slot;
+
+ void (*exit) (void *exit_data);
+ void *exit_data;
+ int (*set_prop)(void *prop_data, uint64_t key, const char *data, int len);
+ int (*get_prop)(void *prop_data, const char *key, char **data, int *len);
+ void *prop_data;
+};
+
+void
+ctx_parser_set_size (CtxParser *parser,
+ int width,
+ int height,
+ float cell_width,
+ float cell_height)
+{
+ if (cell_width > 0)
+ parser->cell_width = cell_width;
+ if (cell_height > 0)
+ parser->cell_height = cell_height;
+ if (width > 0)
+ parser->width = width;
+ if (height > 0)
+ parser->height = height;
+}
+
+static CtxParser *
+ctx_parser_init (CtxParser *parser,
+ Ctx *ctx,
+ int width,
+ int height,
+ float cell_width,
+ float cell_height,
+ int cursor_x,
+ int cursor_y,
+ int (*set_prop)(void *prop_data, uint64_t key, const char *data, int len),
+ int (*get_prop)(void *prop_Data, const char *key, char **data, int *len),
+ void *prop_data,
+ void (*exit) (void *exit_data),
+ void *exit_data
+ )
+{
+ ctx_memset (parser, 0, sizeof (CtxParser) );
+ parser->line = 1;
+ parser->ctx = ctx;
+ parser->cell_width = cell_width;
+ parser->cell_height = cell_height;
+ parser->cursor_x = cursor_x;
+ parser->cursor_y = cursor_y;
+ parser->width = width;
+ parser->height = height;
+ parser->exit = exit;
+ parser->exit_data = exit_data;
+ parser->color_model = CTX_RGBA;
+ parser->color_stroke = 0;
+ parser->color_components = 4;
+ parser->command = CTX_MOVE_TO;
+ parser->set_prop = set_prop;
+ parser->get_prop = get_prop;
+ parser->prop_data = prop_data;
+ return parser;
+}
+
+CtxParser *ctx_parser_new (
+ Ctx *ctx,
+ int width,
+ int height,
+ float cell_width,
+ float cell_height,
+ int cursor_x,
+ int cursor_y,
+ int (*set_prop)(void *prop_data, uint64_t key, const char *data, int len),
+ int (*get_prop)(void *prop_Data, const char *key, char **data, int *len),
+ void *prop_data,
+ void (*exit) (void *exit_data),
+ void *exit_data)
+{
+ return ctx_parser_init ( (CtxParser *) ctx_calloc (sizeof (CtxParser), 1),
+ ctx,
+ width, height,
+ cell_width, cell_height,
+ cursor_x, cursor_y, set_prop, get_prop, prop_data,
+ exit, exit_data);
+}
+
+void ctx_parser_free (CtxParser *parser)
+{
+#if !CTX_PARSER_FIXED_TEMP
+ if (parser->holding)
+ free (parser->holding);
+#endif
+ free (parser);
+}
+
+#define CTX_ARG_COLLECT_NUMBERS 50
+#define CTX_ARG_STRING_OR_NUMBER 100
+#define CTX_ARG_NUMBER_OF_COMPONENTS 200
+#define CTX_ARG_NUMBER_OF_COMPONENTS_PLUS_1 201
+
+static int ctx_arguments_for_code (CtxCode code)
+{
+ switch (code)
+ {
+ case CTX_SAVE:
+ case CTX_START_GROUP:
+ case CTX_END_GROUP:
+ case CTX_IDENTITY:
+ case CTX_CLOSE_PATH:
+ case CTX_BEGIN_PATH:
+ case CTX_RESET:
+ case CTX_FLUSH:
+ case CTX_RESTORE:
+ case CTX_STROKE:
+ case CTX_FILL:
+ case CTX_NEW_PAGE:
+ case CTX_CLIP:
+ case CTX_EXIT:
+ return 0;
+ case CTX_GLOBAL_ALPHA:
+ case CTX_COMPOSITING_MODE:
+ case CTX_BLEND_MODE:
+ case CTX_FONT_SIZE:
+ case CTX_LINE_JOIN:
+ case CTX_LINE_CAP:
+ case CTX_LINE_WIDTH:
+ case CTX_LINE_DASH_OFFSET:
+ case CTX_IMAGE_SMOOTHING:
+ case CTX_SHADOW_BLUR:
+ case CTX_SHADOW_OFFSET_X:
+ case CTX_SHADOW_OFFSET_Y:
+ case CTX_FILL_RULE:
+ case CTX_TEXT_ALIGN:
+ case CTX_TEXT_BASELINE:
+ case CTX_TEXT_DIRECTION:
+ case CTX_MITER_LIMIT:
+ case CTX_REL_VER_LINE_TO:
+ case CTX_REL_HOR_LINE_TO:
+ case CTX_HOR_LINE_TO:
+ case CTX_VER_LINE_TO:
+ case CTX_FONT:
+ case CTX_ROTATE:
+ case CTX_GLYPH:
+ return 1;
+ case CTX_TRANSLATE:
+ case CTX_REL_SMOOTHQ_TO:
+ case CTX_LINE_TO:
+ case CTX_MOVE_TO:
+ case CTX_SCALE:
+ case CTX_REL_LINE_TO:
+ case CTX_REL_MOVE_TO:
+ case CTX_SMOOTHQ_TO:
+ return 2;
+ case CTX_LINEAR_GRADIENT:
+ case CTX_REL_QUAD_TO:
+ case CTX_QUAD_TO:
+ case CTX_RECTANGLE:
+ case CTX_FILL_RECT:
+ case CTX_STROKE_RECT:
+ case CTX_REL_SMOOTH_TO:
+ case CTX_VIEW_BOX:
+ case CTX_SMOOTH_TO:
+ return 4;
+ case CTX_ARC_TO:
+ case CTX_REL_ARC_TO:
+ case CTX_ROUND_RECTANGLE:
+ return 5;
+ case CTX_ARC:
+ case CTX_CURVE_TO:
+ case CTX_REL_CURVE_TO:
+ case CTX_APPLY_TRANSFORM:
+ case CTX_RADIAL_GRADIENT:
+ return 6;
+ case CTX_STROKE_TEXT:
+ case CTX_TEXT:
+ case CTX_COLOR_SPACE:
+ case CTX_DEFINE_GLYPH:
+ case CTX_KERNING_PAIR:
+ case CTX_TEXTURE:
+ case CTX_DEFINE_TEXTURE:
+ return CTX_ARG_STRING_OR_NUMBER;
+ case CTX_LINE_DASH: /* append to current dashes for each argument encountered */
+ return CTX_ARG_COLLECT_NUMBERS;
+ //case CTX_SET_KEY:
+ case CTX_COLOR:
+ case CTX_SHADOW_COLOR:
+ return CTX_ARG_NUMBER_OF_COMPONENTS;
+ case CTX_GRADIENT_STOP:
+ return CTX_ARG_NUMBER_OF_COMPONENTS_PLUS_1;
+
+ default:
+#if 1
+ case CTX_SET_RGBA_U8:
+ case CTX_NOP:
+ case CTX_NEW_EDGE:
+ case CTX_EDGE:
+ case CTX_EDGE_FLIPPED:
+ case CTX_CONT:
+ case CTX_DATA:
+ case CTX_DATA_REV:
+ case CTX_SET_PIXEL:
+ case CTX_REL_LINE_TO_X4:
+ case CTX_REL_LINE_TO_REL_CURVE_TO:
+ case CTX_REL_CURVE_TO_REL_LINE_TO:
+ case CTX_REL_CURVE_TO_REL_MOVE_TO:
+ case CTX_REL_LINE_TO_X2:
+ case CTX_MOVE_TO_REL_LINE_TO:
+ case CTX_REL_LINE_TO_REL_MOVE_TO:
+ case CTX_FILL_MOVE_TO:
+ case CTX_REL_QUAD_TO_REL_QUAD_TO:
+ case CTX_REL_QUAD_TO_S16:
+#endif
+ return 0;
+ }
+}
+
+static int ctx_parser_set_command (CtxParser *parser, CtxCode code)
+{
+ if (code < 150 && code >= 32)
+ {
+ parser->expected_args = ctx_arguments_for_code (code);
+ parser->n_args = 0;
+ parser->texture_done = 0;
+ if (parser->expected_args >= CTX_ARG_NUMBER_OF_COMPONENTS)
+ {
+ parser->expected_args = (parser->expected_args % 100) + parser->color_components;
+ }
+ }
+ return code;
+}
+
+static void ctx_parser_set_color_model (CtxParser *parser, CtxColorModel color_model, int stroke);
+
+static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
+{
+ uint64_t ret = str[0]; /* if it is single char it already is the CtxCode */
+
+ /* this is handled outside the hashing to make it possible to be case insensitive
+ * with the rest.
+ */
+ if (str[0] == CTX_SET_KEY && str[1] && str[2] == 0)
+ {
+ switch (str[1])
+ {
+ case 'm': return ctx_parser_set_command (parser, CTX_COMPOSITING_MODE);
+ case 'B': return ctx_parser_set_command (parser, CTX_BLEND_MODE);
+ case 'l': return ctx_parser_set_command (parser, CTX_MITER_LIMIT);
+ case 't': return ctx_parser_set_command (parser, CTX_TEXT_ALIGN);
+ case 'b': return ctx_parser_set_command (parser, CTX_TEXT_BASELINE);
+ case 'd': return ctx_parser_set_command (parser, CTX_TEXT_DIRECTION);
+ case 'j': return ctx_parser_set_command (parser, CTX_LINE_JOIN);
+ 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 '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);
+ case 'x': return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_X);
+ case 'y': return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_Y);
+ case 'a': return ctx_parser_set_command (parser, CTX_GLOBAL_ALPHA);
+ case 'f': return ctx_parser_set_command (parser, CTX_FONT_SIZE);
+ case 'r': return ctx_parser_set_command (parser, CTX_FILL_RULE);
+ }
+ }
+
+ if (str[0] && str[1])
+ {
+ uint64_t str_hash;
+ /* trim ctx_ and CTX_ prefix */
+ if ( (str[0] == 'c' && str[1] == 't' && str[2] == 'x' && str[3] == '_') ||
+ (str[0] == 'C' && str[1] == 'T' && str[2] == 'X' && str[3] == '_') )
+ {
+ str += 4;
+ }
+ if ( (str[0] == 's' && str[1] == 'e' && str[2] == 't' && str[3] == '_') )
+ { str += 4; }
+ str_hash = ctx_strhash ( (char *) str, 0);
+ switch (str_hash)
+ {
+ /* first a list of mappings to one_char hashes, handled in a
+ * separate fast path switch without hashing
+ */
+ case CTX_arcTo: ret = CTX_ARC_TO; break;
+ case CTX_arc: ret = CTX_ARC; break;
+ case CTX_curveTo: ret = CTX_CURVE_TO; break;
+ case CTX_restore: ret = CTX_RESTORE; break;
+ case CTX_stroke: ret = CTX_STROKE; break;
+ case CTX_fill: ret = CTX_FILL; break;
+ case CTX_flush: ret = CTX_FLUSH; break;
+ case CTX_horLineTo: ret = CTX_HOR_LINE_TO; break;
+ case CTX_rotate: ret = CTX_ROTATE; break;
+ case CTX_color: ret = CTX_COLOR; break;
+ case CTX_lineTo: ret = CTX_LINE_TO; break;
+ case CTX_moveTo: ret = CTX_MOVE_TO; break;
+ case CTX_scale: ret = CTX_SCALE; break;
+ 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_clear: ret = CTX_COMPOSITE_CLEAR; break;
+ case CTX_copy: ret = CTX_COMPOSITE_COPY; break;
+ case CTX_destinationOver: ret = CTX_COMPOSITE_DESTINATION_OVER; break;
+ case CTX_destinationIn: ret = CTX_COMPOSITE_DESTINATION_IN; break;
+ case CTX_destinationOut: ret = CTX_COMPOSITE_DESTINATION_OUT; break;
+ case CTX_sourceOver: ret = CTX_COMPOSITE_SOURCE_OVER; break;
+ case CTX_sourceAtop: ret = CTX_COMPOSITE_SOURCE_ATOP; break;
+ case CTX_destinationAtop: ret = CTX_COMPOSITE_DESTINATION_ATOP; break;
+ case CTX_sourceOut: ret = CTX_COMPOSITE_SOURCE_OUT; break;
+ case CTX_sourceIn: ret = CTX_COMPOSITE_SOURCE_IN; break;
+ case CTX_xor: ret = CTX_COMPOSITE_XOR; break;
+ case CTX_darken: ret = CTX_BLEND_DARKEN; break;
+ case CTX_lighten: ret = CTX_BLEND_LIGHTEN; break;
+ //case CTX_color: ret = CTX_BLEND_COLOR; break;
+ //
+ // XXX check that he special casing for color works
+ // it is the first collision and it is due to our own
+ // color, not w3c for now unique use of it
+ //
+ case CTX_hue: ret = CTX_BLEND_HUE; break;
+ case CTX_multiply: ret = CTX_BLEND_MULTIPLY; break;
+ 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_verLineTo: ret = CTX_VER_LINE_TO; break;
+ case CTX_exit:
+ case CTX_done: ret = CTX_EXIT; break;
+ case CTX_closePath: ret = CTX_CLOSE_PATH; break;
+ case CTX_beginPath:
+ case CTX_newPath: ret = CTX_BEGIN_PATH; break;
+ case CTX_relArcTo: ret = CTX_REL_ARC_TO; break;
+ case CTX_clip: ret = CTX_CLIP; break;
+ case CTX_relCurveTo: ret = CTX_REL_CURVE_TO; break;
+ case CTX_startGroup: ret = CTX_START_GROUP; break;
+ case CTX_endGroup: ret = CTX_END_GROUP; break;
+ case CTX_save: ret = CTX_SAVE; break;
+ case CTX_translate: ret = CTX_TRANSLATE; break;
+ case CTX_linearGradient: ret = CTX_LINEAR_GRADIENT; break;
+ case CTX_relHorLineTo: ret = CTX_REL_HOR_LINE_TO; break;
+ case CTX_relLineTo: ret = CTX_REL_LINE_TO; break;
+ case CTX_relMoveTo: ret = CTX_REL_MOVE_TO; break;
+ case CTX_font: ret = CTX_FONT; break;
+ case CTX_radialGradient:ret = CTX_RADIAL_GRADIENT; break;
+ case CTX_gradientAddStop:
+ case CTX_addStop: ret = CTX_GRADIENT_STOP; break;
+ case CTX_relQuadTo: ret = CTX_REL_QUAD_TO; break;
+ case CTX_rectangle:
+ case CTX_rect: ret = CTX_RECTANGLE; break;
+ case CTX_roundRectangle: ret = CTX_ROUND_RECTANGLE; break;
+ case CTX_relSmoothTo: ret = CTX_REL_SMOOTH_TO; break;
+ case CTX_relSmoothqTo: ret = CTX_REL_SMOOTHQ_TO; break;
+ case CTX_strokeText: ret = CTX_STROKE_TEXT; break;
+ case CTX_strokeRect: ret = CTX_STROKE_RECT; break;
+ case CTX_fillRect: ret = CTX_FILL_RECT; break;
+ case CTX_relVerLineTo: ret = CTX_REL_VER_LINE_TO; break;
+ case CTX_text: ret = CTX_TEXT; break;
+ case CTX_identity: ret = CTX_IDENTITY; break;
+ case CTX_transform: ret = CTX_APPLY_TRANSFORM; break;
+ case CTX_texture: ret = CTX_TEXTURE; break;
+ case CTX_defineTexture: ret = CTX_DEFINE_TEXTURE; break;
+#if 0
+ case CTX_rgbSpace:
+ return ctx_parser_set_command (parser, CTX_SET_RGB_SPACE);
+ case CTX_cmykSpace:
+ return ctx_parser_set_command (parser, CTX_SET_CMYK_SPACE);
+ case CTX_drgbSpace:
+ return ctx_parser_set_command (parser, CTX_SET_DRGB_SPACE);
+#endif
+ case CTX_defineGlyph:
+ return ctx_parser_set_command (parser, CTX_DEFINE_GLYPH);
+ case CTX_kerningPair:
+ return ctx_parser_set_command (parser, CTX_KERNING_PAIR);
+
+ case CTX_colorSpace:
+ return ctx_parser_set_command (parser, CTX_COLOR_SPACE);
+ case CTX_fillRule:
+ return ctx_parser_set_command (parser, CTX_FILL_RULE);
+ case CTX_fontSize:
+ case CTX_setFontSize:
+ return ctx_parser_set_command (parser, CTX_FONT_SIZE);
+ case CTX_compositingMode:
+ return ctx_parser_set_command (parser, CTX_COMPOSITING_MODE);
+
+ case CTX_blend:
+ case CTX_blending:
+ case CTX_blendMode:
+ return ctx_parser_set_command (parser, CTX_BLEND_MODE);
+
+ case CTX_miterLimit:
+ return ctx_parser_set_command (parser, CTX_MITER_LIMIT);
+ case CTX_textAlign:
+ return ctx_parser_set_command (parser, CTX_TEXT_ALIGN);
+ case CTX_textBaseline:
+ return ctx_parser_set_command (parser, CTX_TEXT_BASELINE);
+ case CTX_textDirection:
+ return ctx_parser_set_command (parser, CTX_TEXT_DIRECTION);
+ case CTX_join:
+ case CTX_lineJoin:
+ case CTX_setLineJoin:
+ return ctx_parser_set_command (parser, CTX_LINE_JOIN);
+ case CTX_glyph:
+ return ctx_parser_set_command (parser, CTX_GLYPH);
+ case CTX_cap:
+ case CTX_lineCap:
+ case CTX_setLineCap:
+ return ctx_parser_set_command (parser, CTX_LINE_CAP);
+ case CTX_lineDash:
+ return ctx_parser_set_command (parser, CTX_LINE_DASH);
+ case CTX_lineWidth:
+ case CTX_setLineWidth:
+ return ctx_parser_set_command (parser, CTX_LINE_WIDTH);
+ case CTX_lineDashOffset:
+ return ctx_parser_set_command (parser, CTX_LINE_DASH_OFFSET);
+ case CTX_imageSmoothing:
+ return ctx_parser_set_command (parser, CTX_IMAGE_SMOOTHING);
+ case CTX_shadowColor:
+ return ctx_parser_set_command (parser, CTX_SHADOW_COLOR);
+ case CTX_shadowBlur:
+ return ctx_parser_set_command (parser, CTX_SHADOW_BLUR);
+ case CTX_shadowOffsetX:
+ return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_X);
+ case CTX_shadowOffsetY:
+ return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_Y);
+ case CTX_globalAlpha:
+ return ctx_parser_set_command (parser, CTX_GLOBAL_ALPHA);
+
+ /* strings are handled directly here,
+ * instead of in the one-char handler, using return instead of break
+ */
+ case CTX_gray:
+ ctx_parser_set_color_model (parser, CTX_GRAY, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_graya:
+ ctx_parser_set_color_model (parser, CTX_GRAYA, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_rgb:
+ ctx_parser_set_color_model (parser, CTX_RGB, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_drgb:
+ ctx_parser_set_color_model (parser, CTX_DRGB, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_rgba:
+ ctx_parser_set_color_model (parser, CTX_RGBA, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_drgba:
+ ctx_parser_set_color_model (parser, CTX_DRGBA, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_cmyk:
+ ctx_parser_set_color_model (parser, CTX_CMYK, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_cmyka:
+ ctx_parser_set_color_model (parser, CTX_CMYKA, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_lab:
+ ctx_parser_set_color_model (parser, CTX_LAB, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_laba:
+ ctx_parser_set_color_model (parser, CTX_LABA, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_lch:
+ ctx_parser_set_color_model (parser, CTX_LCH, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_lcha:
+ ctx_parser_set_color_model (parser, CTX_LCHA, 0);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+
+ /* and a full repeat of the above, with S for Stroke suffix */
+ case CTX_grayS:
+ ctx_parser_set_color_model (parser, CTX_GRAY, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_grayaS:
+ ctx_parser_set_color_model (parser, CTX_GRAYA, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_rgbS:
+ ctx_parser_set_color_model (parser, CTX_RGB, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_drgbS:
+ ctx_parser_set_color_model (parser, CTX_DRGB, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_rgbaS:
+ ctx_parser_set_color_model (parser, CTX_RGBA, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_drgbaS:
+ ctx_parser_set_color_model (parser, CTX_DRGBA, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_cmykS:
+ ctx_parser_set_color_model (parser, CTX_CMYK, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_cmykaS:
+ ctx_parser_set_color_model (parser, CTX_CMYKA, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_labS:
+ ctx_parser_set_color_model (parser, CTX_LAB, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_labaS:
+ ctx_parser_set_color_model (parser, CTX_LABA, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_lchS:
+ ctx_parser_set_color_model (parser, CTX_LCH, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+ case CTX_lchaS:
+ ctx_parser_set_color_model (parser, CTX_LCHA, 1);
+ return ctx_parser_set_command (parser, CTX_COLOR);
+
+ /* words that correspond to low integer constants
+ */
+ case CTX_winding: return CTX_FILL_RULE_WINDING;
+ case CTX_evenOdd:
+ case CTX_even_odd: 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;
+ case CTX_none: return CTX_CAP_NONE;
+ case CTX_square: return CTX_CAP_SQUARE;
+ case CTX_start: return CTX_TEXT_ALIGN_START;
+ case CTX_end: return CTX_TEXT_ALIGN_END;
+ case CTX_left: return CTX_TEXT_ALIGN_LEFT;
+ case CTX_right: return CTX_TEXT_ALIGN_RIGHT;
+ case CTX_center: return CTX_TEXT_ALIGN_CENTER;
+ case CTX_top: return CTX_TEXT_BASELINE_TOP;
+ case CTX_bottom : return CTX_TEXT_BASELINE_BOTTOM;
+ case CTX_middle: return CTX_TEXT_BASELINE_MIDDLE;
+ case CTX_alphabetic: return CTX_TEXT_BASELINE_ALPHABETIC;
+ case CTX_hanging: return CTX_TEXT_BASELINE_HANGING;
+ case CTX_ideographic: return CTX_TEXT_BASELINE_IDEOGRAPHIC;
+
+ case CTX_userRGB: return CTX_COLOR_SPACE_USER_RGB;
+ case CTX_deviceRGB: return CTX_COLOR_SPACE_DEVICE_RGB;
+ case CTX_userCMYK: return CTX_COLOR_SPACE_USER_CMYK;
+ case CTX_deviceCMYK: return CTX_COLOR_SPACE_DEVICE_CMYK;
+#undef STR
+#undef LOWER
+ default:
+ ret = str_hash;
+ }
+ }
+ if (ret == CTX_CLOSE_PATH2)
+ { ret = CTX_CLOSE_PATH; }
+ /* handling single char, and ret = foo; break; in cases above*/
+ return ctx_parser_set_command (parser, (CtxCode) ret);
+}
+
+enum
+{
+ CTX_PARSER_NEUTRAL = 0,
+ CTX_PARSER_NUMBER,
+ CTX_PARSER_NEGATIVE_NUMBER,
+ CTX_PARSER_WORD,
+ CTX_PARSER_COMMENT,
+ CTX_PARSER_STRING_APOS,
+ CTX_PARSER_STRING_QUOT,
+ CTX_PARSER_STRING_APOS_ESCAPED,
+ CTX_PARSER_STRING_QUOT_ESCAPED,
+ CTX_PARSER_STRING_A85,
+} CTX_STATE;
+
+static void ctx_parser_set_color_model (CtxParser *parser, CtxColorModel color_model, int stroke)
+{
+ parser->color_model = color_model;
+ parser->color_stroke = stroke;
+ parser->color_components = ctx_color_model_get_components (color_model);
+}
+
+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;
+ switch (parser->color_model)
+ {
+ case CTX_GRAYA:
+ *alpha = parser->numbers[offset + 1];
+ /* FALLTHROUGH */
+ case CTX_GRAY:
+ *red = *green = *blue = parser->numbers[offset + 0];
+ break;
+ default:
+ case CTX_LABA: // NYI - needs RGB profile
+ case CTX_LCHA: // NYI - needs RGB profile
+ case CTX_RGBA:
+ *alpha = parser->numbers[offset + 3];
+ /* FALLTHROUGH */
+ case CTX_LAB: // NYI
+ case CTX_LCH: // NYI
+ case CTX_RGB:
+ *red = parser->numbers[offset + 0];
+ *green = parser->numbers[offset + 1];
+ *blue = parser->numbers[offset + 2];
+ break;
+ case CTX_CMYKA:
+ *alpha = parser->numbers[offset + 4];
+ /* 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]);
+ break;
+ }
+}
+
+static void ctx_parser_dispatch_command (CtxParser *parser)
+{
+ CtxCode cmd = parser->command;
+ Ctx *ctx = parser->ctx;
+#if 1
+ if (parser->expected_args != CTX_ARG_STRING_OR_NUMBER &&
+ parser->expected_args != CTX_ARG_COLLECT_NUMBERS &&
+ parser->expected_args != parser->n_numbers)
+ {
+ if (0)
+ fprintf (stderr, "ctx:%i:%i %c got %i instead of %i args\n",
+ parser->line, parser->col,
+ cmd, parser->n_numbers, parser->expected_args);
+ }
+#endif
+
+#define arg(a) (parser->numbers[a])
+ parser->command = CTX_NOP;
+ //parser->n_args = 0;
+ switch (cmd)
+ {
+ default:
+ break; // to silence warnings about missing ones
+ case CTX_PRESERVE:
+ ctx_preserve (ctx);
+ break;
+ case CTX_FILL:
+ ctx_fill (ctx);
+ break;
+ case CTX_SAVE:
+ ctx_save (ctx);
+ break;
+ case CTX_START_GROUP:
+ ctx_start_group (ctx);
+ break;
+ case CTX_END_GROUP:
+ ctx_end_group (ctx);
+ break;
+ case CTX_STROKE:
+ ctx_stroke (ctx);
+ break;
+ case CTX_RESTORE:
+ ctx_restore (ctx);
+ break;
+#if CTX_ENABLE_CM
+ case CTX_COLOR_SPACE:
+ if (parser->n_numbers == 1)
+ {
+ parser->color_space_slot = arg(0);
+ parser->command = CTX_COLOR_SPACE; // did this work without?
+ }
+ else
+ {
+ ctx_colorspace (ctx, parser->color_space_slot,
+ parser->holding, parser->pos);
+ }
+ break;
+#endif
+ case CTX_KERNING_PAIR:
+ switch (parser->n_args)
+ {
+ case 0:
+ parser->numbers[0] = ctx_utf8_to_unichar ((char*)parser->holding);
+ break;
+ case 1:
+ parser->numbers[1] = ctx_utf8_to_unichar ((char*)parser->holding);
+ break;
+ case 2:
+ parser->numbers[2] = strtod ((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;
+ ctx_process (ctx, &e);
+ }
+ break;
+ }
+ parser->command = CTX_KERNING_PAIR;
+ parser->n_args ++; // make this more generic?
+ break;
+ case CTX_TEXTURE:
+ if (parser->texture_done)
+ {
+ }
+ else
+ if (parser->n_numbers == 2)
+ {
+ const char *eid = (char*)parser->holding;
+ float x0 = arg(0);
+ float x1 = arg(1);
+ ctx_texture (ctx, eid, x0, x1);
+ parser->texture_done = 1;
+ }
+ parser->command = CTX_TEXTURE;
+ //parser->n_args++;
+ break;
+ case CTX_DEFINE_TEXTURE:
+ if (parser->texture_done)
+ {
+ if (parser->texture_done++ == 1)
+ {
+ const char *eid = (char*)parser->texture_id;
+ int width = arg(0);
+ int height = arg(1);
+ int format = arg(2);
+ int stride = ctx_pixel_format_get_stride (format, width);
+
+
+ if (parser->pos != stride * height)
+ {
+ fprintf (stderr, "unexpected datasize for define texture %s %ix%i\n size:%i != expected:%i -
start of data: %i %i %i %i\n", eid, width, height,
+ parser->pos,
+ stride * height,
+ parser->holding[0],
+ parser->holding[1],
+ parser->holding[2],
+ parser->holding[3]
+ );
+ }
+ else
+ ctx_define_texture (ctx, eid, width, height, stride, format, parser->holding, NULL);
+ }
+ }
+ else
+ {
+ switch (parser->n_numbers)
+ {
+ case 0:
+ strncpy ((char*)parser->texture_id, (char*)parser->holding, sizeof(parser->texture_id));
+ parser->texture_id[sizeof(parser->texture_id)-1]=0;
+ break;
+ case 1:
+ case 2:
+ break;
+ case 3:
+ parser->texture_done = 1;
+ break;
+ default:
+ fprintf (stderr, "!!%i\n", parser->n_numbers);
+ break;
+ }
+ }
+ parser->command = CTX_DEFINE_TEXTURE;
+ break;
+
+
+ case CTX_DEFINE_GLYPH:
+ /* XXX : reuse n_args logic - to enforce order */
+ if (parser->n_numbers == 1)
+ {
+ CtxEntry e = {CTX_DEFINE_GLYPH, };
+ e.data.u32[0] = parser->color_space_slot;
+ e.data.u32[1] = arg(0) * 256;
+ ctx_process (ctx, &e);
+ }
+ else
+ {
+ int unichar = ctx_utf8_to_unichar ((char*)parser->holding);
+ parser->color_space_slot = unichar;
+ }
+ parser->command = CTX_DEFINE_GLYPH;
+ break;
+
+ case CTX_COLOR:
+ {
+ switch (parser->color_model)
+ {
+ case CTX_GRAY:
+ case CTX_GRAYA:
+ case CTX_RGB:
+ case CTX_RGBA:
+ case CTX_DRGB:
+ case CTX_DRGBA:
+ ctx_color_raw (ctx, parser->color_model, parser->numbers, parser->color_stroke);
+ break;
+#if CTX_ENABLE_CMYK
+ case CTX_CMYK:
+ case CTX_CMYKA:
+ ctx_color_raw (ctx, parser->color_model, parser->numbers, parser->color_stroke);
+ break;
+#else
+ /* when there is no cmyk support at all in rasterizer
+ * do a naive mapping to RGB on input.
+ */
+ case CTX_CMYK:
+ case CTX_CMYKA:
+ {
+ float rgba[4] = {1,1,1,1.0f};
+
+ ctx_cmyk_to_rgb (arg(0), arg(1), arg(2), arg(3), &rgba[0], &rgba[1], &rgba[2]);
+ if (parser->color_model == CTX_CMYKA)
+ { rgba[3] = arg(4); }
+ ctx_color_raw (ctx, CTX_RGBA, rgba, parser->color_stroke);
+ }
+ break;
+#endif
+ }
+ }
+ break;
+ case CTX_LINE_DASH:
+ if (parser->n_numbers)
+ {
+ ctx_line_dash (ctx, parser->numbers, parser->n_numbers);
+ }
+ else
+ {
+ ctx_line_dash (ctx, NULL, 0);
+ }
+ //append_dash_val (ctx, arg(0));
+ break;
+ case CTX_ARC_TO:
+ ctx_arc_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4));
+ break;
+ case CTX_REL_ARC_TO:
+ ctx_rel_arc_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4) );
+ break;
+ case CTX_REL_SMOOTH_TO:
+ {
+ float cx = parser->pcx;
+ float cy = parser->pcy;
+ float ax = 2 * ctx_x (ctx) - cx;
+ float ay = 2 * ctx_y (ctx) - cy;
+ ctx_curve_to (ctx, ax, ay, arg(0) + cx, arg(1) + cy,
+ arg(2) + cx, arg(3) + cy);
+ parser->pcx = arg(0) + cx;
+ parser->pcy = arg(1) + cy;
+ }
+ break;
+ case CTX_SMOOTH_TO:
+ {
+ float ax = 2 * ctx_x (ctx) - parser->pcx;
+ float ay = 2 * ctx_y (ctx) - parser->pcy;
+ ctx_curve_to (ctx, ax, ay, arg(0), arg(1),
+ arg(2), arg(3) );
+ parser->pcx = arg(0);
+ parser->pcx = arg(1);
+ }
+ break;
+ case CTX_SMOOTHQ_TO:
+ ctx_quad_to (ctx, parser->pcx, parser->pcy, arg(0), arg(1) );
+ break;
+ case CTX_REL_SMOOTHQ_TO:
+ {
+ float cx = parser->pcx;
+ float cy = parser->pcy;
+ parser->pcx = 2 * ctx_x (ctx) - parser->pcx;
+ parser->pcy = 2 * ctx_y (ctx) - parser->pcy;
+ ctx_quad_to (ctx, parser->pcx, parser->pcy, arg(0) + cx, arg(1) + cy);
+ }
+ break;
+ case CTX_VER_LINE_TO:
+ ctx_line_to (ctx, ctx_x (ctx), arg(0) );
+ parser->command = CTX_VER_LINE_TO;
+ parser->pcx = ctx_x (ctx);
+ parser->pcy = ctx_y (ctx);
+ break;
+ case CTX_HOR_LINE_TO:
+ ctx_line_to (ctx, arg(0), ctx_y (ctx) );
+ parser->command = CTX_HOR_LINE_TO;
+ parser->pcx = ctx_x (ctx);
+ parser->pcy = ctx_y (ctx);
+ break;
+ case CTX_REL_HOR_LINE_TO:
+ ctx_rel_line_to (ctx, arg(0), 0.0f);
+ parser->command = CTX_REL_HOR_LINE_TO;
+ parser->pcx = ctx_x (ctx);
+ parser->pcy = ctx_y (ctx);
+ break;
+ case CTX_REL_VER_LINE_TO:
+ ctx_rel_line_to (ctx, 0.0f, arg(0) );
+ parser->command = CTX_REL_VER_LINE_TO;
+ parser->pcx = ctx_x (ctx);
+ parser->pcy = ctx_y (ctx);
+ break;
+ case CTX_ARC:
+ ctx_arc (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
+ break;
+ case CTX_APPLY_TRANSFORM:
+ ctx_apply_transform (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
+ break;
+ case CTX_CURVE_TO:
+ ctx_curve_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
+ parser->pcx = arg(2);
+ parser->pcy = arg(3);
+ parser->command = CTX_CURVE_TO;
+ break;
+ case CTX_REL_CURVE_TO:
+ parser->pcx = arg(2) + ctx_x (ctx);
+ parser->pcy = arg(3) + ctx_y (ctx);
+ ctx_rel_curve_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
+ parser->command = CTX_REL_CURVE_TO;
+ break;
+ case CTX_LINE_TO:
+ ctx_line_to (ctx, arg(0), arg(1) );
+ parser->command = CTX_LINE_TO;
+ parser->pcx = arg(0);
+ parser->pcy = arg(1);
+ break;
+ case CTX_MOVE_TO:
+ ctx_move_to (ctx, arg(0), arg(1) );
+ parser->command = CTX_LINE_TO;
+ parser->pcx = arg(0);
+ parser->pcy = arg(1);
+ parser->left_margin = parser->pcx;
+ break;
+ case CTX_FONT_SIZE:
+ ctx_font_size (ctx, arg(0) );
+ break;
+ case CTX_MITER_LIMIT:
+ ctx_miter_limit (ctx, arg(0) );
+ break;
+ case CTX_SCALE:
+ ctx_scale (ctx, arg(0), arg(1) );
+ break;
+ case CTX_QUAD_TO:
+ parser->pcx = arg(0);
+ parser->pcy = arg(1);
+ ctx_quad_to (ctx, arg(0), arg(1), arg(2), arg(3) );
+ parser->command = CTX_QUAD_TO;
+ break;
+ case CTX_REL_QUAD_TO:
+ parser->pcx = arg(0) + ctx_x (ctx);
+ parser->pcy = arg(1) + ctx_y (ctx);
+ ctx_rel_quad_to (ctx, arg(0), arg(1), arg(2), arg(3) );
+ parser->command = CTX_REL_QUAD_TO;
+ break;
+ case CTX_CLIP:
+ ctx_clip (ctx);
+ break;
+ case CTX_TRANSLATE:
+ ctx_translate (ctx, arg(0), arg(1) );
+ break;
+ case CTX_ROTATE:
+ ctx_rotate (ctx, arg(0) );
+ break;
+ case CTX_FONT:
+ ctx_font (ctx, (char *) parser->holding);
+ break;
+
+ case CTX_STROKE_TEXT:
+ case CTX_TEXT:
+ if (parser->n_numbers == 1)
+ { ctx_rel_move_to (ctx, -parser->numbers[0], 0.0); } // XXX : scale by font(size)
+ else
+ {
+ for (char *c = (char *) parser->holding; c; )
+ {
+ char *next_nl = ctx_strchr (c, '\n');
+ if (next_nl)
+ { *next_nl = 0; }
+ /* do our own layouting on a per-word basis?, to get justified
+ * margins? then we'd want explict margins rather than the
+ * implicit ones from move_to's .. making move_to work within
+ * margins.
+ */
+ if (cmd == CTX_STROKE_TEXT)
+ { ctx_text_stroke (ctx, c); }
+ else
+ { ctx_text (ctx, c); }
+ if (next_nl)
+ {
+ *next_nl = '\n'; // swap it newline back in
+ ctx_move_to (ctx, parser->left_margin, ctx_y (ctx) +
+ ctx_get_font_size (ctx) );
+ c = next_nl + 1;
+ if (c[0] == 0)
+ { c = NULL; }
+ }
+ else
+ {
+ c = NULL;
+ }
+ }
+ }
+ if (cmd == CTX_STROKE_TEXT)
+ { parser->command = CTX_STROKE_TEXT; }
+ else
+ { parser->command = CTX_TEXT; }
+ break;
+ case CTX_REL_LINE_TO:
+ ctx_rel_line_to (ctx, arg(0), arg(1) );
+ parser->pcx += arg(0);
+ parser->pcy += arg(1);
+ break;
+ case CTX_REL_MOVE_TO:
+ ctx_rel_move_to (ctx, arg(0), arg(1) );
+ parser->pcx += arg(0);
+ parser->pcy += arg(1);
+ parser->left_margin = ctx_x (ctx);
+ break;
+ case CTX_LINE_WIDTH:
+ ctx_line_width (ctx, arg(0));
+ break;
+ case CTX_LINE_DASH_OFFSET:
+ ctx_line_dash_offset (ctx, arg(0));
+ break;
+ case CTX_IMAGE_SMOOTHING:
+ ctx_image_smoothing (ctx, arg(0));
+ break;
+ case CTX_SHADOW_COLOR:
+ ctx_shadow_rgba (ctx, arg(0), arg(1), arg(2), arg(3));
+ break;
+ case CTX_SHADOW_BLUR:
+ ctx_shadow_blur (ctx, arg(0) );
+ break;
+ case CTX_SHADOW_OFFSET_X:
+ ctx_shadow_offset_x (ctx, arg(0) );
+ break;
+ case CTX_SHADOW_OFFSET_Y:
+ ctx_shadow_offset_y (ctx, arg(0) );
+ break;
+ case CTX_LINE_JOIN:
+ ctx_line_join (ctx, (CtxLineJoin) arg(0) );
+ break;
+ case CTX_LINE_CAP:
+ ctx_line_cap (ctx, (CtxLineCap) arg(0) );
+ break;
+ case CTX_COMPOSITING_MODE:
+ ctx_compositing_mode (ctx, (CtxCompositingMode) arg(0) );
+ break;
+ case CTX_BLEND_MODE:
+ {
+ int blend_mode = arg(0);
+ if (blend_mode == CTX_COLOR) blend_mode = CTX_BLEND_COLOR;
+ ctx_blend_mode (ctx, (CtxBlend)blend_mode);
+ }
+ break;
+ case CTX_FILL_RULE:
+ ctx_fill_rule (ctx, (CtxFillRule) arg(0) );
+ break;
+ case CTX_TEXT_ALIGN:
+ ctx_text_align (ctx, (CtxTextAlign) arg(0) );
+ break;
+ case CTX_TEXT_BASELINE:
+ ctx_text_baseline (ctx, (CtxTextBaseline) arg(0) );
+ break;
+ case CTX_TEXT_DIRECTION:
+ ctx_text_direction (ctx, (CtxTextDirection) arg(0) );
+ break;
+ case CTX_IDENTITY:
+ ctx_identity (ctx);
+ break;
+ case CTX_RECTANGLE:
+ ctx_rectangle (ctx, arg(0), arg(1), arg(2), arg(3) );
+ break;
+ case CTX_FILL_RECT:
+ ctx_rectangle (ctx, arg(0), arg(1), arg(2), arg(3) );
+ ctx_fill (ctx);
+ break;
+ case CTX_STROKE_RECT:
+ ctx_rectangle (ctx, arg(0), arg(1), arg(2), arg(3) );
+ ctx_stroke (ctx);
+ break;
+ case CTX_ROUND_RECTANGLE:
+ ctx_round_rectangle (ctx, arg(0), arg(1), arg(2), arg(3), arg(4));
+ break;
+ case CTX_VIEW_BOX:
+ ctx_view_box (ctx, arg(0), arg(1), arg(2), arg(3) );
+ break;
+ case CTX_LINEAR_GRADIENT:
+ ctx_linear_gradient (ctx, arg(0), arg(1), arg(2), arg(3) );
+ break;
+ case CTX_RADIAL_GRADIENT:
+ ctx_radial_gradient (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
+ break;
+ case CTX_GRADIENT_STOP:
+ {
+ float red, green, blue, alpha;
+ ctx_parser_get_color_rgba (parser, 1, &red, &green, &blue, &alpha);
+ ctx_gradient_add_stop (ctx, arg(0), red, green, blue, alpha);
+ }
+ break;
+ case CTX_GLOBAL_ALPHA:
+ ctx_global_alpha (ctx, arg(0) );
+ break;
+ case CTX_BEGIN_PATH:
+ ctx_begin_path (ctx);
+ break;
+ case CTX_GLYPH:
+ ctx_glyph (ctx, arg(0), 0);
+ break;
+ case CTX_CLOSE_PATH:
+ ctx_close_path (ctx);
+ break;
+ case CTX_EXIT:
+ if (parser->exit)
+ { parser->exit (parser->exit_data);
+ return;
+ }
+ break;
+ case CTX_FLUSH:
+ //ctx_flush (ctx);
+ break;
+ case CTX_RESET:
+ ctx_reset (ctx);
+ ctx_translate (ctx,
+ (parser->cursor_x-1) * parser->cell_width * 1.0,
+ (parser->cursor_y-1) * parser->cell_height * 1.0);
+ break;
+ }
+#undef arg
+// parser->n_numbers = 0;
+}
+
+static void ctx_parser_holding_append (CtxParser *parser, int byte)
+{
+#if !CTX_PARSER_FIXED_TEMP
+ if (parser->hold_len < parser->pos + 1 + 1)
+ {
+ int new_len = parser->hold_len * 1.5;
+ if (new_len < 512) new_len = 512;
+ parser->holding = realloc (parser->holding, new_len);
+ parser->hold_len = new_len;
+ }
+#endif
+
+ parser->holding[parser->pos++]=byte;
+#if CTX_PARSER_FIXED_TEMP
+ if (parser->pos > (int) sizeof (parser->holding)-2)
+ { parser->pos = sizeof (parser->holding)-2; }
+#endif
+ parser->holding[parser->pos]=0;
+}
+
+static void ctx_parser_transform_percent (CtxParser *parser, CtxCode code, int arg_no, float *value)
+{
+ int big = parser->width;
+ int small = parser->height;
+ if (big < small)
+ {
+ small = parser->width;
+ big = parser->height;
+ }
+ switch (code)
+ {
+ case CTX_RADIAL_GRADIENT:
+ case CTX_ARC:
+ switch (arg_no)
+ {
+ case 0:
+ case 3:
+ *value *= (parser->width/100.0);
+ break;
+ case 1:
+ case 4:
+ *value *= (parser->height/100.0);
+ break;
+ case 2:
+ case 5:
+ *value *= small/100.0;
+ break;
+ }
+ break;
+ case CTX_FONT_SIZE:
+ case CTX_MITER_LIMIT:
+ case CTX_LINE_WIDTH:
+ case CTX_LINE_DASH_OFFSET:
+ {
+ *value *= (small/100.0);
+ }
+ break;
+ case CTX_ARC_TO:
+ case CTX_REL_ARC_TO:
+ if (arg_no > 3)
+ {
+ *value *= (small/100.0);
+ }
+ else
+ {
+ if (arg_no % 2 == 0)
+ { *value *= ( (parser->width) /100.0); }
+ else
+ { *value *= ( (parser->height) /100.0); }
+ }
+ break;
+ case CTX_ROUND_RECTANGLE:
+ if (arg_no == 4)
+ {
+ { *value *= ((parser->height)/100.0); }
+ return;
+ }
+ /* FALLTHROUGH */
+ default: // even means x coord
+ if (arg_no % 2 == 0)
+ { *value *= ((parser->width)/100.0); }
+ else
+ { *value *= ((parser->height)/100.0); }
+ break;
+ }
+}
+
+static void ctx_parser_transform_percent_height (CtxParser *parser, CtxCode code, int arg_no, float *value)
+{
+ *value *= (parser->height/100.0);
+}
+
+static void ctx_parser_transform_percent_width (CtxParser *parser, CtxCode code, int arg_no, float *value)
+{
+ *value *= (parser->height/100.0);
+}
+
+static void ctx_parser_transform_cell (CtxParser *parser, CtxCode code, int arg_no, float *value)
+{
+ float small = parser->cell_width;
+ if (small > parser->cell_height)
+ { small = parser->cell_height; }
+ switch (code)
+ {
+ case CTX_RADIAL_GRADIENT:
+ case CTX_ARC:
+ switch (arg_no)
+ {
+ case 0:
+ case 3:
+ *value *= parser->cell_width;
+ break;
+ case 1:
+ case 4:
+ *value *= parser->cell_height;
+ break;
+ case 2:
+ case 5:
+ *value *= small; // use height?
+ break;
+ }
+ break;
+ case CTX_MITER_LIMIT:
+ case CTX_FONT_SIZE:
+ case CTX_LINE_WIDTH:
+ case CTX_LINE_DASH_OFFSET:
+ {
+ *value *= parser->cell_height;
+ }
+ break;
+ case CTX_ARC_TO:
+ case CTX_REL_ARC_TO:
+ if (arg_no > 3)
+ {
+ *value *= small;
+ }
+ else
+ {
+ *value *= (arg_no%2==0) ?parser->cell_width:parser->cell_height;
+ }
+ break;
+ case CTX_RECTANGLE:
+ if (arg_no % 2 == 0)
+ { *value *= parser->cell_width; }
+ else
+ {
+ if (! (arg_no > 1) )
+ { (*value) -= 1.0f; }
+ *value *= parser->cell_height;
+ }
+ break;
+ default: // even means x coord odd means y coord
+ *value *= (arg_no%2==0) ?parser->cell_width:parser->cell_height;
+ break;
+ }
+}
+
+// %h %v %m %M
+
+static void ctx_parser_number_done (CtxParser *parser)
+{
+
+}
+
+static void ctx_parser_word_done (CtxParser *parser)
+{
+ parser->holding[parser->pos]=0;
+ //int old_args = parser->expected_args;
+ int command = ctx_parser_resolve_command (parser, parser->holding);
+ if ((command >= 0 && command < 32)
+ || (command > 150) || (command < 0)
+ ) // special case low enum values
+ { // and enum values too high to be
+ // commands - permitting passing words
+ // for strings in some cases
+ parser->numbers[parser->n_numbers] = command;
+
+ // trigger transition from number
+ parser->state = CTX_PARSER_NUMBER;
+ ctx_parser_feed_byte (parser, ',');
+ }
+ else if (command > 0)
+ {
+#if 0
+ if (old_args == CTX_ARG_COLLECT_NUMBERS ||
+ old_args == CTX_ARG_STRING_OR_NUMBER)
+ {
+ int tmp1 = parser->command;
+ int tmp2 = parser->expected_args;
+ int tmp3 = parser->n_numbers;
+ // int tmp4 = parser->n_args;
+ ctx_parser_dispatch_command (parser);
+ parser->command = (CtxCode)tmp1;
+ parser->expected_args = tmp2;
+ parser->n_numbers = tmp3;
+ // parser->n_args = tmp4;
+ }
+#endif
+
+ parser->command = (CtxCode) command;
+ parser->n_numbers = 0;
+ parser->n_args = 0;
+ if (parser->expected_args == 0)
+ {
+ ctx_parser_dispatch_command (parser);
+ }
+ }
+ else
+ {
+ /* interpret char by char */
+ uint8_t buf[16]=" ";
+ for (int i = 0; parser->pos && parser->holding[i] > ' '; i++)
+ {
+ buf[0] = parser->holding[i];
+ parser->command = (CtxCode) ctx_parser_resolve_command (parser, buf);
+ parser->n_numbers = 0;
+ parser->n_args = 0;
+ if (parser->command > 0)
+ {
+ if (parser->expected_args == 0)
+ {
+ ctx_parser_dispatch_command (parser);
+ }
+ }
+ else
+ {
+ ctx_log ("unhandled command '%c'\n", buf[0]);
+ }
+ }
+ }
+}
+
+static void ctx_parser_string_done (CtxParser *parser)
+{
+ if (parser->expected_args == CTX_ARG_STRING_OR_NUMBER)
+ {
+ /*
+ if (parser->state != CTX_PARSER_NUMBER &&
+ parser->state != CTX_PARSER_NEGATIVE_NUMBER &&
+ parser->state != CTX_PARSER_STRING_A85 &&
+ parser->state != CTX_PARSER_STRING_APOS &&
+ parser->state != CTX_PARSER_STRING_QUOT
+ )
+ */
+ {
+ int tmp1 = parser->command;
+ int tmp2 = parser->expected_args;
+ int tmp3 = parser->n_numbers;
+ int tmp4 = parser->n_args;
+ ctx_parser_dispatch_command (parser);
+ parser->command = (CtxCode)tmp1;
+ parser->expected_args = tmp2;
+ parser->n_numbers = tmp3;
+ parser->n_args = tmp4;
+ }
+ }
+ else
+ {
+ ctx_parser_dispatch_command (parser);
+ }
+}
+
+void ctx_parser_feed_byte (CtxParser *parser, int byte)
+{
+ switch (byte)
+ {
+ case '\n':
+ parser->col=0;
+ parser->line++;
+ break;
+ default:
+ parser->col++;
+ }
+ switch (parser->state)
+ {
+ case CTX_PARSER_NEUTRAL:
+ switch (byte)
+ {
+ case 0: case 1: case 2: case 3: case 4: case 5:
+ case 6: case 7: case 8: case 11: case 12: case 14:
+ case 15: case 16: case 17: case 18: case 19: case 20:
+ case 21: case 22: case 23: case 24: case 25: case 26:
+ case 27: case 28: case 29: case 30: case 31:
+ break;
+ case ' ': case '\t': case '\r': case '\n':
+ case ';': case ',':
+ case '(': case ')':
+ case '{': case '}':
+ case '=':
break;
case '#':
parser->state = CTX_PARSER_COMMENT;
@@ -16043,35 +18003,12 @@ void ctx_parser_feed_byte (CtxParser *parser, int byte)
{
switch (byte)
{
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 11:
- case 12:
- case 14:
- case 15:
- case 16:
- case 17:
- case 18:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23:
- case 24:
- case 25:
- case 26:
- case 27:
- case 28:
- case 29:
- case 30:
- case 31:
+ case 0: case 1: case 2: case 3: case 4: case 5:
+ case 6: case 7: case 8:
+ case 11: case 12: case 14: case 15: case 16:
+ case 17: case 18: case 19: case 20: case 21:
+ case 22: case 23: case 24: case 25: case 26:
+ case 27: case 28: case 29: case 30: case 31:
parser->state = CTX_PARSER_NEUTRAL;
break;
case ' ':
@@ -16104,16 +18041,8 @@ void ctx_parser_feed_byte (CtxParser *parser, int byte)
//if (parser->decimal) // TODO permit .13.32.43 to equivalent to .12 .32 .43
parser->decimal = 1;
break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
if (parser->decimal)
{
parser->decimal *= 10;
@@ -16177,11 +18106,21 @@ void ctx_parser_feed_byte (CtxParser *parser, int byte)
(parser->state != CTX_PARSER_NEGATIVE_NUMBER))
{
parser->n_numbers ++;
- //parser->t_args ++;
+ ctx_parser_number_done (parser);
+
if (parser->n_numbers == parser->expected_args ||
- parser->expected_args == 100)
+ parser->expected_args == CTX_ARG_COLLECT_NUMBERS ||
+ parser->expected_args == CTX_ARG_STRING_OR_NUMBER)
{
+ int tmp1 = parser->n_numbers;
+ //int tmp2 = parser->n_args;
+ int tmp3 = parser->command;
+ int tmp4 = parser->expected_args;
ctx_parser_dispatch_command (parser);
+ parser->n_numbers = tmp1;
+ //parser->n_args = tmp2;
+ parser->command = tmp3;
+ parser->expected_args = tmp4;
}
if (parser->n_numbers > CTX_PARSER_MAX_ARGS)
{ parser->n_numbers = CTX_PARSER_MAX_ARGS;
@@ -16233,8 +18172,11 @@ void ctx_parser_feed_byte (CtxParser *parser, int byte)
case CTX_PARSER_STRING_A85:
switch (byte)
{
- case '~': parser->state = CTX_PARSER_NEUTRAL;
+ case '~':
+ parser->state = CTX_PARSER_NEUTRAL;
+ // fprintf (stderr, "got %i\n", parser->pos);
parser->pos = ctx_a85dec ((char*)parser->holding, (char*)parser->holding, parser->pos);
+ // fprintf (stderr, "dec got %i\n", parser->pos);
ctx_parser_string_done (parser);
break;
default:
@@ -16247,7 +18189,8 @@ void ctx_parser_feed_byte (CtxParser *parser, int byte)
{
case '\\': parser->state = CTX_PARSER_STRING_APOS_ESCAPED; break;
case '\'': parser->state = CTX_PARSER_NEUTRAL;
- ctx_parser_string_done (parser); break;
+ ctx_parser_string_done (parser);
+ break;
default:
ctx_parser_holding_append (parser, byte); break;
}
@@ -16372,7 +18315,7 @@ ctx_load_font_ttf_file (const char *name, const char *path)
{
uint8_t *contents = NULL;
long length = 0;
- _ctx_file_get_contents (path, &contents, &length);
+ ctx_get_contents (path, &contents, &length);
if (!contents)
{
ctx_log ( "File load failed\n");
@@ -16735,7 +18678,7 @@ ctx_load_font_ctx_file (const char *name, const char *path)
{
uint8_t *contents = NULL;
long length = 0;
- _ctx_file_get_contents (path, &contents, &length);
+ ctx_get_contents (path, &contents, &length);
if (!contents)
{
ctx_log ( "File load failed\n");
@@ -16778,17 +18721,15 @@ ctx_glyph_width_ctx_fs (CtxFont *font, Ctx *ctx, uint32_t unichar)
sprintf (path, "%s/%010p", font->ctx_fs.path, unichar);
uint8_t *data = NULL;
long int len_bytes = 0;
- _ctx_file_get_contents (path, &data, &len_bytes);
+ 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);
- //fprintf (stderr, "\n");
for (int i = 0; i < glyph_ctx->drawlist.count; i++)
{
CtxEntry *e = &glyph_ctx->drawlist.entries[i];
- // fprintf (stderr, "%c:", e->code);
if (e->code == CTX_DEFINE_GLYPH)
ret = e->data.u32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE;
}
@@ -16802,11 +18743,10 @@ static int
ctx_glyph_ctx_fs (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke)
{
char path[1024];
- sprintf (path, "%s/%010p", font->ctx_fs.path, unichar);
+ sprintf (path, "file://%s/%010p", font->ctx_fs.path, unichar);
uint8_t *data = NULL;
long int len_bytes = 0;
- _ctx_file_get_contents (path, &data, &len_bytes);
-//fprintf (stderr, "%s %li\n", path, len_bytes);
+ ctx_get_contents (path, &data, &len_bytes);
if (data){
Ctx *glyph_ctx = ctx_new ();
@@ -16948,11 +18888,11 @@ _ctx_text (Ctx *ctx,
{
case CTX_TEXT_BASELINE_HANGING:
/* XXX : crude */
- baseline_offset = ctx->state.gstate.font_size * 0.55;
+ baseline_offset = ctx->state.gstate.font_size * 0.55;
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.7;
break;
case CTX_TEXT_BASELINE_BOTTOM:
baseline_offset = -ctx->state.gstate.font_size * 0.1;
@@ -17039,6 +18979,15 @@ ctx_text (Ctx *ctx,
#endif
}
+
+void
+ctx_fill_text (Ctx *ctx, const char *string,
+ float x, float y)
+{
+ ctx_move_to (ctx, x, y);
+ ctx_text (ctx, string);
+}
+
void
ctx_text_stroke (Ctx *ctx,
const char *string)
@@ -17046,13 +18995,21 @@ ctx_text_stroke (Ctx *ctx,
if (!string)
return;
#if CTX_BACKEND_TEXT
- ctx_process_cmd_str (ctx, CTX_TEXT_STROKE, string, 0, 0);
+ ctx_process_cmd_str (ctx, CTX_STROKE_TEXT, string, 0, 0);
_ctx_text (ctx, string, 1, 0);
#else
_ctx_text (ctx, string, 1, 1);
#endif
}
+void
+ctx_stroke_text (Ctx *ctx, const char *string,
+ float x, float y)
+{
+ ctx_move_to (ctx, x, y);
+ ctx_text_stroke (ctx, string);
+}
+
static int _ctx_resolve_font (const char *name)
{
for (int i = 0; i < ctx_font_count; i ++)
@@ -17158,25 +19115,6 @@ static void ctx_font_setup ()
}
-/* mrg - MicroRaptor Gui
- * Copyright (c) 2014 Øyvind Kolås <pippin hodefoting com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-//#include "ctx-string.h"
-
#ifndef _DEFAULT_SOURCE
#define _DEFAULT_SOURCE
#endif
@@ -17304,2846 +19242,3568 @@ void ctx_string_append_data (CtxString *string, const char *str, int len)
{ _ctx_string_append_byte (string, str[i]); }
}
-void ctx_string_append_string (CtxString *string, CtxString *string2)
+void ctx_string_append_string (CtxString *string, CtxString *string2)
+{
+ const char *str = ctx_string_get (string2);
+ while (str && *str)
+ {
+ _ctx_string_append_byte (string, *str);
+ str++;
+ }
+}
+
+const char *ctx_string_get (CtxString *string)
+{
+ return string->str;
+}
+
+int ctx_string_get_length (CtxString *string)
+{
+ return string->length;
+}
+
+void
+ctx_string_free (CtxString *string, int freealloc)
+{
+ if (freealloc)
+ {
+ ctx_string_destroy (string);
+ }
+#if 0
+ if (string->is_line)
+ {
+ VtLine *line = (VtLine*)string;
+ if (line->style)
+ { free (line->style); }
+ if (line->ctx)
+ { ctx_free (line->ctx); }
+ if (line->ctx_copy)
+ { ctx_free (line->ctx_copy); }
+ }
+#endif
+ free (string);
+}
+
+void
+ctx_string_set (CtxString *string, const char *new_string)
+{
+ ctx_string_clear (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)
+{
+ int new_len = ctx_utf8_len (*new_glyph);
+#if 1
+ int old_len = string->utf8_length;
+#else
+ int old_len = ctx_utf8_strlen (string->str);// string->utf8_length;
+#endif
+ char tmpg[3]=" ";
+ if (pos == old_len)
+ {
+ _ctx_string_append_str (string, new_glyph);
+ return;
+ }
+ if (new_len <= 1 && new_glyph[0] < 32)
+ {
+ new_len = 1;
+ tmpg[0]=new_glyph[0]+64;
+ new_glyph = tmpg;
+ }
+ {
+ for (int i = old_len; i <= pos + 2; i++)
+ {
+ _ctx_string_append_byte (string, ' ');
+ old_len++;
+ }
+ }
+ if (string->length + new_len >= string->allocated_length - 2)
+ {
+ char *tmp;
+ char *defer;
+ string->allocated_length = string->length + new_len + 2;
+ tmp = (char*) ctx_calloc (string->allocated_length + 1 + 8, 1);
+ strcpy (tmp, string->str);
+ defer = string->str;
+ string->str = tmp;
+ free (defer);
+ }
+ char *p = (char *) ctx_utf8_skip (string->str, pos);
+ int prev_len = ctx_utf8_len (*p);
+ char *rest;
+ if (*p == 0 || * (p+prev_len) == 0)
+ {
+ rest = ctx_strdup ("");
+ }
+ else
+ {
+ if (p + prev_len >= string->length + string->str)
+ { rest = ctx_strdup (""); }
+ else
+ { rest = ctx_strdup (p + prev_len); }
+ }
+ memcpy (p, new_glyph, new_len);
+ memcpy (p + new_len, rest, strlen (rest) + 1);
+ //string->length += new_len;
+ //string->length -= prev_len;
+ free (rest);
+ string->length = strlen (string->str);
+ string->utf8_length = ctx_utf8_strlen (string->str);
+}
+
+void ctx_string_replace_unichar (CtxString *string, int pos, uint32_t unichar)
+{
+ uint8_t utf8[8];
+ ctx_unichar_to_utf8 (unichar, utf8);
+ ctx_string_replace_utf8 (string, pos, (char *) utf8);
+}
+
+uint32_t ctx_string_get_unichar (CtxString *string, int pos)
+{
+ char *p = (char *) ctx_utf8_skip (string->str, pos);
+ if (!p)
+ { return 0; }
+ return ctx_utf8_to_unichar (p);
+}
+
+void ctx_string_insert_utf8 (CtxString *string, int pos, const char *new_glyph)
+{
+ int new_len = ctx_utf8_len (*new_glyph);
+ int old_len = string->utf8_length;
+ char tmpg[3]=" ";
+ if (old_len == pos && 0)
+ {
+ ctx_string_append_str (string, new_glyph);
+ return;
+ }
+ if (new_len <= 1 && new_glyph[0] < 32)
+ {
+ tmpg[0]=new_glyph[0]+64;
+ new_glyph = tmpg;
+ }
+ {
+ for (int i = old_len; i <= pos; i++)
+ {
+ _ctx_string_append_byte (string, ' ');
+ old_len++;
+ }
+ }
+ if (string->length + new_len + 1 > string->allocated_length)
+ {
+ char *tmp;
+ char *defer;
+ string->allocated_length = string->length + new_len + 1;
+ tmp = (char*) ctx_calloc (string->allocated_length + 1, 1);
+ strcpy (tmp, string->str);
+ defer = string->str;
+ string->str = tmp;
+ free (defer);
+ }
+ char *p = (char *) ctx_utf8_skip (string->str, pos);
+ int prev_len = ctx_utf8_len (*p);
+ char *rest;
+ if ( (*p == 0 || * (p+prev_len) == 0) && pos != 0)
+ {
+ rest = ctx_strdup ("");
+ }
+ else
+ {
+ rest = ctx_strdup (p);
+ }
+ memcpy (p, new_glyph, new_len);
+ memcpy (p + new_len, rest, strlen (rest) + 1);
+ string->length += new_len;
+ free (rest);
+ string->utf8_length = ctx_utf8_strlen (string->str);
+}
+
+void ctx_string_remove (CtxString *string, int pos)
{
- const char *str = ctx_string_get (string2);
- while (str && *str)
+ int old_len = string->utf8_length;
+ {
+ for (int i = old_len; i <= pos; i++)
+ {
+ _ctx_string_append_byte (string, ' ');
+ old_len++;
+ }
+ }
+ char *p = (char *) ctx_utf8_skip (string->str, pos);
+ int prev_len = ctx_utf8_len (*p);
+ char *rest;
+ if (*p == 0 || * (p+prev_len) == 0)
{
- _ctx_string_append_byte (string, *str);
- str++;
+ rest = ctx_strdup ("");
+ prev_len = 0;
}
+ else
+ {
+ rest = ctx_strdup (p + prev_len);
+ }
+ strcpy (p, rest);
+ string->str[string->length - prev_len] = 0;
+ free (rest);
+ string->length = strlen (string->str);
+ string->utf8_length = ctx_utf8_strlen (string->str);
}
-const char *ctx_string_get (CtxString *string)
+char *ctx_strdup_printf (const char *format, ...)
{
- return string->str;
+ va_list ap;
+ size_t needed;
+ char *buffer;
+ va_start (ap, format);
+ needed = vsnprintf (NULL, 0, format, ap) + 1;
+ buffer = (char*)malloc (needed);
+ va_end (ap);
+ va_start (ap, format);
+ vsnprintf (buffer, needed, format, ap);
+ va_end (ap);
+ return buffer;
}
-int ctx_string_get_length (CtxString *string)
+void ctx_string_append_printf (CtxString *string, const char *format, ...)
{
- return string->length;
+ va_list ap;
+ size_t needed;
+ char *buffer;
+ va_start (ap, format);
+ needed = vsnprintf (NULL, 0, format, ap) + 1;
+ buffer = (char*)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);
}
-void
-ctx_string_free (CtxString *string, int freealloc)
+#if CTX_CAIRO
+
+typedef struct _CtxCairo CtxCairo;
+struct
+ _CtxCairo
{
- if (freealloc)
+ CtxImplementation vfuncs;
+ Ctx *ctx;
+ cairo_t *cr;
+ cairo_pattern_t *pat;
+ cairo_surface_t *image;
+ int preserve;
+};
+
+static void
+ctx_cairo_process (CtxCairo *ctx_cairo, CtxCommand *c)
+{
+ CtxEntry *entry = (CtxEntry *) &c->entry;
+ cairo_t *cr = ctx_cairo->cr;
+ switch (entry->code)
{
- ctx_string_destroy (string);
- }
+ case CTX_LINE_TO:
+ cairo_line_to (cr, c->line_to.x, c->line_to.y);
+ break;
+ case CTX_REL_LINE_TO:
+ cairo_rel_line_to (cr, c->rel_line_to.x, c->rel_line_to.y);
+ break;
+ case CTX_MOVE_TO:
+ cairo_move_to (cr, c->move_to.x, c->move_to.y);
+ break;
+ case CTX_REL_MOVE_TO:
+ cairo_rel_move_to (cr, ctx_arg_float (0), ctx_arg_float (1) );
+ break;
+ case CTX_CURVE_TO:
+ cairo_curve_to (cr, ctx_arg_float (0), ctx_arg_float (1),
+ ctx_arg_float (2), ctx_arg_float (3),
+ ctx_arg_float (4), ctx_arg_float (5) );
+ break;
+ case CTX_REL_CURVE_TO:
+ cairo_rel_curve_to (cr,ctx_arg_float (0), ctx_arg_float (1),
+ ctx_arg_float (2), ctx_arg_float (3),
+ ctx_arg_float (4), ctx_arg_float (5) );
+ break;
+ case CTX_PRESERVE:
+ ctx_cairo->preserve = 1;
+ break;
+ case CTX_QUAD_TO:
+ {
+ double x0, y0;
+ cairo_get_current_point (cr, &x0, &y0);
+ float cx = ctx_arg_float (0);
+ float cy = ctx_arg_float (1);
+ float x = ctx_arg_float (2);
+ float y = ctx_arg_float (3);
+ cairo_curve_to (cr,
+ (cx * 2 + x0) / 3.0f, (cy * 2 + y0) / 3.0f,
+ (cx * 2 + x) / 3.0f, (cy * 2 + y) / 3.0f,
+ x, y);
+ }
+ break;
+ case CTX_REL_QUAD_TO:
+ {
+ double x0, y0;
+ cairo_get_current_point (cr, &x0, &y0);
+ float cx = ctx_arg_float (0) + x0;
+ float cy = ctx_arg_float (1) + y0;
+ float x = ctx_arg_float (2) + x0;
+ float y = ctx_arg_float (3) + y0;
+ cairo_curve_to (cr,
+ (cx * 2 + x0) / 3.0f, (cy * 2 + y0) / 3.0f,
+ (cx * 2 + x) / 3.0f, (cy * 2 + y) / 3.0f,
+ x, y);
+ }
+ break;
+ /* rotate/scale/translate does not occur in fully minified data stream */
+ case CTX_ROTATE:
+ cairo_rotate (cr, ctx_arg_float (0) );
+ break;
+ case CTX_SCALE:
+ cairo_scale (cr, ctx_arg_float (0), ctx_arg_float (1) );
+ break;
+ case CTX_TRANSLATE:
+ cairo_translate (cr, ctx_arg_float (0), ctx_arg_float (1) );
+ break;
+ case CTX_LINE_WIDTH:
+ cairo_set_line_width (cr, ctx_arg_float (0) );
+ break;
+ case CTX_ARC:
+#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));
+#endif
+ if (ctx_arg_float (5) == 1)
+ cairo_arc (cr, ctx_arg_float (0), ctx_arg_float (1),
+ ctx_arg_float (2), ctx_arg_float (3),
+ ctx_arg_float (4) );
+ else
+ cairo_arc_negative (cr, ctx_arg_float (0), ctx_arg_float (1),
+ ctx_arg_float (2), ctx_arg_float (3),
+ ctx_arg_float (4) );
+ break;
+ case CTX_SET_RGBA_U8:
+ cairo_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) ) );
+ break;
+#if 0
+ case CTX_SET_RGBA_STROKE: // XXX : we need to maintain
+ // state for the two kinds
+ cairo_set_source_rgba (cr, ctx_arg_u8 (0) /255.0,
+ ctx_arg_u8 (1) /255.0,
+ ctx_arg_u8 (2) /255.0,
+ ctx_arg_u8 (3) /255.0);
+ break;
+#endif
+ case CTX_RECTANGLE:
+ case CTX_ROUND_RECTANGLE: // XXX - arcs
+ cairo_rectangle (cr, c->rectangle.x, c->rectangle.y,
+ c->rectangle.width, c->rectangle.height);
+ break;
+ case CTX_SET_PIXEL:
+ cairo_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) ) );
+ cairo_rectangle (cr, ctx_arg_u16 (2), ctx_arg_u16 (3), 1, 1);
+ cairo_fill (cr);
+ break;
+ case CTX_FILL:
+ if (ctx_cairo->preserve)
+ {
+ cairo_fill_preserve (cr);
+ ctx_cairo->preserve = 0;
+ }
+ else
+ {
+ cairo_fill (cr);
+ }
+ break;
+ case CTX_STROKE:
+ if (ctx_cairo->preserve)
+ {
+ cairo_stroke_preserve (cr);
+ ctx_cairo->preserve = 0;
+ }
+ else
+ {
+ cairo_stroke (cr);
+ }
+ break;
+ case CTX_IDENTITY:
+ cairo_identity_matrix (cr);
+ break;
+ case CTX_CLIP:
+ if (ctx_cairo->preserve)
+ {
+ cairo_clip_preserve (cr);
+ ctx_cairo->preserve = 0;
+ }
+ else
+ {
+ cairo_clip (cr);
+ }
+ break;
+ break;
+ case CTX_BEGIN_PATH:
+ cairo_new_path (cr);
+ break;
+ case CTX_CLOSE_PATH:
+ cairo_close_path (cr);
+ break;
+ case CTX_SAVE:
+ cairo_save (cr);
+ break;
+ case CTX_RESTORE:
+ cairo_restore (cr);
+ break;
+ case CTX_FONT_SIZE:
+ cairo_set_font_size (cr, ctx_arg_float (0) );
+ break;
+ case CTX_MITER_LIMIT:
+ cairo_set_miter_limit (cr, ctx_arg_float (0) );
+ break;
+ case CTX_LINE_CAP:
+ {
+ int cairo_val = CAIRO_LINE_CAP_SQUARE;
+ switch (ctx_arg_u8 (0) )
+ {
+ case CTX_CAP_ROUND:
+ cairo_val = CAIRO_LINE_CAP_ROUND;
+ break;
+ case CTX_CAP_SQUARE:
+ cairo_val = CAIRO_LINE_CAP_SQUARE;
+ break;
+ case CTX_CAP_NONE:
+ cairo_val = CAIRO_LINE_CAP_BUTT;
+ break;
+ }
+ cairo_set_line_cap (cr, cairo_val);
+ }
+ break;
+ case CTX_BLEND_MODE:
+ {
+ // does not map to cairo
+ }
+ break;
+ case CTX_COMPOSITING_MODE:
+ {
+ int cairo_val = CAIRO_OPERATOR_OVER;
+ switch (ctx_arg_u8 (0) )
+ {
+ case CTX_COMPOSITE_SOURCE_OVER:
+ cairo_val = CAIRO_OPERATOR_OVER;
+ break;
+ case CTX_COMPOSITE_COPY:
+ cairo_val = CAIRO_OPERATOR_SOURCE;
+ break;
+ }
+ cairo_set_operator (cr, cairo_val);
+ }
+ case CTX_LINE_JOIN:
+ {
+ int cairo_val = CAIRO_LINE_JOIN_ROUND;
+ switch (ctx_arg_u8 (0) )
+ {
+ case CTX_JOIN_ROUND:
+ cairo_val = CAIRO_LINE_JOIN_ROUND;
+ break;
+ case CTX_JOIN_BEVEL:
+ cairo_val = CAIRO_LINE_JOIN_BEVEL;
+ break;
+ case CTX_JOIN_MITER:
+ cairo_val = CAIRO_LINE_JOIN_MITER;
+ break;
+ }
+ cairo_set_line_join (cr, cairo_val);
+ }
+ break;
+ case CTX_LINEAR_GRADIENT:
+ {
+ if (ctx_cairo->pat)
+ {
+ cairo_pattern_destroy (ctx_cairo->pat);
+ ctx_cairo->pat = NULL;
+ }
+ ctx_cairo->pat = cairo_pattern_create_linear (ctx_arg_float (0), ctx_arg_float (1),
+ ctx_arg_float (2), ctx_arg_float (3) );
+ cairo_pattern_add_color_stop_rgba (ctx_cairo->pat, 0, 0, 0, 0, 1);
+ cairo_pattern_add_color_stop_rgba (ctx_cairo->pat, 1, 1, 1, 1, 1);
+ cairo_set_source (cr, ctx_cairo->pat);
+ }
+ break;
+ case CTX_RADIAL_GRADIENT:
+ {
+ if (ctx_cairo->pat)
+ {
+ cairo_pattern_destroy (ctx_cairo->pat);
+ ctx_cairo->pat = NULL;
+ }
+ ctx_cairo->pat = cairo_pattern_create_radial (ctx_arg_float (0), ctx_arg_float (1),
+ ctx_arg_float (2), ctx_arg_float (3),
+ ctx_arg_float (4), ctx_arg_float (5) );
+ cairo_set_source (cr, ctx_cairo->pat);
+ }
+ break;
+ case CTX_GRADIENT_STOP:
+ cairo_pattern_add_color_stop_rgba (ctx_cairo->pat,
+ ctx_arg_float (0),
+ ctx_u8_to_float (ctx_arg_u8 (4) ),
+ ctx_u8_to_float (ctx_arg_u8 (5) ),
+ ctx_u8_to_float (ctx_arg_u8 (6) ),
+ ctx_u8_to_float (ctx_arg_u8 (7) ) );
+ break;
+ // XXX implement TEXTURE
#if 0
- if (string->is_line)
- {
- VtLine *line = (VtLine*)string;
- if (line->style)
- { free (line->style); }
- if (line->ctx)
- { ctx_free (line->ctx); }
- if (line->ctx_copy)
- { ctx_free (line->ctx_copy); }
- }
-#endif
- free (string);
-}
-
-void
-ctx_string_set (CtxString *string, const char *new_string)
-{
- ctx_string_clear (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)
-{
- int new_len = ctx_utf8_len (*new_glyph);
-#if 1
- int old_len = string->utf8_length;
-#else
- int old_len = ctx_utf8_strlen (string->str);// string->utf8_length;
+ case CTX_LOAD_IMAGE:
+ {
+ if (image)
+ {
+ cairo_surface_destroy (image);
+ image = NULL;
+ }
+ if (pat)
+ {
+ cairo_pattern_destroy (pat);
+ pat = NULL;
+ }
+ image = cairo_image_surface_create_from_png (ctx_arg_string() );
+ cairo_set_source_surface (cr, image, ctx_arg_float (0), ctx_arg_float (1) );
+ }
+ break;
#endif
- char tmpg[3]=" ";
- if (pos == old_len)
- {
- _ctx_string_append_str (string, new_glyph);
- return;
- }
- if (new_len <= 1 && new_glyph[0] < 32)
- {
- new_len = 1;
- tmpg[0]=new_glyph[0]+64;
- new_glyph = tmpg;
- }
- {
- for (int i = old_len; i <= pos + 2; i++)
- {
- _ctx_string_append_byte (string, ' ');
- old_len++;
- }
- }
- if (string->length + new_len >= string->allocated_length - 2)
- {
- char *tmp;
- char *defer;
- string->allocated_length = string->length + new_len + 2;
- tmp = (char*) ctx_calloc (string->allocated_length + 1 + 8, 1);
- strcpy (tmp, string->str);
- defer = string->str;
- string->str = tmp;
- free (defer);
- }
- char *p = (char *) ctx_utf8_skip (string->str, pos);
- int prev_len = ctx_utf8_len (*p);
- char *rest;
- if (*p == 0 || * (p+prev_len) == 0)
- {
- rest = ctx_strdup ("");
- }
- else
- {
- if (p + prev_len >= string->length + string->str)
- { rest = ctx_strdup (""); }
- else
- { rest = ctx_strdup (p + prev_len); }
- }
- memcpy (p, new_glyph, new_len);
- memcpy (p + new_len, rest, strlen (rest) + 1);
- //string->length += new_len;
- //string->length -= prev_len;
- free (rest);
- string->length = strlen (string->str);
- string->utf8_length = ctx_utf8_strlen (string->str);
-}
-
-void ctx_string_replace_unichar (CtxString *string, int pos, uint32_t unichar)
-{
- uint8_t utf8[8];
- ctx_unichar_to_utf8 (unichar, utf8);
- ctx_string_replace_utf8 (string, pos, (char *) utf8);
-}
-
-uint32_t ctx_string_get_unichar (CtxString *string, int pos)
-{
- char *p = (char *) ctx_utf8_skip (string->str, pos);
- if (!p)
- { return 0; }
- return ctx_utf8_to_unichar (p);
-}
-
-void ctx_string_insert_utf8 (CtxString *string, int pos, const char *new_glyph)
-{
- int new_len = ctx_utf8_len (*new_glyph);
- int old_len = string->utf8_length;
- char tmpg[3]=" ";
- if (old_len == pos && 0)
- {
- ctx_string_append_str (string, new_glyph);
- return;
- }
- if (new_len <= 1 && new_glyph[0] < 32)
- {
- tmpg[0]=new_glyph[0]+64;
- new_glyph = tmpg;
- }
- {
- for (int i = old_len; i <= pos; i++)
- {
- _ctx_string_append_byte (string, ' ');
- old_len++;
- }
- }
- if (string->length + new_len + 1 > string->allocated_length)
- {
- char *tmp;
- char *defer;
- string->allocated_length = string->length + new_len + 1;
- tmp = (char*) ctx_calloc (string->allocated_length + 1, 1);
- strcpy (tmp, string->str);
- defer = string->str;
- string->str = tmp;
- free (defer);
- }
- char *p = (char *) ctx_utf8_skip (string->str, pos);
- int prev_len = ctx_utf8_len (*p);
- char *rest;
- if ( (*p == 0 || * (p+prev_len) == 0) && pos != 0)
- {
- rest = ctx_strdup ("");
- }
- else
- {
- rest = ctx_strdup (p);
+ case CTX_TEXT:
+ /* XXX: implement some linebreaking/wrap, positioning
+ * behavior here
+ */
+ cairo_show_text (cr, ctx_arg_string () );
+ break;
+ case CTX_CONT:
+ case CTX_EDGE:
+ case CTX_DATA:
+ case CTX_DATA_REV:
+ case CTX_FLUSH:
+ break;
}
- memcpy (p, new_glyph, new_len);
- memcpy (p + new_len, rest, strlen (rest) + 1);
- string->length += new_len;
- free (rest);
- string->utf8_length = ctx_utf8_strlen (string->str);
+ ctx_process (ctx_cairo->ctx, entry);
}
-void ctx_string_remove (CtxString *string, int pos)
+void ctx_cairo_free (CtxCairo *ctx_cairo)
{
- int old_len = string->utf8_length;
- {
- for (int i = old_len; i <= pos; i++)
- {
- _ctx_string_append_byte (string, ' ');
- old_len++;
- }
- }
- char *p = (char *) ctx_utf8_skip (string->str, pos);
- int prev_len = ctx_utf8_len (*p);
- char *rest;
- if (*p == 0 || * (p+prev_len) == 0)
- {
- rest = ctx_strdup ("");
- prev_len = 0;
- }
- else
- {
- rest = ctx_strdup (p + prev_len);
- }
- strcpy (p, rest);
- string->str[string->length - prev_len] = 0;
- free (rest);
- string->length = strlen (string->str);
- string->utf8_length = ctx_utf8_strlen (string->str);
+ if (ctx_cairo->pat)
+ { cairo_pattern_destroy (ctx_cairo->pat); }
+ if (ctx_cairo->image)
+ { cairo_surface_destroy (ctx_cairo->image); }
+ free (ctx_cairo);
}
-char *ctx_strdup_printf (const char *format, ...)
+void
+ctx_render_cairo (Ctx *ctx, cairo_t *cr)
{
- va_list ap;
- size_t needed;
- char *buffer;
- va_start (ap, format);
- needed = vsnprintf (NULL, 0, format, ap) + 1;
- buffer = malloc (needed);
- va_end (ap);
- va_start (ap, format);
- vsnprintf (buffer, needed, format, ap);
- va_end (ap);
- return buffer;
+ CtxIterator iterator;
+ CtxCommand *command;
+ CtxCairo ctx_cairo = {{(void*)ctx_cairo_process, NULL, NULL}, ctx, cr, NULL, NULL};
+ ctx_iterator_init (&iterator, &ctx->drawlist, 0,
+ CTX_ITERATOR_EXPAND_BITPACK);
+ while ( (command = ctx_iterator_next (&iterator) ) )
+ { ctx_cairo_process (&ctx_cairo, command); }
}
-void ctx_string_append_printf (CtxString *string, const char *format, ...)
+Ctx *
+ctx_new_for_cairo (cairo_t *cr)
{
- va_list ap;
- size_t needed;
- char *buffer;
- va_start (ap, format);
- needed = vsnprintf (NULL, 0, format, ap) + 1;
- buffer = 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 *ctx = ctx_new ();
+ CtxCairo *ctx_cairo = calloc(sizeof(CtxCairo),1);
+ ctx_cairo->vfuncs.free = (void*)ctx_cairo_free;
+ ctx_cairo->vfuncs.process = (void*)ctx_cairo_process;
+ ctx_cairo->ctx = ctx;
+ ctx_cairo->cr = cr;
+
+ ctx_set_renderer (ctx, (void*)ctx_cairo);
+ return ctx;
}
-#if CTX_CAIRO
+#endif
-typedef struct _CtxCairo CtxCairo;
-struct
- _CtxCairo
+#if CTX_EVENTS
+
+static int ctx_find_largest_matching_substring
+ (const char *X, const char *Y, int m, int n, int *offsetY, int *offsetX)
+{
+ int longest_common_suffix[2][n+1];
+ int best_length = 0;
+ for (int i=0; i<=m; i++)
+ {
+ for (int j=0; j<=n; j++)
+ {
+ if (i == 0 || j == 0 || !(X[i-1] == Y[j-1]))
+ {
+ longest_common_suffix[i%2][j] = 0;
+ }
+ else
+ {
+ longest_common_suffix[i%2][j] = longest_common_suffix[(i-1)%2][j-1] + 1;
+ if (best_length < longest_common_suffix[i%2][j])
+ {
+ best_length = longest_common_suffix[i%2][j];
+ if (offsetY) *offsetY = j - best_length;
+ if (offsetX) *offsetX = i - best_length;
+ }
+ }
+ }
+ }
+ return best_length;
+}
+
+typedef struct CtxSpan {
+ int from_prev;
+ int start;
+ int length;
+} CtxSpan;
+
+#define CHUNK_SIZE 32
+#define MIN_MATCH 7 // minimum match length to be encoded
+#define WINDOW_PADDING 16 // look-aside amount
+
+#if 0
+static void _dassert(int line, int condition, const char *str, int foo, int bar, int baz)
{
- CtxImplementation vfuncs;
- Ctx *ctx;
- cairo_t *cr;
- cairo_pattern_t *pat;
- cairo_surface_t *image;
- int preserve;
-};
+ if (!condition)
+ {
+ FILE *f = fopen ("/tmp/cdebug", "a");
+ fprintf (f, "%i: %s %i %i %i\n", line, str, foo, bar, baz);
+ fclose (f);
+ }
+}
+#define dassert(cond, foo, bar, baz) _dassert(__LINE__, cond, #cond, foo, bar ,baz)
+#endif
+#define dassert(cond, foo, bar, baz)
-static void
-ctx_cairo_process (CtxCairo *ctx_cairo, CtxCommand *c)
+/* XXX repeated substring matching is slow, we'll be
+ * better off with a hash-table with linked lists of
+ * matching 3-4 characters in previous.. or even
+ * a naive approach that expects rough alignment..
+ */
+static char *encode_in_terms_of_previous (
+ const char *src, int src_len,
+ const char *prev, int prev_len,
+ int *out_len,
+ int max_ticks)
{
- CtxEntry *entry = (CtxEntry *) &c->entry;
- cairo_t *cr = ctx_cairo->cr;
- switch (entry->code)
- {
- case CTX_LINE_TO:
- cairo_line_to (cr, c->line_to.x, c->line_to.y);
- break;
- case CTX_REL_LINE_TO:
- cairo_rel_line_to (cr, c->rel_line_to.x, c->rel_line_to.y);
- break;
- case CTX_MOVE_TO:
- cairo_move_to (cr, c->move_to.x, c->move_to.y);
- break;
- case CTX_REL_MOVE_TO:
- cairo_rel_move_to (cr, ctx_arg_float (0), ctx_arg_float (1) );
- break;
- case CTX_CURVE_TO:
- cairo_curve_to (cr, ctx_arg_float (0), ctx_arg_float (1),
- ctx_arg_float (2), ctx_arg_float (3),
- ctx_arg_float (4), ctx_arg_float (5) );
- break;
- case CTX_REL_CURVE_TO:
- cairo_rel_curve_to (cr,ctx_arg_float (0), ctx_arg_float (1),
- ctx_arg_float (2), ctx_arg_float (3),
- ctx_arg_float (4), ctx_arg_float (5) );
- break;
- case CTX_PRESERVE:
- ctx_cairo->preserve = 1;
- break;
- case CTX_QUAD_TO:
- {
- double x0, y0;
- cairo_get_current_point (cr, &x0, &y0);
- float cx = ctx_arg_float (0);
- float cy = ctx_arg_float (1);
- float x = ctx_arg_float (2);
- float y = ctx_arg_float (3);
- cairo_curve_to (cr,
- (cx * 2 + x0) / 3.0f, (cy * 2 + y0) / 3.0f,
- (cx * 2 + x) / 3.0f, (cy * 2 + y) / 3.0f,
- x, y);
- }
- break;
- case CTX_REL_QUAD_TO:
- {
- double x0, y0;
- cairo_get_current_point (cr, &x0, &y0);
- float cx = ctx_arg_float (0) + x0;
- float cy = ctx_arg_float (1) + y0;
- float x = ctx_arg_float (2) + x0;
- float y = ctx_arg_float (3) + y0;
- cairo_curve_to (cr,
- (cx * 2 + x0) / 3.0f, (cy * 2 + y0) / 3.0f,
- (cx * 2 + x) / 3.0f, (cy * 2 + y) / 3.0f,
- x, y);
- }
- break;
- /* rotate/scale/translate does not occur in fully minified data stream */
- case CTX_ROTATE:
- cairo_rotate (cr, ctx_arg_float (0) );
- break;
- case CTX_SCALE:
- cairo_scale (cr, ctx_arg_float (0), ctx_arg_float (1) );
- break;
- case CTX_TRANSLATE:
- cairo_translate (cr, ctx_arg_float (0), ctx_arg_float (1) );
- break;
- case CTX_LINE_WIDTH:
- cairo_set_line_width (cr, ctx_arg_float (0) );
- break;
- case CTX_ARC:
+ CtxString *string = ctx_string_new ("");
+ CtxList *encoded_list = NULL;
+
+ /* TODO : make expected position offset in prev slide based on
+ * matches and not be constant */
+
+ long ticks_start = ctx_ticks ();
+ int start = 0;
+ int length = CHUNK_SIZE;
+ for (start = 0; start < src_len; start += length)
+ {
+ CtxSpan *span = calloc (sizeof (CtxSpan), 1);
+ span->start = start;
+ if (start + length > src_len)
+ span->length = src_len - start;
+ else
+ span->length = length;
+ span->from_prev = 0;
+ ctx_list_append (&encoded_list, span);
+ }
+
+ for (CtxList *l = encoded_list; l; l = l->next)
+ {
+ CtxSpan *span = l->data;
+ if (!span->from_prev)
+ {
+ if (span->length >= MIN_MATCH)
+ {
+ int prev_pos = 0;
+ int curr_pos = 0;
+ assert(1);
#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));
+ int prev_start = 0;
+ int prev_window_length = prev_len;
+#else
+ int window_padding = WINDOW_PADDING;
+ int prev_start = span->start - window_padding;
+ if (prev_start < 0)
+ prev_start = 0;
+
+ dassert(span->start>=0 , 0,0,0);
+
+ int prev_window_length = prev_len - prev_start;
+ if (prev_window_length > span->length + window_padding * 2 + span->start)
+ prev_window_length = span->length + window_padding * 2 + span->start;
#endif
- if (ctx_arg_float (5) == 1)
- cairo_arc (cr, ctx_arg_float (0), ctx_arg_float (1),
- ctx_arg_float (2), ctx_arg_float (3),
- ctx_arg_float (4) );
- else
- cairo_arc_negative (cr, ctx_arg_float (0), ctx_arg_float (1),
- ctx_arg_float (2), ctx_arg_float (3),
- ctx_arg_float (4) );
- break;
- case CTX_SET_RGBA_U8:
- cairo_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) ) );
- break;
-#if 0
- case CTX_SET_RGBA_STROKE: // XXX : we need to maintain
- // state for the two kinds
- cairo_set_source_rgba (cr, ctx_arg_u8 (0) /255.0,
- ctx_arg_u8 (1) /255.0,
- ctx_arg_u8 (2) /255.0,
- ctx_arg_u8 (3) /255.0);
- break;
+ int match_len = 0;
+ if (prev_window_length > 0)
+ match_len = ctx_find_largest_matching_substring(prev + prev_start, src + span->start,
prev_window_length, span->length, &curr_pos, &prev_pos);
+#if 1
+ prev_pos += prev_start;
#endif
- case CTX_RECTANGLE:
- case CTX_ROUND_RECTANGLE: // XXX - arcs
- cairo_rectangle (cr, c->rectangle.x, c->rectangle.y,
- c->rectangle.width, c->rectangle.height);
- break;
- case CTX_SET_PIXEL:
- cairo_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) ) );
- cairo_rectangle (cr, ctx_arg_u16 (2), ctx_arg_u16 (3), 1, 1);
- cairo_fill (cr);
- break;
- case CTX_FILL:
- if (ctx_cairo->preserve)
- {
- cairo_fill_preserve (cr);
- ctx_cairo->preserve = 0;
- }
- else
- {
- cairo_fill (cr);
- }
- break;
- case CTX_STROKE:
- if (ctx_cairo->preserve)
- {
- cairo_stroke_preserve (cr);
- ctx_cairo->preserve = 0;
- }
- else
- {
- cairo_stroke (cr);
- }
- break;
- case CTX_IDENTITY:
- cairo_identity_matrix (cr);
- break;
- case CTX_CLIP:
- if (ctx_cairo->preserve)
- {
- cairo_clip_preserve (cr);
- ctx_cairo->preserve = 0;
- }
- else
- {
- cairo_clip (cr);
- }
- break;
- break;
- case CTX_BEGIN_PATH:
- cairo_new_path (cr);
- break;
- case CTX_CLOSE_PATH:
- cairo_close_path (cr);
- break;
- case CTX_SAVE:
- cairo_save (cr);
- break;
- case CTX_RESTORE:
- cairo_restore (cr);
- break;
- case CTX_FONT_SIZE:
- cairo_set_font_size (cr, ctx_arg_float (0) );
- break;
- case CTX_MITER_LIMIT:
- cairo_set_miter_limit (cr, ctx_arg_float (0) );
- break;
- case CTX_LINE_CAP:
- {
- int cairo_val = CAIRO_LINE_CAP_SQUARE;
- switch (ctx_arg_u8 (0) )
+
+ if (match_len >= MIN_MATCH)
+ {
+ int start = span->start;
+ int length = span->length;
+
+ span->from_prev = 1;
+ span->start = prev_pos;
+ span->length = match_len;
+ dassert (span->start >= 0, prev_pos, prev_start, span->start);
+ dassert (span->length > 0, prev_pos, prev_start, span->length);
+
+ if (curr_pos)
{
- case CTX_CAP_ROUND:
- cairo_val = CAIRO_LINE_CAP_ROUND;
- break;
- case CTX_CAP_SQUARE:
- cairo_val = CAIRO_LINE_CAP_SQUARE;
- break;
- case CTX_CAP_NONE:
- cairo_val = CAIRO_LINE_CAP_BUTT;
- break;
+ CtxSpan *prev = calloc (sizeof (CtxSpan), 1);
+ prev->start = start;
+ prev->length = curr_pos;
+ dassert (prev->start >= 0, prev_pos, prev_start, prev->start);
+ dassert (prev->length > 0, prev_pos, prev_start, prev->length);
+ prev->from_prev = 0;
+ ctx_list_insert_before (&encoded_list, l, prev);
}
- cairo_set_line_cap (cr, cairo_val);
- }
- break;
- case CTX_BLEND_MODE:
- {
- // does not map to cairo
- }
- break;
- case CTX_COMPOSITING_MODE:
- {
- int cairo_val = CAIRO_OPERATOR_OVER;
- switch (ctx_arg_u8 (0) )
+
+
+ if (match_len + curr_pos < start + length)
{
- case CTX_COMPOSITE_SOURCE_OVER:
- cairo_val = CAIRO_OPERATOR_OVER;
- break;
- case CTX_COMPOSITE_COPY:
- cairo_val = CAIRO_OPERATOR_SOURCE;
- break;
+ CtxSpan *next = 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);
+ // dassert (next->length > 0, prev_pos, prev_start, next->length);
+ next->from_prev = 0;
+ if (next->length)
+ {
+ if (l->next)
+ ctx_list_insert_before (&encoded_list, l->next, next);
+ else
+ ctx_list_append (&encoded_list, next);
+ }
+ else
+ free (next);
}
- cairo_set_operator (cr, cairo_val);
- }
- case CTX_LINE_JOIN:
- {
- int cairo_val = CAIRO_LINE_JOIN_ROUND;
- switch (ctx_arg_u8 (0) )
+
+ if (curr_pos) // step one item back for forloop
{
- case CTX_JOIN_ROUND:
- cairo_val = CAIRO_LINE_JOIN_ROUND;
- break;
- case CTX_JOIN_BEVEL:
- cairo_val = CAIRO_LINE_JOIN_BEVEL;
- break;
- case CTX_JOIN_MITER:
- cairo_val = CAIRO_LINE_JOIN_MITER;
- break;
+ CtxList *tmp = encoded_list;
+ int found = 0;
+ while (!found && tmp && tmp->next)
+ {
+ if (tmp->next == l)
+ {
+ l = tmp;
+ break;
+ }
+ tmp = tmp->next;
+ }
}
- cairo_set_line_join (cr, cairo_val);
+ }
+ }
+ }
+
+ if (ctx_ticks ()-ticks_start > (unsigned long)max_ticks)
+ break;
+ }
+
+ /* merge adjecant prev span references */
+ {
+ for (CtxList *l = encoded_list; l; l = l->next)
+ {
+ CtxSpan *span = l->data;
+again:
+ if (l->next)
+ {
+ CtxSpan *next_span = l->next->data;
+ if (span->from_prev && next_span->from_prev &&
+ span->start + span->length ==
+ next_span->start)
+ {
+ span->length += next_span->length;
+ ctx_list_remove (&encoded_list, next_span);
+ goto again;
}
- break;
- case CTX_LINEAR_GRADIENT:
+ }
+ }
+ }
+
+ while (encoded_list)
+ {
+ CtxSpan *span = encoded_list->data;
+ if (span->from_prev)
+ {
+ char ref[128];
+ sprintf (ref, "%c%i %i%c", CTX_CODEC_CHAR, span->start, span->length, CTX_CODEC_CHAR);
+ ctx_string_append_data (string, ref, strlen(ref));
+ }
+ else
+ {
+ for (int i = span->start; i< span->start+span->length; i++)
+ {
+ if (src[i] == CTX_CODEC_CHAR)
{
- if (ctx_cairo->pat)
- {
- cairo_pattern_destroy (ctx_cairo->pat);
- ctx_cairo->pat = NULL;
- }
- ctx_cairo->pat = cairo_pattern_create_linear (ctx_arg_float (0), ctx_arg_float (1),
- ctx_arg_float (2), ctx_arg_float (3) );
- cairo_pattern_add_color_stop_rgba (ctx_cairo->pat, 0, 0, 0, 0, 1);
- cairo_pattern_add_color_stop_rgba (ctx_cairo->pat, 1, 1, 1, 1, 1);
- cairo_set_source (cr, ctx_cairo->pat);
+ ctx_string_append_byte (string, CTX_CODEC_CHAR);
+ ctx_string_append_byte (string, CTX_CODEC_CHAR);
}
- break;
- case CTX_RADIAL_GRADIENT:
+ else
{
- if (ctx_cairo->pat)
- {
- cairo_pattern_destroy (ctx_cairo->pat);
- ctx_cairo->pat = NULL;
- }
- ctx_cairo->pat = cairo_pattern_create_radial (ctx_arg_float (0), ctx_arg_float (1),
- ctx_arg_float (2), ctx_arg_float (3),
- ctx_arg_float (4), ctx_arg_float (5) );
- cairo_set_source (cr, ctx_cairo->pat);
+ ctx_string_append_byte (string, src[i]);
}
- break;
- case CTX_GRADIENT_STOP:
- cairo_pattern_add_color_stop_rgba (ctx_cairo->pat,
- ctx_arg_float (0),
- ctx_u8_to_float (ctx_arg_u8 (4) ),
- ctx_u8_to_float (ctx_arg_u8 (5) ),
- ctx_u8_to_float (ctx_arg_u8 (6) ),
- ctx_u8_to_float (ctx_arg_u8 (7) ) );
- break;
- // XXX implement TEXTURE
-#if 0
- case CTX_LOAD_IMAGE:
+ }
+ }
+ free (span);
+ ctx_list_remove (&encoded_list, span);
+ }
+
+ char *ret = string->str;
+ if (out_len) *out_len = string->length;
+ ctx_string_free (string, 0);
+ return ret;
+}
+
+#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)
+{
+ CtxString *string = ctx_string_new ("");
+ char reference[32]="";
+ int ref_len = 0;
+ int in_ref = 0;
+ for (int i = 0; i < enc_len; i++)
+ {
+ if (encoded[i] == CTX_CODEC_CHAR)
+ {
+ if (!in_ref)
+ {
+ in_ref = 1;
+ }
+ else
+ {
+ int start = atoi (reference);
+ int len = 0;
+ if (strchr (reference, ' '))
+ len = atoi (strchr (reference, ' ')+1);
+
+ if (start < 0)start = 0;
+ if (start >= prev_len)start = prev_len-1;
+ if (len + start > prev_len)
+ len = prev_len - start;
+
+ if (start == 0 && len == 0)
+ ctx_string_append_byte (string, CTX_CODEC_CHAR);
+ else
+ ctx_string_append_data (string, prev + start, len);
+ ref_len = 0;
+ in_ref = 0;
+ }
+ }
+ else
+ {
+ if (in_ref)
+ {
+ if (ref_len < 16)
{
- if (image)
- {
- cairo_surface_destroy (image);
- image = NULL;
- }
- if (pat)
- {
- cairo_pattern_destroy (pat);
- pat = NULL;
- }
- image = cairo_image_surface_create_from_png (ctx_arg_string() );
- cairo_set_source_surface (cr, image, ctx_arg_float (0), ctx_arg_float (1) );
+ reference[ref_len++] = encoded[i];
+ reference[ref_len] = 0;
}
- break;
-#endif
- case CTX_TEXT:
- /* XXX: implement some linebreaking/wrap, positioning
- * behavior here
- */
- cairo_show_text (cr, ctx_arg_string () );
- break;
- case CTX_CONT:
- case CTX_EDGE:
- case CTX_DATA:
- case CTX_DATA_REV:
- case CTX_FLUSH:
- break;
+ }
+ else
+ ctx_string_append_byte (string, encoded[i]);
}
- ctx_process (ctx_cairo->ctx, entry);
+ }
+ char *ret = string->str;
+ if (out_len) *out_len = string->length;
+ ctx_string_free (string, 0);
+ return ret;
}
+#endif
-void ctx_cairo_free (CtxCairo *ctx_cairo)
+#define CTX_START_STRING "U\n" // or " reset "
+#define CTX_END_STRING "\nX" // or "\ndone"
+#define CTX_END_STRING2 "\n\e"
+
+int ctx_frame_ack = -1;
+static char *prev_frame_contents = NULL;
+static int prev_frame_len = 0;
+
+static void ctx_ctx_flush (CtxCtx *ctxctx)
{
- if (ctx_cairo->pat)
- { cairo_pattern_destroy (ctx_cairo->pat); }
- if (ctx_cairo->image)
- { cairo_surface_destroy (ctx_cairo->image); }
- free (ctx_cairo);
+#if 0
+ FILE *debug = fopen ("/tmp/ctx-debug", "a");
+ fprintf (debug, "------\n");
+#endif
+
+ if (ctx_native_events)
+ fprintf (stdout, "\e[?201h");
+ fprintf (stdout, "\e[H\e[?25l\e[?200h");
+#if 0
+ fprintf (stdout, CTX_START_STRING);
+ ctx_render_stream (ctxctx->ctx, stdout, 0);
+ fprintf (stdout, CTX_END_STRING);
+#else
+ {
+ 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);
+
+ 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);
+ cur_frame_len += strlen (CTX_START_STRING) + strlen (CTX_END_STRING);
+
+ if (prev_frame_contents && 0) // XXX :
+ {
+ char *encoded;
+ int encoded_len = 0;
+ //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);
+ //uint64_t ticks_end = ctx_ticks ();
+
+ fwrite (encoded, encoded_len, 1, stdout);
+// fwrite (encoded, cur_frame_len, 1, stdout);
+#if 0
+ fprintf (debug, "---prev-frame(%i)\n%s", (int)strlen(prev_frame_contents), prev_frame_contents);
+ fprintf (debug, "---cur-frame(%i)\n%s", (int)strlen(cur_frame_contents), cur_frame_contents);
+ fprintf (debug, "---encoded(%.4f %i)---\n%s--------\n",
+ (ticks_end-ticks_start)/1000.0,
+ (int)strlen(encoded), encoded);
+#endif
+ free (encoded);
+ }
+ else
+ {
+ fwrite (cur_frame_contents, cur_frame_len, 1, stdout);
+ }
+
+ if (prev_frame_contents)
+ free (prev_frame_contents);
+ prev_frame_contents = cur_frame_contents;
+ prev_frame_len = cur_frame_len;
+ }
+#endif
+#if 0
+ fclose (debug);
+#endif
+ fprintf (stdout, CTX_END_STRING2);
+
+ fprintf (stdout, "\e[5n");
+ fflush (stdout);
+
+ ctx_frame_ack = 0;
+ do {
+ ctx_consume_events (ctxctx->ctx);
+ } while (ctx_frame_ack != 1);
}
-void
-ctx_render_cairo (Ctx *ctx, cairo_t *cr)
+void ctx_ctx_free (CtxCtx *ctx)
{
- CtxIterator iterator;
- CtxCommand *command;
- CtxCairo ctx_cairo = {{(void*)ctx_cairo_process, NULL, NULL}, ctx, cr, NULL, NULL};
- ctx_iterator_init (&iterator, &ctx->drawlist, 0,
- CTX_ITERATOR_EXPAND_BITPACK);
- while ( (command = ctx_iterator_next (&iterator) ) )
- { ctx_cairo_process (&ctx_cairo, command); }
+ nc_at_exit ();
+ free (ctx);
+ /* we're not destoring the ctx member, this is function is called in ctx' teardown */
}
-Ctx *
-ctx_new_for_cairo (cairo_t *cr)
+Ctx *ctx_new_ctx (int width, int height)
{
Ctx *ctx = ctx_new ();
- CtxCairo *ctx_cairo = calloc(sizeof(CtxCairo),1);
- ctx_cairo->vfuncs.free = (void*)ctx_cairo_free;
- ctx_cairo->vfuncs.process = (void*)ctx_cairo_process;
- ctx_cairo->ctx = ctx;
- ctx_cairo->cr = cr;
-
- ctx_set_renderer (ctx, (void*)ctx_cairo);
+ CtxCtx *ctxctx = (CtxCtx*)calloc (sizeof (CtxCtx), 1);
+ fprintf (stdout, "\e[?1049h");
+ //fprintf (stderr, "\e[H");
+ //fprintf (stderr, "\e[2J");
+ ctx_native_events = 1;
+ if (width <= 0 || height <= 0)
+ {
+ ctxctx->cols = ctx_terminal_cols ();
+ ctxctx->rows = ctx_terminal_rows ();
+ width = ctxctx->width = ctx_terminal_width ();
+ height = ctxctx->height = ctx_terminal_height ();
+ }
+ else
+ {
+ ctxctx->width = width;
+ ctxctx->height = height;
+ ctxctx->cols = width / 80;
+ ctxctx->rows = height / 24;
+ }
+ ctxctx->ctx = ctx;
+ if (!ctx_native_events)
+ _ctx_mouse (ctx, NC_MOUSE_DRAG);
+ ctx_set_renderer (ctx, ctxctx);
+ ctx_set_size (ctx, width, height);
+ ctxctx->flush = (void(*)(void *))ctx_ctx_flush;
+ ctxctx->free = (void(*)(void *))ctx_ctx_free;
return ctx;
}
+int ctx_ctx_consume_events (Ctx *ctx)
+{
+ int ix, iy;
+ CtxCtx *ctxctx = (CtxCtx*)ctx->renderer;
+ const char *event = NULL;
+ if (ctx_native_events)
+ {
+ float x = 0, y = 0;
+ int b = 0;
+ char event_type[128]="";
+ event = ctx_native_get_event (ctx, 1000/120);
+#if 0
+ if(event){
+ FILE *file = fopen ("/tmp/log", "a");
+ fprintf (file, "[%s]\n", event);
+ fclose (file);
+ }
#endif
+ if (event)
+ {
+ sscanf (event, "%s %f %f %i", event_type, &x, &y, &b);
+ if (!strcmp (event_type, "idle"))
+ {
+ }
+ else if (!strcmp (event_type, "mouse-press"))
+ {
+ ctx_pointer_press (ctx, x, y, b, 0);
+ }
+ else if (!strcmp (event_type, "mouse-drag")||
+ !strcmp (event_type, "mouse-motion"))
+ {
+ ctx_pointer_motion (ctx, x, y, b, 0);
+ }
+ else if (!strcmp (event_type, "mouse-release"))
+ {
+ ctx_pointer_release (ctx, x, y, b, 0);
+ }
+ else if (!strcmp (event_type, "message"))
+ {
+ ctx_incoming_message (ctx, event + strlen ("message"), 0);
+ } else if (!strcmp (event, "size-changed"))
+ {
+ fprintf (stdout, "\e[H\e[2J\e[?25l");
+ ctxctx->cols = ctx_terminal_cols ();
+ ctxctx->rows = ctx_terminal_rows ();
+ ctxctx->width = ctx_terminal_width ();
+ ctxctx->height = ctx_terminal_height ();
+ ctx_set_size (ctx, ctxctx->width, ctxctx->height);
-#if CTX_EVENTS
-
-static int ctx_find_largest_matching_substring
- (const char *X, const char *Y, int m, int n, int *offsetY, int *offsetX)
-{
- int longest_common_suffix[2][n+1];
- int best_length = 0;
- for (int i=0; i<=m; i++)
- {
- for (int j=0; j<=n; j++)
- {
- if (i == 0 || j == 0 || !(X[i-1] == Y[j-1]))
+ if (prev_frame_contents)
+ free (prev_frame_contents);
+ prev_frame_contents = NULL;
+ prev_frame_len = 0;
+ ctx_set_dirty (ctx, 1);
+ //ctx_key_press (ctx, 0, "size-changed", 0);
+ }
+ else if (!strcmp (event_type, "keyup"))
{
- longest_common_suffix[i%2][j] = 0;
+ char buf[4]={ x, 0 };
+ ctx_key_up (ctx, (int)x, buf, 0);
+ }
+ else if (!strcmp (event_type, "keydown"))
+ {
+ char buf[4]={ x, 0 };
+ ctx_key_down (ctx, (int)x, buf, 0);
}
else
{
- longest_common_suffix[i%2][j] = longest_common_suffix[(i-1)%2][j-1] + 1;
- if (best_length < longest_common_suffix[i%2][j])
- {
- best_length = longest_common_suffix[i%2][j];
- if (offsetY) *offsetY = j - best_length;
- if (offsetX) *offsetX = i - best_length;
- }
+ ctx_key_press (ctx, 0, event, 0);
+ }
}
}
- }
- return best_length;
-}
+ else
+ {
+ float x, y;
+ event = ctx_nct_get_event (ctx, 20, &ix, &iy);
+ x = (ix - 1.0 + 0.5) / ctxctx->cols * ctx->events.width;
+ y = (iy - 1.0) / ctxctx->rows * ctx->events.height;
-typedef struct CtxSpan {
- int from_prev;
- int start;
- int length;
-} CtxSpan;
+ if (!strcmp (event, "mouse-press"))
+ {
+ ctx_pointer_press (ctx, x, y, 0, 0);
+ ctxctx->was_down = 1;
+ } else if (!strcmp (event, "mouse-release"))
+ {
+ ctx_pointer_release (ctx, x, y, 0, 0);
+ } else if (!strcmp (event, "mouse-motion"))
+ {
+ //nct_set_cursor_pos (backend->term, ix, iy);
+ //nct_flush (backend->term);
+ if (ctxctx->was_down)
+ {
+ ctx_pointer_release (ctx, x, y, 0, 0);
+ ctxctx->was_down = 0;
+ }
+ ctx_pointer_motion (ctx, x, y, 0, 0);
+ } else if (!strcmp (event, "mouse-drag"))
+ {
+ ctx_pointer_motion (ctx, x, y, 0, 0);
+ } else if (!strcmp (event, "size-changed"))
+ {
+ fprintf (stdout, "\e[H\e[2J\e[?25l");
+ ctxctx->cols = ctx_terminal_cols ();
+ ctxctx->rows = ctx_terminal_rows ();
+ ctxctx->width = ctx_terminal_width ();
+ ctxctx->height = ctx_terminal_height ();
+ ctx_set_size (ctx, ctxctx->width, ctxctx->height);
-#define CHUNK_SIZE 32
-#define MIN_MATCH 7 // minimum match length to be encoded
-#define WINDOW_PADDING 16 // look-aside amount
+ if (prev_frame_contents)
+ free (prev_frame_contents);
+ prev_frame_contents = NULL;
+ prev_frame_len = 0;
+ ctx_set_dirty (ctx, 1);
+ //ctx_key_press (ctx, 0, "size-changed", 0);
+ }
+ else
+ {
+ if (!strcmp (event, "esc"))
+ ctx_key_press (ctx, 0, "escape", 0);
+ else if (!strcmp (event, "space"))
+ ctx_key_press (ctx, 0, "space", 0);
+ else if (!strcmp (event, "enter")||
+ !strcmp (event, "return"))
+ ctx_key_press (ctx, 0, "\n", 0);
+ else
+ ctx_key_press (ctx, 0, event, 0);
+ }
+ }
-#if 0
-static void _dassert(int line, int condition, const char *str, int foo, int bar, int baz)
-{
- if (!condition)
- {
- FILE *f = fopen ("/tmp/cdebug", "a");
- fprintf (f, "%i: %s %i %i %i\n", line, str, foo, bar, baz);
- fclose (f);
- }
+ return 1;
}
-#define dassert(cond, foo, bar, baz) _dassert(__LINE__, cond, #cond, foo, bar ,baz)
-#endif
-#define dassert(cond, foo, bar, baz)
-/* XXX repeated substring matching is slow, we'll be
- * better off with a hash-table with linked lists of
- * matching 3-4 characters in previous.. or even
- * a naive approach that expects rough alignment..
- */
-static char *encode_in_terms_of_previous (
- const char *src, int src_len,
- const char *prev, int prev_len,
- int *out_len,
- int max_ticks)
+int ctx_renderer_is_ctx (Ctx *ctx)
{
- CtxString *string = ctx_string_new ("");
- CtxList *encoded_list = NULL;
-
- /* TODO : make expected position offset in prev slide based on
- * matches and not be constant */
-
- long ticks_start = ctx_ticks ();
- int start = 0;
- int length = CHUNK_SIZE;
- for (start = 0; start < src_len; start += length)
- {
- CtxSpan *span = calloc (sizeof (CtxSpan), 1);
- span->start = start;
- if (start + length > src_len)
- span->length = src_len - start;
- else
- span->length = length;
- span->from_prev = 0;
- ctx_list_append (&encoded_list, span);
- }
-
- for (CtxList *l = encoded_list; l; l = l->next)
- {
- CtxSpan *span = l->data;
- if (!span->from_prev)
- {
- if (span->length >= MIN_MATCH)
- {
- int prev_pos = 0;
- int curr_pos = 0;
- assert(1);
-#if 0
- int prev_start = 0;
- int prev_window_length = prev_len;
-#else
- int window_padding = WINDOW_PADDING;
- int prev_start = span->start - window_padding;
- if (prev_start < 0)
- prev_start = 0;
-
- dassert(span->start>=0 , 0,0,0);
+ if (ctx->renderer &&
+ ctx->renderer->free == (void*)ctx_ctx_free)
+ return 1;
+ return 0;
+}
- int prev_window_length = prev_len - prev_start;
- if (prev_window_length > span->length + window_padding * 2 + span->start)
- prev_window_length = span->length + window_padding * 2 + span->start;
-#endif
- int match_len = 0;
- if (prev_window_length > 0)
- match_len = ctx_find_largest_matching_substring(prev + prev_start, src + span->start,
prev_window_length, span->length, &curr_pos, &prev_pos);
-#if 1
- prev_pos += prev_start;
#endif
- if (match_len >= MIN_MATCH)
- {
- int start = span->start;
- int length = span->length;
-
- span->from_prev = 1;
- span->start = prev_pos;
- span->length = match_len;
- dassert (span->start >= 0, prev_pos, prev_start, span->start);
- dassert (span->length > 0, prev_pos, prev_start, span->length);
-
- if (curr_pos)
- {
- CtxSpan *prev = calloc (sizeof (CtxSpan), 1);
- prev->start = start;
- prev->length = curr_pos;
- dassert (prev->start >= 0, prev_pos, prev_start, prev->start);
- dassert (prev->length > 0, prev_pos, prev_start, prev->length);
- prev->from_prev = 0;
- ctx_list_insert_before (&encoded_list, l, prev);
- }
-
+#if CTX_TILED
+static inline int
+ctx_tiled_threads_done (CtxTiled *tiled)
+{
+ int sum = 0;
+ for (int i = 0; i < _ctx_max_threads; i++)
+ {
+ if (tiled->rendered_frame[i] == tiled->render_frame)
+ sum ++;
+ }
+ return sum;
+}
- if (match_len + curr_pos < start + length)
- {
- CtxSpan *next = 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);
- // dassert (next->length > 0, prev_pos, prev_start, next->length);
- next->from_prev = 0;
- if (next->length)
- {
- if (l->next)
- ctx_list_insert_before (&encoded_list, l->next, next);
- else
- ctx_list_append (&encoded_list, next);
- }
- else
- free (next);
- }
+void ctx_tiled_free (CtxTiled *tiled)
+{
+ tiled->quit = 1;
+ mtx_lock (&tiled->mtx);
+ cnd_broadcast (&tiled->cond);
+ mtx_unlock (&tiled->mtx);
- if (curr_pos) // step one item back for forloop
- {
- CtxList *tmp = encoded_list;
- int found = 0;
- while (!found && tmp && tmp->next)
- {
- if (tmp->next == l)
- {
- l = tmp;
- break;
- }
- tmp = tmp->next;
- }
- }
- }
- }
- }
+ while (tiled->thread_quit < _ctx_max_threads)
+ usleep (1000);
- if (ctx_ticks ()-ticks_start > (unsigned long)max_ticks)
- break;
+ if (tiled->pixels)
+ {
+ free (tiled->pixels);
+ tiled->pixels = NULL;
+ for (int i = 0 ; i < _ctx_max_threads; i++)
+ {
+ ctx_free (tiled->host[i]);
+ tiled->host[i]=NULL;
}
- /* merge adjecant prev span references */
+ ctx_free (tiled->ctx_copy);
+ }
+ // leak?
+}
+
+inline static void ctx_tiled_flush (CtxTiled *tiled)
+{
+ if (tiled->shown_frame == tiled->render_frame)
{
- for (CtxList *l = encoded_list; l; l = l->next)
+ int dirty_tiles = 0;
+ ctx_set_drawlist (tiled->ctx_copy, &tiled->ctx->drawlist.entries[0],
+ tiled->ctx->drawlist.count * 9);
+ if (_ctx_enable_hash_cache)
{
- CtxSpan *span = l->data;
-again:
- if (l->next)
+ Ctx *hasher = ctx_hasher_new (tiled->width, tiled->height,
+ CTX_HASH_COLS, CTX_HASH_ROWS);
+ ctx_render_ctx (tiled->ctx_copy, hasher);
+
+ for (int row = 0; row < CTX_HASH_ROWS; row++)
+ for (int col = 0; col < CTX_HASH_COLS; col++)
+ {
+ uint8_t *new_hash = ctx_hasher_get_hash (hasher, col, row);
+ if (new_hash && memcmp (new_hash, &tiled->hashes[(row * CTX_HASH_COLS + col) * 20], 20))
+ {
+ memcpy (&tiled->hashes[(row * CTX_HASH_COLS + col)*20], new_hash, 20);
+ tiled->tile_affinity[row * CTX_HASH_COLS + col] = 1;
+ dirty_tiles++;
+ }
+ else
+ {
+ tiled->tile_affinity[row * CTX_HASH_COLS + col] = -1;
+ }
+ }
+ free (((CtxHasher*)(hasher->renderer))->hashes);
+ ctx_free (hasher);
+ }
+ else
+ {
+ for (int row = 0; row < CTX_HASH_ROWS; row++)
+ for (int col = 0; col < CTX_HASH_COLS; col++)
+ {
+ tiled->tile_affinity[row * CTX_HASH_COLS + col] = 1;
+ dirty_tiles++;
+ }
+ }
+ int dirty_no = 0;
+ if (dirty_tiles)
+ for (int row = 0; row < CTX_HASH_ROWS; row++)
+ for (int col = 0; col < CTX_HASH_COLS; col++)
{
- CtxSpan *next_span = l->next->data;
- if (span->from_prev && next_span->from_prev &&
- span->start + span->length ==
- next_span->start)
+ if (tiled->tile_affinity[row * CTX_HASH_COLS + col] != -1)
{
- span->length += next_span->length;
- ctx_list_remove (&encoded_list, next_span);
- goto again;
+ tiled->tile_affinity[row * CTX_HASH_COLS + col] = dirty_no * (_ctx_max_threads) / dirty_tiles;
+ dirty_no++;
+ if (col > tiled->max_col) tiled->max_col = col;
+ if (col < tiled->min_col) tiled->min_col = col;
+ if (row > tiled->max_row) tiled->max_row = row;
+ if (row < tiled->min_row) tiled->min_row = row;
}
}
+
+#if CTX_DAMAGE_CONTROL
+ for (int i = 0; i < tiled->width * tiled->height; i++)
+ {
+ int new_ = (tiled->pixels[i*4+0]+ tiled->pixels[i*4+1]+ tiled->pixels[i*4+2])/3;
+ //if (new_>1) new_--;
+ tiled->pixels[i*4] = (tiled->pixels[i*4] + 255)/2;
+ tiled->pixels[i*4+1]= (tiled->pixels[i*4+1] + new_)/2;
+ tiled->pixels[i*4+2]= (tiled->pixels[i*4+1] + new_)/2;
}
+#endif
+
+ tiled->render_frame = ++tiled->frame;
+
+ mtx_lock (&tiled->mtx);
+ cnd_broadcast (&tiled->cond);
+ mtx_unlock (&tiled->mtx);
}
+}
+static unsigned char *sdl_icc = NULL;
+static long sdl_icc_length = 0;
- while (encoded_list)
+static
+void ctx_tiled_render_fun (void **data)
+{
+ int no = (size_t)data[0];
+ CtxTiled *tiled = data[1];
+
+ while (!tiled->quit)
{
- CtxSpan *span = encoded_list->data;
- if (span->from_prev)
- {
- char ref[128];
- sprintf (ref, "%c%i %i%c", CTX_CODEC_CHAR, span->start, span->length, CTX_CODEC_CHAR);
- ctx_string_append_data (string, ref, strlen(ref));
- }
- else
+ Ctx *host = tiled->host[no];
+
+ mtx_lock (&tiled->mtx);
+ cnd_wait(&tiled->cond, &tiled->mtx);
+ mtx_unlock (&tiled->mtx);
+
+ if (tiled->render_frame != tiled->rendered_frame[no])
{
- for (int i = span->start; i< span->start+span->length; i++)
- {
- if (src[i] == CTX_CODEC_CHAR)
- {
- ctx_string_append_byte (string, CTX_CODEC_CHAR);
- ctx_string_append_byte (string, CTX_CODEC_CHAR);
- }
- else
+ int hno = 0;
+ for (int row = 0; row < CTX_HASH_ROWS; row++)
+ for (int col = 0; col < CTX_HASH_COLS; col++, hno++)
{
- ctx_string_append_byte (string, src[i]);
+ if (tiled->tile_affinity[hno]==no)
+ {
+ int x0 = ((tiled->width)/CTX_HASH_COLS) * col;
+ int y0 = ((tiled->height)/CTX_HASH_ROWS) * row;
+ int width = tiled->width / CTX_HASH_COLS;
+ int height = tiled->height / CTX_HASH_ROWS;
+
+ CtxRasterizer *rasterizer = (CtxRasterizer*)host->renderer;
+#if 1 // merge horizontally adjecant tiles of same affinity into one job
+ while (col + 1 < CTX_HASH_COLS &&
+ tiled->tile_affinity[hno+1] == no)
+ {
+ width += tiled->width / CTX_HASH_COLS;
+ col++;
+ hno++;
+ }
+#endif
+ int swap_red_green = ((CtxRasterizer*)(host->renderer))->swap_red_green;
+ ctx_rasterizer_init (rasterizer,
+ host, tiled->ctx, &host->state,
+ &tiled->pixels[tiled->width * 4 * y0 + x0 * 4],
+ 0, 0, width, height,
+ tiled->width*4, CTX_FORMAT_RGBA8,
+ tiled->antialias);
+ ((CtxRasterizer*)(host->renderer))->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 (tiled->ctx_copy, host);
+ }
}
- }
+ tiled->rendered_frame[no] = tiled->render_frame;
}
- free (span);
- ctx_list_remove (&encoded_list, span);
}
+ tiled->thread_quit++; // need atomic?
+}
+
+#endif
+
+
+#if CTX_EVENTS
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+
+
+#if CTX_FB
+ #include <linux/fb.h>
+ #include <linux/vt.h>
+ #include <linux/kd.h>
+ #include <sys/mman.h>
+ #include <threads.h>
+ #include <libdrm/drm.h>
+ #include <libdrm/drm_mode.h>
+
+typedef struct _EvSource EvSource;
+
+
+struct _EvSource
+{
+ void *priv; /* private storage */
+
+ /* returns non 0 if there is events waiting */
+ int (*has_event) (EvSource *ev_source);
+
+ /* get an event, the returned event should be freed by the caller */
+ char *(*get_event) (EvSource *ev_source);
+
+ /* destroy/unref this instance */
+ void (*destroy) (EvSource *ev_source);
+
+ /* get the underlying fd, useful for using select on */
+ int (*get_fd) (EvSource *ev_source);
+
+
+ void (*set_coord) (EvSource *ev_source, double x, double y);
+ /* set_coord is needed to warp relative cursors into normalized range,
+ * like normal mice/trackpads/nipples - to obey edges and more.
+ */
+
+ /* if this returns non-0 select can be used for non-blocking.. */
+};
+
+
+typedef struct _CtxFb CtxFb;
+struct _CtxFb
+{
+ CtxTiled tiled;
+#if 0
+ void (*render) (void *fb, CtxCommand *command);
+ void (*reset) (void *fb);
+ void (*flush) (void *fb);
+ char *(*get_clipboard) (void *ctxctx);
+ void (*set_clipboard) (void *ctxctx, const char *text);
+ void (*free) (void *fb);
+ Ctx *ctx;
+ int width;
+ int height;
+ int cols; // unused
+ int rows; // unused
+ int was_down;
+ uint8_t *pixels;
+ Ctx *ctx_copy;
+ Ctx *host[CTX_MAX_THREADS];
+ CtxAntialias antialias;
+ int quit;
+ _Atomic int thread_quit;
+ int shown_frame;
+ int render_frame;
+ int rendered_frame[CTX_MAX_THREADS];
+ int frame;
+ int min_col; // hasher cols and rows
+ int min_row;
+ int max_col;
+ int max_row;
+ uint8_t hashes[CTX_HASH_ROWS * CTX_HASH_COLS * 20];
+ int8_t tile_affinity[CTX_HASH_ROWS * CTX_HASH_COLS]; // which render thread no is
+ // responsible for a tile
+ //
+
+
+ int pointer_down[3];
+#endif
+ int key_balance;
+ int key_repeat;
+ int lctrl;
+ int lalt;
+ int rctrl;
+
+ uint8_t *fb;
+
+ int fb_fd;
+ char *fb_path;
+ int fb_bits;
+ int fb_bpp;
+ int fb_mapped_size;
+ struct fb_var_screeninfo vinfo;
+ struct fb_fix_screeninfo finfo;
+ int vt;
+ int tty;
+ int vt_active;
+ EvSource *evsource[4];
+ int evsource_count;
+ int is_drm;
+ cnd_t cond;
+ mtx_t mtx;
+ struct drm_mode_crtc crtc;
+};
+
+static char *ctx_fb_clipboard = NULL;
+static void ctx_fb_set_clipboard (CtxFb *fb, const char *text)
+{
+ if (ctx_fb_clipboard)
+ free (ctx_fb_clipboard);
+ ctx_fb_clipboard = NULL;
+ if (text)
+ {
+ ctx_fb_clipboard = strdup (text);
+ }
+}
- char *ret = string->str;
- if (out_len) *out_len = string->length;
- ctx_string_free (string, 0);
- return ret;
+static char *ctx_fb_get_clipboard (CtxFb *sdl)
+{
+ if (ctx_fb_clipboard) return strdup (ctx_fb_clipboard);
+ return strdup ("");
}
-#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)
+#if UINTPTR_MAX == 0xffFFffFF
+ #define fbdrmuint_t uint32_t
+#elif UINTPTR_MAX == 0xffFFffFFffFFffFF
+ #define fbdrmuint_t uint64_t
+#endif
+
+void *ctx_fbdrm_new (CtxFb *fb, int *width, int *height)
{
- CtxString *string = ctx_string_new ("");
- char reference[32]="";
- int ref_len = 0;
- int in_ref = 0;
- for (int i = 0; i < enc_len; i++)
- {
- if (encoded[i] == CTX_CODEC_CHAR)
- {
- if (!in_ref)
- {
- in_ref = 1;
- }
- else
- {
- int start = atoi (reference);
- int len = 0;
- if (strchr (reference, ' '))
- len = atoi (strchr (reference, ' ')+1);
+ int got_master = 0;
+ fb->fb_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
+ if (!fb->fb_fd)
+ return NULL;
+ static fbdrmuint_t res_conn_buf[20]={0}; // this is static since its contents
+ // are used by the flip callback
+ fbdrmuint_t res_fb_buf[20]={0};
+ fbdrmuint_t res_crtc_buf[20]={0};
+ fbdrmuint_t res_enc_buf[20]={0};
+ struct drm_mode_card_res res={0};
- if (start < 0)start = 0;
- if (start >= prev_len)start = prev_len-1;
- if (len + start > prev_len)
- len = prev_len - start;
+ if (ioctl(fb->fb_fd, DRM_IOCTL_SET_MASTER, 0))
+ goto cleanup;
+ got_master = 1;
- if (start == 0 && len == 0)
- ctx_string_append_byte (string, CTX_CODEC_CHAR);
- else
- ctx_string_append_data (string, prev + start, len);
- ref_len = 0;
- in_ref = 0;
- }
- }
- else
- {
- if (in_ref)
- {
- if (ref_len < 16)
- {
- reference[ref_len++] = encoded[i];
- reference[ref_len] = 0;
- }
- }
- else
- ctx_string_append_byte (string, encoded[i]);
- }
- }
- char *ret = string->str;
- if (out_len) *out_len = string->length;
- ctx_string_free (string, 0);
- return ret;
-}
-#endif
+ if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
+ goto cleanup;
+ res.fb_id_ptr=(fbdrmuint_t)res_fb_buf;
+ res.crtc_id_ptr=(fbdrmuint_t)res_crtc_buf;
+ res.connector_id_ptr=(fbdrmuint_t)res_conn_buf;
+ res.encoder_id_ptr=(fbdrmuint_t)res_enc_buf;
+ if(ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
+ goto cleanup;
-#define CTX_START_STRING "U\n" // or " reset "
-#define CTX_END_STRING "\nX" // or "\ndone"
-#define CTX_END_STRING2 "\n\e"
-int ctx_frame_ack = -1;
-static char *prev_frame_contents = NULL;
-static int prev_frame_len = 0;
+ unsigned int i;
+ for (i=0;i<res.count_connectors;i++)
+ {
+ struct drm_mode_modeinfo conn_mode_buf[20]={0};
+ fbdrmuint_t conn_prop_buf[20]={0},
+ conn_propval_buf[20]={0},
+ conn_enc_buf[20]={0};
-static void ctx_ctx_flush (CtxCtx *ctxctx)
-{
-#if 0
- FILE *debug = fopen ("/tmp/ctx-debug", "a");
- fprintf (debug, "------\n");
-#endif
+ struct drm_mode_get_connector conn={0};
- if (ctx_native_events)
- fprintf (stdout, "\e[?201h");
- fprintf (stdout, "\e[H\e[?25l\e[?200h");
-#if 0
- fprintf (stdout, CTX_START_STRING);
- ctx_render_stream (ctxctx->ctx, stdout, 0);
- fprintf (stdout, CTX_END_STRING);
-#else
- {
- 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);
+ conn.connector_id=res_conn_buf[i];
- 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);
- cur_frame_len += strlen (CTX_START_STRING) + strlen (CTX_END_STRING);
+ if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
+ goto cleanup;
- if (prev_frame_contents)
- {
- char *encoded;
- int encoded_len = 0;
- //uint64_t ticks_start = ctx_ticks ();
+ conn.modes_ptr=(fbdrmuint_t)conn_mode_buf;
+ conn.props_ptr=(fbdrmuint_t)conn_prop_buf;
+ conn.prop_values_ptr=(fbdrmuint_t)conn_propval_buf;
+ conn.encoders_ptr=(fbdrmuint_t)conn_enc_buf;
- 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);
- //uint64_t ticks_end = ctx_ticks ();
+ if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
+ goto cleanup;
- fwrite (encoded, encoded_len, 1, stdout);
-// fwrite (encoded, cur_frame_len, 1, stdout);
-#if 0
- fprintf (debug, "---prev-frame(%i)\n%s", (int)strlen(prev_frame_contents), prev_frame_contents);
- fprintf (debug, "---cur-frame(%i)\n%s", (int)strlen(cur_frame_contents), cur_frame_contents);
- fprintf (debug, "---encoded(%.4f %i)---\n%s--------\n",
- (ticks_end-ticks_start)/1000.0,
- (int)strlen(encoded), encoded);
-#endif
- free (encoded);
- }
- else
- {
- fwrite (cur_frame_contents, cur_frame_len, 1, stdout);
- }
+ //Check if the connector is OK to use (connected to something)
+ if (conn.count_encoders<1 || conn.count_modes<1 || !conn.encoder_id || !conn.connection)
+ continue;
- if (prev_frame_contents)
- free (prev_frame_contents);
- prev_frame_contents = cur_frame_contents;
- prev_frame_len = cur_frame_len;
- }
-#endif
-#if 0
- fclose (debug);
-#endif
- fprintf (stdout, CTX_END_STRING2);
+//------------------------------------------------------------------------------
+//Creating a dumb buffer
+//------------------------------------------------------------------------------
+ struct drm_mode_create_dumb create_dumb={0};
+ struct drm_mode_map_dumb map_dumb={0};
+ struct drm_mode_fb_cmd cmd_dumb={0};
+ create_dumb.width = conn_mode_buf[0].hdisplay;
+ create_dumb.height = conn_mode_buf[0].vdisplay;
+ create_dumb.bpp = 32;
+ create_dumb.flags = 0;
+ create_dumb.pitch = 0;
+ create_dumb.size = 0;
+ create_dumb.handle = 0;
+ if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) ||
+ !create_dumb.handle)
+ goto cleanup;
- fprintf (stdout, "\e[5n");
- fflush (stdout);
+ cmd_dumb.width =create_dumb.width;
+ cmd_dumb.height=create_dumb.height;
+ cmd_dumb.bpp =create_dumb.bpp;
+ cmd_dumb.pitch =create_dumb.pitch;
+ cmd_dumb.depth =24;
+ cmd_dumb.handle=create_dumb.handle;
+ if (ioctl(fb->fb_fd,DRM_IOCTL_MODE_ADDFB,&cmd_dumb))
+ goto cleanup;
+
+ map_dumb.handle=create_dumb.handle;
+ if (ioctl(fb->fb_fd,DRM_IOCTL_MODE_MAP_DUMB,&map_dumb))
+ goto cleanup;
+
+ void *base = mmap(0, create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fb->fb_fd, map_dumb.offset);
+ if (!base)
+ {
+ goto cleanup;
+ }
+ *width = create_dumb.width;
+ *height = create_dumb.height;
+
+ struct drm_mode_get_encoder enc={0};
+ enc.encoder_id=conn.encoder_id;
+ if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETENCODER, &enc))
+ goto cleanup;
+
+ fb->crtc.crtc_id=enc.crtc_id;
+ if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCRTC, &fb->crtc))
+ goto cleanup;
+
+ fb->crtc.fb_id=cmd_dumb.fb_id;
+ fb->crtc.set_connectors_ptr=(fbdrmuint_t)&res_conn_buf[i];
+ fb->crtc.count_connectors=1;
+ fb->crtc.mode=conn_mode_buf[0];
+ fb->crtc.mode_valid=1;
+ return base;
+ }
+cleanup:
+ if (got_master)
+ ioctl(fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
+ fb->fb_fd = 0;
+ return NULL;
+}
- ctx_frame_ack = 0;
- do {
- ctx_consume_events (ctxctx->ctx);
- } while (ctx_frame_ack != 1);
+void ctx_fbdrm_flip (CtxFb *fb)
+{
+ if (!fb->fb_fd)
+ return;
+ ioctl(fb->fb_fd, DRM_IOCTL_MODE_SETCRTC, &fb->crtc);
}
-void ctx_ctx_free (CtxCtx *ctx)
+void ctx_fbdrm_close (CtxFb *fb)
{
- nc_at_exit ();
- free (ctx);
- /* we're not destoring the ctx member, this is function is called in ctx' teardown */
+ if (!fb->fb_fd)
+ return;
+ ioctl(fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
+ close (fb->fb_fd);
+ fb->fb_fd = 0;
}
-Ctx *ctx_new_ctx (int width, int height)
+static void ctx_fb_flip (CtxFb *fb)
{
- Ctx *ctx = ctx_new ();
- CtxCtx *ctxctx = (CtxCtx*)calloc (sizeof (CtxCtx), 1);
- fprintf (stdout, "\e[?1049h");
- //fprintf (stderr, "\e[H");
- //fprintf (stderr, "\e[2J");
- ctx_native_events = 1;
- if (width <= 0 || height <= 0)
- {
- ctxctx->cols = ctx_terminal_cols ();
- ctxctx->rows = ctx_terminal_rows ();
- width = ctxctx->width = ctx_terminal_width ();
- height = ctxctx->height = ctx_terminal_height ();
- }
+ if (fb->is_drm)
+ ctx_fbdrm_flip (fb);
else
- {
- ctxctx->width = width;
- ctxctx->height = height;
- ctxctx->cols = width / 80;
- ctxctx->rows = height / 24;
- }
- ctxctx->ctx = ctx;
- if (!ctx_native_events)
- _ctx_mouse (ctx, NC_MOUSE_DRAG);
- ctx_set_renderer (ctx, ctxctx);
- ctx_set_size (ctx, width, height);
- ctxctx->flush = (void(*)(void *))ctx_ctx_flush;
- ctxctx->free = (void(*)(void *))ctx_ctx_free;
- return ctx;
+ ioctl (fb->fb_fd, FBIOPAN_DISPLAY, &fb->vinfo);
}
-int ctx_ctx_consume_events (Ctx *ctx)
+inline static uint32_t
+ctx_swap_red_green2 (uint32_t orig)
{
- int ix, iy;
- CtxCtx *ctxctx = (CtxCtx*)ctx->renderer;
- const char *event = NULL;
- if (ctx_native_events)
- {
- float x = 0, y = 0;
- int b = 0;
- char event_type[128]="";
- event = ctx_native_get_event (ctx, 1000/120);
-#if 0
- if(event){
- FILE *file = fopen ("/tmp/log", "a");
- fprintf (file, "[%s]\n", event);
- fclose (file);
- }
-#endif
- if (event)
- {
- sscanf (event, "%s %f %f %i", event_type, &x, &y, &b);
- if (!strcmp (event_type, "idle"))
+ uint32_t green_alpha = (orig & 0xff00ff00);
+ uint32_t red_blue = (orig & 0x00ff00ff);
+ uint32_t red = red_blue << 16;
+ uint32_t blue = red_blue >> 16;
+ return green_alpha | red | blue;
+}
+
+static int fb_cursor_drawn = 0;
+static int fb_cursor_drawn_x = 0;
+static int fb_cursor_drawn_y = 0;
+static CtxCursor fb_cursor_drawn_shape = 0;
+
+
+#define CTX_FB_HIDE_CURSOR_FRAMES 200
+
+static int fb_cursor_same_pos = CTX_FB_HIDE_CURSOR_FRAMES;
+
+static inline int ctx_is_in_cursor (int x, int y, int size, CtxCursor shape)
+{
+ switch (shape)
+ {
+ case CTX_CURSOR_ARROW:
+ if (x > ((size * 4)-y*4)) return 0;
+ if (x < y && x > y / 16)
+ return 1;
+ return 0;
+
+ case CTX_CURSOR_RESIZE_SE:
+ case CTX_CURSOR_RESIZE_NW:
+ case CTX_CURSOR_RESIZE_SW:
+ case CTX_CURSOR_RESIZE_NE:
{
+ float theta = -45.0/180 * M_PI;
+ float cos_theta;
+ float sin_theta;
+
+ if ((shape == CTX_CURSOR_RESIZE_SW) ||
+ (shape == CTX_CURSOR_RESIZE_NE))
+ {
+ theta = -theta;
+ cos_theta = cos (theta);
+ sin_theta = sin (theta);
+ }
+ else
+ {
+ cos_theta = cos (theta);
+ sin_theta = sin (theta);
+ }
+ int rot_x = x * cos_theta - y * sin_theta;
+ int rot_y = y * cos_theta + x * sin_theta;
+ x = rot_x;
+ y = rot_y;
}
- else if (!strcmp (event_type, "mouse-press"))
+ /*FALLTHROUGH*/
+ case CTX_CURSOR_RESIZE_W:
+ case CTX_CURSOR_RESIZE_E:
+ case CTX_CURSOR_RESIZE_ALL:
+ if (abs (x) < size/2 && abs (y) < size/2)
{
- ctx_pointer_press (ctx, x, y, b, 0);
+ if (abs(y) < size/10)
+ {
+ return 1;
+ }
}
- else if (!strcmp (event_type, "mouse-drag")||
- !strcmp (event_type, "mouse-motion"))
+ if ((abs (x) - size/ (shape == CTX_CURSOR_RESIZE_ALL?2:2.7)) >= 0)
{
- ctx_pointer_motion (ctx, x, y, b, 0);
+ if (abs(y) < (size/2.8)-(abs(x) - (size/2)))
+ return 1;
}
- else if (!strcmp (event_type, "mouse-release"))
+ if (shape != CTX_CURSOR_RESIZE_ALL)
+ break;
+ /* FALLTHROUGH */
+ case CTX_CURSOR_RESIZE_S:
+ case CTX_CURSOR_RESIZE_N:
+ if (abs (y) < size/2 && abs (x) < size/2)
{
- ctx_pointer_release (ctx, x, y, b, 0);
+ if (abs(x) < size/10)
+ {
+ return 1;
+ }
}
- else if (!strcmp (event_type, "message"))
- {
- ctx_incoming_message (ctx, event + strlen ("message"), 0);
- } else if (!strcmp (event, "size-changed"))
+ if ((abs (y) - size/ (shape == CTX_CURSOR_RESIZE_ALL?2:2.7)) >= 0)
{
- fprintf (stdout, "\e[H\e[2J\e[?25l");
- ctxctx->cols = ctx_terminal_cols ();
- ctxctx->rows = ctx_terminal_rows ();
- ctxctx->width = ctx_terminal_width ();
- ctxctx->height = ctx_terminal_height ();
- ctx_set_size (ctx, ctxctx->width, ctxctx->height);
-
- if (prev_frame_contents)
- free (prev_frame_contents);
- prev_frame_contents = NULL;
- prev_frame_len = 0;
- ctx_set_dirty (ctx, 1);
- //ctx_key_press (ctx, 0, "size-changed", 0);
+ if (abs(x) < (size/2.8)-(abs(y) - (size/2)))
+ return 1;
}
- else
+ break;
+#if 0
+ case CTX_CURSOR_RESIZE_ALL:
+ if (abs (x) < size/2 && abs (y) < size/2)
{
- ctx_key_press (ctx, 0, event, 0);
- }
+ if (abs (x) < size/10 || abs(y) < size/10)
+ return 1;
}
- }
- else
- {
- float x, y;
- event = ctx_nct_get_event (ctx, 20, &ix, &iy);
+ break;
+#endif
+ default:
+ return (x ^ y) & 1;
+ }
+ return 0;
+}
- x = (ix - 1.0 + 0.5) / ctxctx->cols * ctx->events.width;
- y = (iy - 1.0) / ctxctx->rows * ctx->events.height;
+static void ctx_fb_undraw_cursor (CtxFb *fb)
+{
+ CtxTiled *tiled = (void*)fb;
+ int cursor_size = ctx_height (tiled->ctx) / 28;
- if (!strcmp (event, "mouse-press"))
- {
- ctx_pointer_press (ctx, x, y, 0, 0);
- ctxctx->was_down = 1;
- } else if (!strcmp (event, "mouse-release"))
- {
- ctx_pointer_release (ctx, x, y, 0, 0);
- } else if (!strcmp (event, "mouse-motion"))
+ if (fb_cursor_drawn)
+ {
+ int no = 0;
+ int startx = -cursor_size;
+ int starty = -cursor_size;
+ if (fb_cursor_drawn_shape == CTX_CURSOR_ARROW)
+ startx = starty = 0;
+
+ for (int y = starty; y < cursor_size; y++)
+ for (int x = startx; x < cursor_size; x++, no+=4)
{
- //nct_set_cursor_pos (backend->term, ix, iy);
- //nct_flush (backend->term);
- if (ctxctx->was_down)
+ if (x + fb_cursor_drawn_x < tiled->width && y + fb_cursor_drawn_y < tiled->height)
{
- ctx_pointer_release (ctx, x, y, 0, 0);
- ctxctx->was_down = 0;
+ if (ctx_is_in_cursor (x, y, cursor_size, fb_cursor_drawn_shape))
+ {
+ int o = ((fb_cursor_drawn_y + y) * tiled->width + (fb_cursor_drawn_x + x)) * 4;
+ fb->fb[o+0]^=0x88;
+ fb->fb[o+1]^=0x88;
+ fb->fb[o+2]^=0x88;
+ }
}
- ctx_pointer_motion (ctx, x, y, 0, 0);
- } else if (!strcmp (event, "mouse-drag"))
- {
- ctx_pointer_motion (ctx, x, y, 0, 0);
- } else if (!strcmp (event, "size-changed"))
- {
- fprintf (stdout, "\e[H\e[2J\e[?25l");
- ctxctx->cols = ctx_terminal_cols ();
- ctxctx->rows = ctx_terminal_rows ();
- ctxctx->width = ctx_terminal_width ();
- ctxctx->height = ctx_terminal_height ();
- ctx_set_size (ctx, ctxctx->width, ctxctx->height);
-
- if (prev_frame_contents)
- free (prev_frame_contents);
- prev_frame_contents = NULL;
- prev_frame_len = 0;
- ctx_set_dirty (ctx, 1);
- //ctx_key_press (ctx, 0, "size-changed", 0);
- }
- else
- {
- if (!strcmp (event, "esc"))
- ctx_key_press (ctx, 0, "escape", 0);
- else if (!strcmp (event, "space"))
- ctx_key_press (ctx, 0, "space", 0);
- else if (!strcmp (event, "enter"))
- ctx_key_press (ctx, 0, "\n", 0);
- else if (!strcmp (event, "return"))
- ctx_key_press (ctx, 0, "\n", 0);
- else
- ctx_key_press (ctx, 0, event, 0);
}
+
+ fb_cursor_drawn = 0;
+ }
+}
+
+static void ctx_fb_draw_cursor (CtxFb *fb)
+{
+ CtxTiled *tiled = (void*)fb;
+ int cursor_x = ctx_pointer_x (tiled->ctx);
+ int cursor_y = ctx_pointer_y (tiled->ctx);
+ int cursor_size = ctx_height (tiled->ctx) / 28;
+ CtxCursor cursor_shape = tiled->ctx->cursor;
+ int no = 0;
+
+ if (cursor_x == fb_cursor_drawn_x &&
+ cursor_y == fb_cursor_drawn_y &&
+ cursor_shape == fb_cursor_drawn_shape)
+ fb_cursor_same_pos ++;
+ else
+ fb_cursor_same_pos = 0;
+
+ if (fb_cursor_same_pos >= CTX_FB_HIDE_CURSOR_FRAMES)
+ {
+ if (fb_cursor_drawn)
+ ctx_fb_undraw_cursor (fb);
+ return;
}
- return 1;
-}
+ /* no need to flicker when stationary, motion flicker can also be removed
+ * by combining the previous and next position masks when a motion has
+ * occured..
+ */
+ if (fb_cursor_same_pos && fb_cursor_drawn)
+ return;
-#endif
+ ctx_fb_undraw_cursor (fb);
-#if CTX_EVENTS
+ no = 0;
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <signal.h>
+ int startx = -cursor_size;
+ int starty = -cursor_size;
-#if CTX_FB
- #include <linux/fb.h>
- #include <linux/vt.h>
- #include <linux/kd.h>
- #include <sys/mman.h>
- #include <threads.h>
- #include <libdrm/drm.h>
- #include <libdrm/drm_mode.h>
+ if (cursor_shape == CTX_CURSOR_ARROW)
+ startx = starty = 0;
-typedef struct _EvSource EvSource;
+ for (int y = starty; y < cursor_size; y++)
+ for (int x = startx; x < cursor_size; x++, no+=4)
+ {
+ if (x + cursor_x < tiled->width && y + cursor_y < tiled->height)
+ {
+ if (ctx_is_in_cursor (x, y, cursor_size, cursor_shape))
+ {
+ int o = ((cursor_y + y) * tiled->width + (cursor_x + x)) * 4;
+ fb->fb[o+0]^=0x88;
+ fb->fb[o+1]^=0x88;
+ fb->fb[o+2]^=0x88;
+ }
+ }
+ }
+ fb_cursor_drawn = 1;
+ fb_cursor_drawn_x = cursor_x;
+ fb_cursor_drawn_y = cursor_y;
+ fb_cursor_drawn_shape = cursor_shape;
+}
-struct _EvSource
+static void ctx_fb_show_frame (CtxFb *fb, int block)
{
- void *priv; /* private storage */
+ CtxTiled *tiled = (void*)fb;
+ if (tiled->shown_frame == tiled->render_frame)
+ {
+ if (block == 0) // consume event call
+ {
+ ctx_fb_draw_cursor (fb);
+ ctx_fb_flip (fb);
+ }
+ return;
+ }
- /* returns non 0 if there is events waiting */
- int (*has_event) (EvSource *ev_source);
+ if (block)
+ {
+ int count = 0;
+ while (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
+ {
+ usleep (500);
+ count ++;
+ if (count > 2000)
+ {
+ tiled->shown_frame = tiled->render_frame;
+ return;
+ }
+ }
+ }
+ else
+ {
+ if (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
+ return;
+ }
- /* get an event, the returned event should be freed by the caller */
- char *(*get_event) (EvSource *ev_source);
+ if (fb->vt_active)
+ {
+ int pre_skip = tiled->min_row * tiled->height/CTX_HASH_ROWS * tiled->width;
+ int post_skip = (CTX_HASH_ROWS-tiled->max_row-1) * tiled->height/CTX_HASH_ROWS * tiled->width;
- /* destroy/unref this instance */
- void (*destroy) (EvSource *ev_source);
+ int rows = ((tiled->width * tiled->height) - pre_skip - post_skip)/tiled->width;
- /* get the underlying fd, useful for using select on */
- int (*get_fd) (EvSource *ev_source);
+ int col_pre_skip = tiled->min_col * tiled->width/CTX_HASH_COLS;
+ int col_post_skip = (CTX_HASH_COLS-tiled->max_col-1) * tiled->width/CTX_HASH_COLS;
+#if CTX_DAMAGE_CONTROL
+ pre_skip = post_skip = col_pre_skip = col_post_skip = 0;
+#endif
+ if (pre_skip < 0) pre_skip = 0;
+ if (post_skip < 0) post_skip = 0;
- void (*set_coord) (EvSource *ev_source, double x, double y);
- /* set_coord is needed to warp relative cursors into normalized range,
- * like normal mice/trackpads/nipples - to obey edges and more.
- */
+ __u32 dummy = 0;
- /* if this returns non-0 select can be used for non-blocking.. */
-};
+ if (tiled->min_row == 100){
+ pre_skip = 0;
+ post_skip = 0;
+ // not when drm ?
+ ioctl (fb->fb_fd, FBIO_WAITFORVSYNC, &dummy);
+ ctx_fb_undraw_cursor (fb);
+ }
+ else
+ {
+ tiled->min_row = 100;
+ tiled->max_row = 0;
+ tiled->min_col = 100;
+ tiled->max_col = 0;
-typedef struct _CtxFb CtxFb;
-struct _CtxFb
-{
- void (*render) (void *fb, CtxCommand *command);
- void (*reset) (void *fb);
- void (*flush) (void *fb);
- char *(*get_clipboard) (void *ctxctx);
- void (*set_clipboard) (void *ctxctx, const char *text);
- void (*free) (void *fb);
- Ctx *ctx;
- int width;
- int height;
- int cols; // unused
- int rows; // unused
- int was_down;
- uint8_t *scratch_fb;
- Ctx *ctx_copy;
- Ctx *host[CTX_MAX_THREADS];
- CtxAntialias antialias;
- int quit;
- _Atomic int thread_quit;
- int shown_frame;
- int render_frame;
- int rendered_frame[CTX_MAX_THREADS];
- int frame;
- int min_col; // hasher cols and rows
- int min_row;
- int max_col;
- int max_row;
- uint8_t hashes[CTX_HASH_ROWS * CTX_HASH_COLS * 20];
- int8_t tile_affinity[CTX_HASH_ROWS * CTX_HASH_COLS]; // which render thread no is
- // responsible for a tile
- //
+ // not when drm ?
+ ioctl (fb->fb_fd, FBIO_WAITFORVSYNC, &dummy);
+ ctx_fb_undraw_cursor (fb);
+ switch (fb->fb_bits)
+ {
+ case 32:
+#if 1
+ {
+ uint8_t *dst = fb->fb + pre_skip * 4;
+ uint8_t *src = tiled->pixels + pre_skip * 4;
+ int pre = col_pre_skip * 4;
+ int post = col_post_skip * 4;
+ int core = tiled->width * 4 - pre - post;
+ for (int i = 0; i < rows; i++)
+ {
+ dst += pre;
+ src += pre;
+ memcpy (dst, src, core);
+ src += core;
+ dst += core;
+ dst += post;
+ src += post;
+ }
+ }
+#else
+ { int count = tiled->width * tiled->height;
+ const uint32_t *src = (void*)tiled->pixels;
+ uint32_t *dst = (void*)fb->fb;
+ count-= pre_skip;
+ src+= pre_skip;
+ dst+= pre_skip;
+ count-= post_skip;
+ while (count -- > 0)
+ {
+ dst[0] = ctx_swap_red_green2 (src[0]);
+ src++;
+ dst++;
+ }
+ }
+#endif
+ break;
+ /* XXX : note: converting a scanline (or all) to target and
+ * then doing a bulk memcpy be faster (at least with som /dev/fbs) */
+ case 24:
+ { int count = tiled->width * tiled->height;
+ const uint8_t *src = tiled->pixels;
+ uint8_t *dst = fb->fb;
+ count-= pre_skip;
+ src+= pre_skip * 4;
+ dst+= pre_skip * 3;
+ count-= post_skip;
+ while (count -- > 0)
+ {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst+=3;
+ src+=4;
+ }
+ }
+ break;
+ case 16:
+ { int count = tiled->width * tiled->height;
+ const uint8_t *src = tiled->pixels;
+ uint8_t *dst = fb->fb;
+ count-= post_skip;
+ count-= pre_skip;
+ src+= pre_skip * 4;
+ dst+= pre_skip * 2;
+ while (count -- > 0)
+ {
+ int big = ((src[0] >> 3)) +
+ ((src[1] >> 2)<<5) +
+ ((src[2] >> 3)<<11);
+ dst[0] = big & 255;
+ dst[1] = big >> 8;
+ dst+=2;
+ src+=4;
+ }
+ }
+ break;
+ case 15:
+ { int count = tiled->width * tiled->height;
+ const uint8_t *src = tiled->pixels;
+ uint8_t *dst = fb->fb;
+ count-= post_skip;
+ count-= pre_skip;
+ src+= pre_skip * 4;
+ dst+= pre_skip * 2;
+ while (count -- > 0)
+ {
+ int big = ((src[2] >> 3)) +
+ ((src[1] >> 2)<<5) +
+ ((src[0] >> 3)<<10);
+ dst[0] = big & 255;
+ dst[1] = big >> 8;
+ dst+=2;
+ src+=4;
+ }
+ }
+ break;
+ case 8:
+ { int count = tiled->width * tiled->height;
+ const uint8_t *src = tiled->pixels;
+ uint8_t *dst = fb->fb;
+ count-= post_skip;
+ count-= pre_skip;
+ src+= pre_skip * 4;
+ dst+= pre_skip;
+ while (count -- > 0)
+ {
+ dst[0] = ((src[0] >> 5)) +
+ ((src[1] >> 5)<<3) +
+ ((src[2] >> 6)<<6);
+ dst+=1;
+ src+=4;
+ }
+ }
+ break;
+ }
+ }
+ fb_cursor_drawn = 0;
+ ctx_fb_draw_cursor (fb);
+ ctx_fb_flip (fb);
+ tiled->shown_frame = tiled->render_frame;
+ }
+}
+#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)
- int pointer_down[3];
- int key_balance;
- int key_repeat;
- int lctrl;
- int lalt;
- int rctrl;
- uint8_t *fb;
- int fb_fd;
- char *fb_path;
- int fb_bits;
- int fb_bpp;
- int fb_mapped_size;
- struct fb_var_screeninfo vinfo;
- struct fb_fix_screeninfo finfo;
- int vt;
- int tty;
- int vt_active;
- EvSource *evsource[4];
- int evsource_count;
- int is_drm;
- cnd_t cond;
- mtx_t mtx;
- struct drm_mode_crtc crtc;
+static int mice_has_event ();
+static char *mice_get_event ();
+static void mice_destroy ();
+static int mice_get_fd (EvSource *ev_source);
+static void mice_set_coord (EvSource *ev_source, double x, double y);
+
+static EvSource ev_src_mice = {
+ NULL,
+ (void*)mice_has_event,
+ (void*)mice_get_event,
+ (void*)mice_destroy,
+ mice_get_fd,
+ mice_set_coord
};
-static char *ctx_fb_clipboard = NULL;
-static void ctx_fb_set_clipboard (CtxFb *fb, const char *text)
+typedef struct Mice
{
- if (ctx_fb_clipboard)
- free (ctx_fb_clipboard);
- ctx_fb_clipboard = NULL;
- if (text)
- {
- ctx_fb_clipboard = strdup (text);
- }
-}
+ int fd;
+ double x;
+ double y;
+ int button;
+ int prev_state;
+} Mice;
-static char *ctx_fb_get_clipboard (CtxFb *sdl)
+Mice *_mrg_evsrc_coord = NULL;
+
+void _mmm_get_coords (Ctx *ctx, double *x, double *y)
{
- if (ctx_fb_clipboard) return strdup (ctx_fb_clipboard);
- return strdup ("");
+ if (!_mrg_evsrc_coord)
+ return;
+ if (x)
+ *x = _mrg_evsrc_coord->x;
+ if (y)
+ *y = _mrg_evsrc_coord->y;
}
-#if UINTPTR_MAX == 0xffFFffFF
- #define fbdrmuint_t uint32_t
-#elif UINTPTR_MAX == 0xffFFffFFffFFffFF
- #define fbdrmuint_t uint64_t
-#endif
+static Mice mice;
+static Mice* mrg_mice_this = &mice;
-void *ctx_fbdrm_new (CtxFb *fb, int *width, int *height)
+static int mmm_evsource_mice_init ()
{
- int got_master = 0;
- fb->fb_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
- if (!fb->fb_fd)
- return NULL;
- static fbdrmuint_t res_conn_buf[20]={0}; // this is static since its contents
- // are used by the flip callback
- fbdrmuint_t res_fb_buf[20]={0};
- fbdrmuint_t res_crtc_buf[20]={0};
- fbdrmuint_t res_enc_buf[20]={0};
- struct drm_mode_card_res res={0};
-
- if (ioctl(fb->fb_fd, DRM_IOCTL_SET_MASTER, 0))
- goto cleanup;
- got_master = 1;
+ unsigned char reset[]={0xff};
+ /* need to detect which event */
- if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
- goto cleanup;
- res.fb_id_ptr=(fbdrmuint_t)res_fb_buf;
- res.crtc_id_ptr=(fbdrmuint_t)res_crtc_buf;
- res.connector_id_ptr=(fbdrmuint_t)res_conn_buf;
- res.encoder_id_ptr=(fbdrmuint_t)res_enc_buf;
- if(ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
- goto cleanup;
+ mrg_mice_this->prev_state = 0;
+ mrg_mice_this->fd = open ("/dev/input/mice", O_RDONLY | O_NONBLOCK);
+ if (mrg_mice_this->fd == -1)
+ {
+ fprintf (stderr, "error opening /dev/input/mice device, maybe add user to input group if such group
exist, or otherwise make the rights be satisfied.\n");
+ return -1;
+ }
+ if (write (mrg_mice_this->fd, reset, 1) == -1)
+ {
+ // might happen if we're a regular user with only read permission
+ }
+ _mrg_evsrc_coord = mrg_mice_this;
+ return 0;
+}
+static void mice_destroy ()
+{
+ if (mrg_mice_this->fd != -1)
+ close (mrg_mice_this->fd);
+}
- unsigned int i;
- for (i=0;i<res.count_connectors;i++)
- {
- struct drm_mode_modeinfo conn_mode_buf[20]={0};
- fbdrmuint_t conn_prop_buf[20]={0},
- conn_propval_buf[20]={0},
- conn_enc_buf[20]={0};
+static int mice_has_event ()
+{
+ struct timeval tv;
+ int retval;
- struct drm_mode_get_connector conn={0};
+ if (mrg_mice_this->fd == -1)
+ return 0;
- conn.connector_id=res_conn_buf[i];
+ fd_set rfds;
+ FD_ZERO (&rfds);
+ FD_SET(mrg_mice_this->fd, &rfds);
+ tv.tv_sec = 0; tv.tv_usec = 0;
+ retval = select (mrg_mice_this->fd+1, &rfds, NULL, NULL, &tv);
+ if (retval == 1)
+ return FD_ISSET (mrg_mice_this->fd, &rfds);
+ return 0;
+}
- if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
- goto cleanup;
+static char *mice_get_event ()
+{
+ const char *ret = "mouse-motion";
+ double relx, rely;
+ signed char buf[3];
+ int n_read = 0;
+ CtxFb *fb = ev_src_mice.priv;
+ CtxTiled *tiled = (void*)fb;
+ n_read = read (mrg_mice_this->fd, buf, 3);
+ if (n_read == 0)
+ return strdup ("");
+ relx = buf[1];
+ rely = -buf[2];
- conn.modes_ptr=(fbdrmuint_t)conn_mode_buf;
- conn.props_ptr=(fbdrmuint_t)conn_prop_buf;
- conn.prop_values_ptr=(fbdrmuint_t)conn_propval_buf;
- conn.encoders_ptr=(fbdrmuint_t)conn_enc_buf;
+ if (relx < 0)
+ {
+ if (relx > -6)
+ relx = - relx*relx;
+ else
+ relx = -36;
+ }
+ else
+ {
+ if (relx < 6)
+ relx = relx*relx;
+ else
+ relx = 36;
+ }
- if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
- goto cleanup;
+ if (rely < 0)
+ {
+ if (rely > -6)
+ rely = - rely*rely;
+ else
+ rely = -36;
+ }
+ else
+ {
+ if (rely < 6)
+ rely = rely*rely;
+ else
+ rely = 36;
+ }
- //Check if the connector is OK to use (connected to something)
- if (conn.count_encoders<1 || conn.count_modes<1 || !conn.encoder_id || !conn.connection)
- continue;
+ mrg_mice_this->x += relx;
+ mrg_mice_this->y += rely;
-//------------------------------------------------------------------------------
-//Creating a dumb buffer
-//------------------------------------------------------------------------------
- struct drm_mode_create_dumb create_dumb={0};
- struct drm_mode_map_dumb map_dumb={0};
- struct drm_mode_fb_cmd cmd_dumb={0};
- create_dumb.width = conn_mode_buf[0].hdisplay;
- create_dumb.height = conn_mode_buf[0].vdisplay;
- create_dumb.bpp = 32;
- create_dumb.flags = 0;
- create_dumb.pitch = 0;
- create_dumb.size = 0;
- create_dumb.handle = 0;
- if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) ||
- !create_dumb.handle)
- goto cleanup;
+ if (mrg_mice_this->x < 0)
+ mrg_mice_this->x = 0;
+ if (mrg_mice_this->y < 0)
+ mrg_mice_this->y = 0;
+ if (mrg_mice_this->x >= tiled->width)
+ mrg_mice_this->x = tiled->width -1;
+ if (mrg_mice_this->y >= tiled->height)
+ mrg_mice_this->y = tiled->height -1;
+ int button = 0;
+
+ if ((mrg_mice_this->prev_state & 1) != (buf[0] & 1))
+ {
+ if (buf[0] & 1)
+ {
+ ret = "mouse-press";
+ }
+ else
+ {
+ ret = "mouse-release";
+ }
+ button = 1;
+ }
+ else if (buf[0] & 1)
+ {
+ ret = "mouse-drag";
+ button = 1;
+ }
- cmd_dumb.width =create_dumb.width;
- cmd_dumb.height=create_dumb.height;
- cmd_dumb.bpp =create_dumb.bpp;
- cmd_dumb.pitch =create_dumb.pitch;
- cmd_dumb.depth =24;
- cmd_dumb.handle=create_dumb.handle;
- if (ioctl(fb->fb_fd,DRM_IOCTL_MODE_ADDFB,&cmd_dumb))
- goto cleanup;
+ if (!button)
+ {
+ if ((mrg_mice_this->prev_state & 2) != (buf[0] & 2))
+ {
+ if (buf[0] & 2)
+ {
+ ret = "mouse-press";
+ }
+ else
+ {
+ ret = "mouse-release";
+ }
+ button = 3;
+ }
+ else if (buf[0] & 2)
+ {
+ ret = "mouse-drag";
+ button = 3;
+ }
+ }
- map_dumb.handle=create_dumb.handle;
- if (ioctl(fb->fb_fd,DRM_IOCTL_MODE_MAP_DUMB,&map_dumb))
- goto cleanup;
+ if (!button)
+ {
+ if ((mrg_mice_this->prev_state & 4) != (buf[0] & 4))
+ {
+ if (buf[0] & 4)
+ {
+ ret = "mouse-press";
+ }
+ else
+ {
+ ret = "mouse-release";
+ }
+ button = 2;
+ }
+ else if (buf[0] & 4)
+ {
+ ret = "mouse-drag";
+ button = 2;
+ }
+ }
- void *base = mmap(0, create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED,
- fb->fb_fd, map_dumb.offset);
- if (!base)
- {
- goto cleanup;
- }
- *width = create_dumb.width;
- *height = create_dumb.height;
+ mrg_mice_this->prev_state = buf[0];
- struct drm_mode_get_encoder enc={0};
- enc.encoder_id=conn.encoder_id;
- if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETENCODER, &enc))
- goto cleanup;
+ //if (!is_active (ev_src_mice.priv))
+ // return NULL;
- fb->crtc.crtc_id=enc.crtc_id;
- if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCRTC, &fb->crtc))
- goto cleanup;
+ {
+ char *r = malloc (64);
+ sprintf (r, "%s %.0f %.0f %i", ret, mrg_mice_this->x, mrg_mice_this->y, button);
+ return r;
+ }
- fb->crtc.fb_id=cmd_dumb.fb_id;
- fb->crtc.set_connectors_ptr=(fbdrmuint_t)&res_conn_buf[i];
- fb->crtc.count_connectors=1;
- fb->crtc.mode=conn_mode_buf[0];
- fb->crtc.mode_valid=1;
- return base;
- }
-cleanup:
- if (got_master)
- ioctl(fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
- fb->fb_fd = 0;
- return NULL;
+ return NULL;
}
-void ctx_fbdrm_flip (CtxFb *fb)
+static int mice_get_fd (EvSource *ev_source)
{
- if (!fb->fb_fd)
- return;
- ioctl(fb->fb_fd, DRM_IOCTL_MODE_SETCRTC, &fb->crtc);
+ return mrg_mice_this->fd;
}
-void ctx_fbdrm_close (CtxFb *fb)
+static void mice_set_coord (EvSource *ev_source, double x, double y)
{
- if (!fb->fb_fd)
- return;
- ioctl(fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
- close (fb->fb_fd);
- fb->fb_fd = 0;
+ mrg_mice_this->x = x;
+ mrg_mice_this->y = y;
}
-static void ctx_fb_flip (CtxFb *fb)
+EvSource *evsource_mice_new (void)
{
- if (fb->is_drm)
- ctx_fbdrm_flip (fb);
- else
- ioctl (fb->fb_fd, FBIOPAN_DISPLAY, &fb->vinfo);
+ if (mmm_evsource_mice_init () == 0)
+ {
+ mrg_mice_this->x = 0;
+ mrg_mice_this->y = 0;
+ return &ev_src_mice;
+ }
+ return NULL;
}
-static inline int
-fb_render_threads_done (CtxFb *fb)
-{
- int sum = 0;
- for (int i = 0; i < _ctx_max_threads; i++)
- {
- if (fb->rendered_frame[i] == fb->render_frame)
- sum ++;
- }
- return sum;
-}
+static int evsource_kb_has_event (void);
+static char *evsource_kb_get_event (void);
+static void evsource_kb_destroy (int sign);
+static int evsource_kb_get_fd (void);
-inline static uint32_t
-ctx_swap_red_green2 (uint32_t orig)
+/* kept out of struct to be reachable by atexit */
+static EvSource ev_src_kb = {
+ NULL,
+ (void*)evsource_kb_has_event,
+ (void*)evsource_kb_get_event,
+ (void*)evsource_kb_destroy,
+ (void*)evsource_kb_get_fd,
+ NULL
+};
+
+static struct termios orig_attr;
+
+int is_active (void *host)
{
- uint32_t green_alpha = (orig & 0xff00ff00);
- uint32_t red_blue = (orig & 0x00ff00ff);
- uint32_t red = red_blue << 16;
- uint32_t blue = red_blue >> 16;
- return green_alpha | red | blue;
+ return 1;
}
+static void real_evsource_kb_destroy (int sign)
+{
+ static int done = 0;
-static int fb_cursor_drawn = 0;
-static int fb_cursor_drawn_x = 0;
-static int fb_cursor_drawn_y = 0;
-static CtxCursor fb_cursor_drawn_shape = CTX_CURSOR_ARROW;
+ if (sign == 0)
+ return;
+ if (done)
+ return;
+ done = 1;
-#define CTX_FB_HIDE_CURSOR_FRAMES 200
+ switch (sign)
+ {
+ case -11:break; /* will be called from atexit with sign==-11 */
+ case SIGSEGV: break;//fprintf (stderr, " SIGSEGV\n");break;
+ case SIGABRT: fprintf (stderr, " SIGABRT\n");break;
+ case SIGBUS: fprintf (stderr, " SIGBUS\n");break;
+ case SIGKILL: fprintf (stderr, " SIGKILL\n");break;
+ case SIGINT: fprintf (stderr, " SIGINT\n");break;
+ case SIGTERM: fprintf (stderr, " SIGTERM\n");break;
+ case SIGQUIT: fprintf (stderr, " SIGQUIT\n");break;
+ default: fprintf (stderr, "sign: %i\n", sign);
+ fprintf (stderr, "%i %i %i %i %i %i %i\n", SIGSEGV, SIGABRT, SIGBUS, SIGKILL, SIGINT, SIGTERM,
SIGQUIT);
+ }
+ tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
+ //fprintf (stderr, "evsource kb destroy\n");
+}
-static int fb_cursor_same_pos = CTX_FB_HIDE_CURSOR_FRAMES;
+static void evsource_kb_destroy (int sign)
+{
+ real_evsource_kb_destroy (-11);
+}
-static inline int ctx_is_in_cursor (int x, int y, int size, CtxCursor shape)
+static int evsource_kb_init ()
{
- switch (shape)
- {
- case CTX_CURSOR_ARROW:
- if (x > ((size * 4)-y*4)) return 0;
- if (x < y && x > y / 16)
- return 1;
- return 0;
+// ioctl(STDIN_FILENO, KDSKBMODE, K_RAW);
+ atexit ((void*) real_evsource_kb_destroy);
+ signal (SIGSEGV, (void*) real_evsource_kb_destroy);
+ signal (SIGABRT, (void*) real_evsource_kb_destroy);
+ signal (SIGBUS, (void*) real_evsource_kb_destroy);
+ signal (SIGKILL, (void*) real_evsource_kb_destroy);
+ signal (SIGINT, (void*) real_evsource_kb_destroy);
+ signal (SIGTERM, (void*) real_evsource_kb_destroy);
+ signal (SIGQUIT, (void*) real_evsource_kb_destroy);
- case CTX_CURSOR_RESIZE_SE:
- case CTX_CURSOR_RESIZE_NW:
- case CTX_CURSOR_RESIZE_SW:
- case CTX_CURSOR_RESIZE_NE:
- {
- float theta = -45.0/180 * M_PI;
- float cos_theta;
- float sin_theta;
+ struct termios raw;
+ if (tcgetattr (STDIN_FILENO, &orig_attr) == -1)
+ {
+ fprintf (stderr, "error initializing keyboard\n");
+ return -1;
+ }
+ raw = orig_attr;
+
+ cfmakeraw (&raw);
+
+ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
+ if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
+ return 0; // XXX? return other value?
- if ((shape == CTX_CURSOR_RESIZE_SW) ||
- (shape == CTX_CURSOR_RESIZE_NE))
- {
- theta = -theta;
- cos_theta = cos (theta);
- sin_theta = sin (theta);
- }
- else
- {
- //cos_theta = -0.707106781186548;
- cos_theta = cos (theta);
- sin_theta = sin (theta);
- }
- int rot_x = x * cos_theta - y * sin_theta;
- int rot_y = y * cos_theta + x * sin_theta;
- x = rot_x;
- y = rot_y;
- }
- /*FALLTHROUGH*/
- case CTX_CURSOR_RESIZE_W:
- case CTX_CURSOR_RESIZE_E:
- case CTX_CURSOR_RESIZE_ALL:
- if (abs (x) < size/2 && abs (y) < size/2)
- {
- if (abs(y) < size/10)
- {
- return 1;
- }
- }
- if ((abs (x) - size/ (shape == CTX_CURSOR_RESIZE_ALL?2:2.7)) >= 0)
- {
- if (abs(y) < (size/2.8)-(abs(x) - (size/2)))
- return 1;
- }
- if (shape != CTX_CURSOR_RESIZE_ALL)
- break;
- /* FALLTHROUGH */
- case CTX_CURSOR_RESIZE_S:
- case CTX_CURSOR_RESIZE_N:
- if (abs (y) < size/2 && abs (x) < size/2)
- {
- if (abs(x) < size/10)
- {
- return 1;
- }
- }
- if ((abs (y) - size/ (shape == CTX_CURSOR_RESIZE_ALL?2:2.7)) >= 0)
- {
- if (abs(x) < (size/2.8)-(abs(y) - (size/2)))
- return 1;
- }
- break;
-#if 0
- case CTX_CURSOR_RESIZE_ALL:
- if (abs (x) < size/2 && abs (y) < size/2)
- {
- if (abs (x) < size/10 || abs(y) < size/10)
- return 1;
- }
- break;
-#endif
- default:
- return (x ^ y) & 1;
- }
return 0;
}
+static int evsource_kb_has_event (void)
+{
+ struct timeval tv;
+ int retval;
-static void ctx_fb_undraw_cursor (CtxFb *fb)
- {
- int cursor_size = ctx_height (fb->ctx) / 28;
-
- if (fb_cursor_drawn)
- {
- int no = 0;
- for (int y = -cursor_size; y < cursor_size; y++)
- for (int x = -cursor_size; x < cursor_size; x++, no+=4)
- {
- if (x + fb_cursor_drawn_x < fb->width && y + fb_cursor_drawn_y < fb->height)
- {
- if (ctx_is_in_cursor (x, y, cursor_size, fb_cursor_drawn_shape))
- {
- int o = ((fb_cursor_drawn_y + y) * fb->width + (fb_cursor_drawn_x + x)) * 4;
- fb->fb[o+0]^=0x88;
- fb->fb[o+1]^=0x88;
- fb->fb[o+2]^=0x88;
- }
- }
- }
- fb_cursor_drawn = 0;
- }
+ fd_set rfds;
+ FD_ZERO (&rfds);
+ FD_SET(STDIN_FILENO, &rfds);
+ tv.tv_sec = 0; tv.tv_usec = 0;
+ retval = select (STDIN_FILENO+1, &rfds, NULL, NULL, &tv);
+ return retval == 1;
}
-static void ctx_fb_draw_cursor (CtxFb *fb)
- {
- int cursor_x = ctx_pointer_x (fb->ctx);
- int cursor_y = ctx_pointer_y (fb->ctx);
- int cursor_size = ctx_height (fb->ctx) / 28;
- CtxCursor cursor_shape = fb->ctx->cursor;
- int no = 0;
+/* note that a nick can have multiple occurences, the labels
+ * should be kept the same for all occurences of a combination.
+ *
+ * this table is taken from nchanterm.
+ */
+typedef struct MmmKeyCode {
+ char *nick; /* programmers name for key */
+ char sequence[10]; /* terminal sequence */
+} MmmKeyCode;
+static const MmmKeyCode ufb_keycodes[]={
+ {"up", "\e[A"},
+ {"down", "\e[B"},
+ {"right", "\e[C"},
+ {"left", "\e[D"},
- if (cursor_x == fb_cursor_drawn_x &&
- cursor_y == fb_cursor_drawn_y &&
- cursor_shape == fb_cursor_drawn_shape)
- fb_cursor_same_pos ++;
- else
- fb_cursor_same_pos = 0;
+ {"shift-up", "\e[1;2A"},
+ {"shift-down", "\e[1;2B"},
+ {"shift-right", "\e[1;2C"},
+ {"shift-left", "\e[1;2D"},
- if (fb_cursor_same_pos >= CTX_FB_HIDE_CURSOR_FRAMES)
- {
- if (fb_cursor_drawn)
- ctx_fb_undraw_cursor (fb);
- return;
- }
+ {"alt-up", "\e[1;3A"},
+ {"alt-down", "\e[1;3B"},
+ {"alt-right", "\e[1;3C"},
+ {"alt-left", "\e[1;3D"},
+ {"alt-shift-up", "\e[1;4A"},
+ {"alt-shift-down", "\e[1;4B"},
+ {"alt-shift-right", "\e[1;4C"},
+ {"alt-shift-left", "\e[1;4D"},
- /* no need to flicker when stationary, motion flicker can also be removed
- * by combining the previous and next position masks when a motion has
- * occured..
- */
- if (fb_cursor_same_pos && fb_cursor_drawn)
- return;
+ {"control-up", "\e[1;5A"},
+ {"control-down", "\e[1;5B"},
+ {"control-right", "\e[1;5C"},
+ {"control-left", "\e[1;5D"},
- ctx_fb_undraw_cursor (fb);
+ /* putty */
+ {"control-up", "\eOA"},
+ {"control-down", "\eOB"},
+ {"control-right", "\eOC"},
+ {"control-left", "\eOD"},
- no = 0;
- for (int y = -cursor_size; y < cursor_size; y++)
- for (int x = -cursor_size; x < cursor_size; x++, no+=4)
- {
- if (x + cursor_x < fb->width && y + cursor_y < fb->height)
- {
- if (ctx_is_in_cursor (x, y, cursor_size, cursor_shape))
- {
- int o = ((cursor_y + y) * fb->width + (cursor_x + x)) * 4;
- fb->fb[o+0]^=0x88;
- fb->fb[o+1]^=0x88;
- fb->fb[o+2]^=0x88;
- }
- }
- }
- fb_cursor_drawn = 1;
- fb_cursor_drawn_x = cursor_x;
- fb_cursor_drawn_y = cursor_y;
- fb_cursor_drawn_shape = cursor_shape;
- }
+ {"control-shift-up", "\e[1;6A"},
+ {"control-shift-down", "\e[1;6B"},
+ {"control-shift-right", "\e[1;6C"},
+ {"control-shift-left", "\e[1;6D"},
-static void ctx_fb_show_frame (CtxFb *fb, int block)
-{
- if (fb->shown_frame == fb->render_frame)
- {
- if (block == 0) // consume event call
- {
- ctx_fb_draw_cursor (fb);
- ctx_fb_flip (fb);
- }
- return;
- }
+ {"control-up", "\eOa"},
+ {"control-down", "\eOb"},
+ {"control-right", "\eOc"},
+ {"control-left", "\eOd"},
+
+ {"shift-up", "\e[a"},
+ {"shift-down", "\e[b"},
+ {"shift-right", "\e[c"},
+ {"shift-left", "\e[d"},
+
+ {"insert", "\e[2~"},
+ {"delete", "\e[3~"},
+ {"page-up", "\e[5~"},
+ {"page-down", "\e[6~"},
+ {"home", "\eOH"},
+ {"end", "\eOF"},
+ {"home", "\e[H"},
+ {"end", "\e[F"},
+ {"control-delete", "\e[3;5~"},
+ {"shift-delete", "\e[3;2~"},
+ {"control-shift-delete","\e[3;6~"},
+
+ {"F1", "\e[25~"},
+ {"F2", "\e[26~"},
+ {"F3", "\e[27~"},
+ {"F4", "\e[26~"},
+
+
+ {"F1", "\e[11~"},
+ {"F2", "\e[12~"},
+ {"F3", "\e[13~"},
+ {"F4", "\e[14~"},
+ {"F1", "\eOP"},
+ {"F2", "\eOQ"},
+ {"F3", "\eOR"},
+ {"F4", "\eOS"},
+ {"F5", "\e[15~"},
+ {"F6", "\e[16~"},
+ {"F7", "\e[17~"},
+ {"F8", "\e[18~"},
+ {"F9", "\e[19~"},
+ {"F9", "\e[20~"},
+ {"F10", "\e[21~"},
+ {"F11", "\e[22~"},
+ {"F12", "\e[23~"},
+ {"tab", {9, '\0'}},
+ {"shift-tab", {27, 9, '\0'}}, // also generated by alt-tab in linux console
+ {"alt-space", {27, ' ', '\0'}},
+ {"shift-tab", "\e[Z"},
+ {"backspace", {127, '\0'}},
+ {"space", " "},
+ {"\e", "\e"},
+ {"return", {10,0}},
+ {"return", {13,0}},
+ /* this section could be autogenerated by code */
+ {"control-a", {1,0}},
+ {"control-b", {2,0}},
+ {"control-c", {3,0}},
+ {"control-d", {4,0}},
+ {"control-e", {5,0}},
+ {"control-f", {6,0}},
+ {"control-g", {7,0}},
+ {"control-h", {8,0}}, /* backspace? */
+ {"control-i", {9,0}},
+ {"control-j", {10,0}},
+ {"control-k", {11,0}},
+ {"control-l", {12,0}},
+ {"control-n", {14,0}},
+ {"control-o", {15,0}},
+ {"control-p", {16,0}},
+ {"control-q", {17,0}},
+ {"control-r", {18,0}},
+ {"control-s", {19,0}},
+ {"control-t", {20,0}},
+ {"control-u", {21,0}},
+ {"control-v", {22,0}},
+ {"control-w", {23,0}},
+ {"control-x", {24,0}},
+ {"control-y", {25,0}},
+ {"control-z", {26,0}},
+ {"alt-`", "\e`"},
+ {"alt-0", "\e0"},
+ {"alt-1", "\e1"},
+ {"alt-2", "\e2"},
+ {"alt-3", "\e3"},
+ {"alt-4", "\e4"},
+ {"alt-5", "\e5"},
+ {"alt-6", "\e6"},
+ {"alt-7", "\e7"}, /* backspace? */
+ {"alt-8", "\e8"},
+ {"alt-9", "\e9"},
+ {"alt-+", "\e+"},
+ {"alt--", "\e-"},
+ {"alt-/", "\e/"},
+ {"alt-a", "\ea"},
+ {"alt-b", "\eb"},
+ {"alt-c", "\ec"},
+ {"alt-d", "\ed"},
+ {"alt-e", "\ee"},
+ {"alt-f", "\ef"},
+ {"alt-g", "\eg"},
+ {"alt-h", "\eh"}, /* backspace? */
+ {"alt-i", "\ei"},
+ {"alt-j", "\ej"},
+ {"alt-k", "\ek"},
+ {"alt-l", "\el"},
+ {"alt-n", "\em"},
+ {"alt-n", "\en"},
+ {"alt-o", "\eo"},
+ {"alt-p", "\ep"},
+ {"alt-q", "\eq"},
+ {"alt-r", "\er"},
+ {"alt-s", "\es"},
+ {"alt-t", "\et"},
+ {"alt-u", "\eu"},
+ {"alt-v", "\ev"},
+ {"alt-w", "\ew"},
+ {"alt-x", "\ex"},
+ {"alt-y", "\ey"},
+ {"alt-z", "\ez"},
+ /* Linux Console */
+ {"home", "\e[1~"},
+ {"end", "\e[4~"},
+ {"F1", "\e[[A"},
+ {"F2", "\e[[B"},
+ {"F3", "\e[[C"},
+ {"F4", "\e[[D"},
+ {"F5", "\e[[E"},
+ {"F6", "\e[[F"},
+ {"F7", "\e[[G"},
+ {"F8", "\e[[H"},
+ {"F9", "\e[[I"},
+ {"F10", "\e[[J"},
+ {"F11", "\e[[K"},
+ {"F12", "\e[[L"},
+ {NULL, }
+};
+static int fb_keyboard_match_keycode (const char *buf, int length, const MmmKeyCode **ret)
+{
+ int i;
+ int matches = 0;
- if (block)
- {
- int count = 0;
- while (fb_render_threads_done (fb) != _ctx_max_threads)
+ if (!strncmp (buf, "\e[M", MIN(length,3)))
{
- usleep (500);
- count ++;
- if (count > 2000)
+ if (length >= 6)
+ return 9001;
+ return 2342;
+ }
+ for (i = 0; ufb_keycodes[i].nick; i++)
+ if (!strncmp (buf, ufb_keycodes[i].sequence, length))
{
- fb->shown_frame = fb->render_frame;
- return;
+ matches ++;
+ if ((int)strlen (ufb_keycodes[i].sequence) == length && ret)
+ {
+ *ret = &ufb_keycodes[i];
+ return 1;
+ }
}
- }
- }
- else
- {
- if (fb_render_threads_done (fb) != _ctx_max_threads)
- return;
- }
-
- if (fb->vt_active)
- {
- int pre_skip = fb->min_row * fb->height/CTX_HASH_ROWS * fb->width;
- int post_skip = (CTX_HASH_ROWS-fb->max_row-1) * fb->height/CTX_HASH_ROWS * fb->width;
-
- int rows = ((fb->width * fb->height) - pre_skip - post_skip)/fb->width;
-
- int col_pre_skip = fb->min_col * fb->width/CTX_HASH_COLS;
- int col_post_skip = (CTX_HASH_COLS-fb->max_col-1) * fb->width/CTX_HASH_COLS;
-#if CTX_DAMAGE_CONTROL
- pre_skip = post_skip = col_pre_skip = col_post_skip = 0;
-#endif
-
- if (pre_skip < 0) pre_skip = 0;
- if (post_skip < 0) post_skip = 0;
-
- __u32 dummy = 0;
-
- if (fb->min_row == 100){
- pre_skip = 0;
- post_skip = 0;
- // not when drm ?
- ioctl (fb->fb_fd, FBIO_WAITFORVSYNC, &dummy);
- ctx_fb_undraw_cursor (fb);
- }
- else
- {
-
- fb->min_row = 100;
- fb->max_row = 0;
- fb->min_col = 100;
- fb->max_col = 0;
-
- // not when drm ?
- ioctl (fb->fb_fd, FBIO_WAITFORVSYNC, &dummy);
- ctx_fb_undraw_cursor (fb);
- switch (fb->fb_bits)
- {
- case 32:
-#if 1
- {
- uint8_t *dst = fb->fb + pre_skip * 4;
- uint8_t *src = fb->scratch_fb + pre_skip * 4;
- int pre = col_pre_skip * 4;
- int post = col_post_skip * 4;
- int core = fb->width * 4 - pre - post;
- for (int i = 0; i < rows; i++)
- {
- dst += pre;
- src += pre;
- memcpy (dst, src, core);
- src += core;
- dst += core;
- dst += post;
- src += post;
- }
- }
-#else
- { int count = fb->width * fb->height;
- const uint32_t *src = (void*)fb->scratch_fb;
- uint32_t *dst = (void*)fb->fb;
- count-= pre_skip;
- src+= pre_skip;
- dst+= pre_skip;
- count-= post_skip;
- while (count -- > 0)
- {
- dst[0] = ctx_swap_red_green2 (src[0]);
- src++;
- dst++;
- }
- }
-#endif
- break;
- /* XXX : note: converting a scanline (or all) to target and
- * then doing a bulk memcpy be faster (at least with som /dev/fbs) */
- case 24:
- { int count = fb->width * fb->height;
- const uint8_t *src = fb->scratch_fb;
- uint8_t *dst = fb->fb;
- count-= pre_skip;
- src+= pre_skip * 4;
- dst+= pre_skip * 3;
- count-= post_skip;
- while (count -- > 0)
- {
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- dst+=3;
- src+=4;
- }
- }
- break;
- case 16:
- { int count = fb->width * fb->height;
- const uint8_t *src = fb->scratch_fb;
- uint8_t *dst = fb->fb;
- count-= post_skip;
- count-= pre_skip;
- src+= pre_skip * 4;
- dst+= pre_skip * 2;
- while (count -- > 0)
- {
- int big = ((src[0] >> 3)) +
- ((src[1] >> 2)<<5) +
- ((src[2] >> 3)<<11);
- dst[0] = big & 255;
- dst[1] = big >> 8;
- dst+=2;
- src+=4;
- }
- }
- break;
- case 15:
- { int count = fb->width * fb->height;
- const uint8_t *src = fb->scratch_fb;
- uint8_t *dst = fb->fb;
- count-= post_skip;
- count-= pre_skip;
- src+= pre_skip * 4;
- dst+= pre_skip * 2;
- while (count -- > 0)
- {
- int big = ((src[2] >> 3)) +
- ((src[1] >> 2)<<5) +
- ((src[0] >> 3)<<10);
- dst[0] = big & 255;
- dst[1] = big >> 8;
- dst+=2;
- src+=4;
- }
- }
- break;
- case 8:
- { int count = fb->width * fb->height;
- const uint8_t *src = fb->scratch_fb;
- uint8_t *dst = fb->fb;
- count-= post_skip;
- count-= pre_skip;
- src+= pre_skip * 4;
- dst+= pre_skip;
- while (count -- > 0)
- {
- dst[0] = ((src[0] >> 5)) +
- ((src[1] >> 5)<<3) +
- ((src[2] >> 6)<<6);
- dst+=1;
- src+=4;
- }
- }
- break;
- }
- }
- fb_cursor_drawn = 0;
- ctx_fb_draw_cursor (fb);
- ctx_fb_flip (fb);
- fb->shown_frame = fb->render_frame;
- }
+ if (matches != 1 && ret)
+ *ret = NULL;
+ return matches==1?2:matches;
}
+static char *evsource_kb_get_event (void)
+{
+ unsigned char buf[20];
+ int length;
-#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)
+ for (length = 0; length < 10; length ++)
+ if (read (STDIN_FILENO, &buf[length], 1) != -1)
+ {
+ const MmmKeyCode *match = NULL;
+ if (!is_active (ev_src_kb.priv))
+ return NULL;
-static int mice_has_event ();
-static char *mice_get_event ();
-static void mice_destroy ();
-static int mice_get_fd (EvSource *ev_source);
-static void mice_set_coord (EvSource *ev_source, double x, double y);
+ /* special case ESC, so that we can use it alone in keybindings */
+ if (length == 0 && buf[0] == 27)
+ {
+ struct timeval tv;
+ fd_set rfds;
+ FD_ZERO (&rfds);
+ FD_SET (STDIN_FILENO, &rfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000 * 120;
+ if (select (STDIN_FILENO+1, &rfds, NULL, NULL, &tv) == 0)
+ return strdup ("escape");
+ }
-static EvSource ev_src_mice = {
- NULL,
- (void*)mice_has_event,
- (void*)mice_get_event,
- (void*)mice_destroy,
- mice_get_fd,
- mice_set_coord
-};
+ switch (fb_keyboard_match_keycode ((void*)buf, length + 1, &match))
+ {
+ case 1: /* unique match */
+ if (!match)
+ return NULL;
+ return strdup (match->nick);
+ break;
+ case 0: /* no matches, bail*/
+ {
+ static char ret[256]="";
+ if (length == 0 && ctx_utf8_len (buf[0])>1) /* read a
+ * single unicode
+ * utf8 character
+ */
+ {
+ int bytes = read (STDIN_FILENO, &buf[length+1], ctx_utf8_len(buf[0])-1);
+ if (bytes)
+ {
+ buf[ctx_utf8_len(buf[0])]=0;
+ strcpy (ret, (void*)buf);
+ }
+ return strdup(ret); //XXX: simplify
+ }
+ if (length == 0) /* ascii */
+ {
+ buf[1]=0;
+ strcpy (ret, (void*)buf);
+ return strdup(ret);
+ }
+ sprintf (ret, "unhandled %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c'",
+ length >=0 ? buf[0] : 0,
+ length >=0 ? buf[0]>31?buf[0]:'?' : ' ',
+ length >=1 ? buf[1] : 0,
+ length >=1 ? buf[1]>31?buf[1]:'?' : ' ',
+ length >=2 ? buf[2] : 0,
+ length >=2 ? buf[2]>31?buf[2]:'?' : ' ',
+ length >=3 ? buf[3] : 0,
+ length >=3 ? buf[3]>31?buf[3]:'?' : ' ',
+ length >=4 ? buf[4] : 0,
+ length >=4 ? buf[4]>31?buf[4]:'?' : ' ',
+ length >=5 ? buf[5] : 0,
+ length >=5 ? buf[5]>31?buf[5]:'?' : ' ',
+ length >=6 ? buf[6] : 0,
+ length >=6 ? buf[6]>31?buf[6]:'?' : ' '
+ );
+ return strdup(ret);
+ }
+ return NULL;
+ default: /* continue */
+ break;
+ }
+ }
+ else
+ return strdup("key read eek");
+ return strdup("fail");
+}
-typedef struct Mice
+static int evsource_kb_get_fd (void)
{
- int fd;
- double x;
- double y;
- int button;
- int prev_state;
-} Mice;
+ return STDIN_FILENO;
+}
-Mice *_mrg_evsrc_coord = NULL;
-void _mmm_get_coords (Ctx *ctx, double *x, double *y)
+EvSource *evsource_kb_new (void)
{
- if (!_mrg_evsrc_coord)
- return;
- if (x)
- *x = _mrg_evsrc_coord->x;
- if (y)
- *y = _mrg_evsrc_coord->y;
+ if (evsource_kb_init() == 0)
+ {
+ return &ev_src_kb;
+ }
+ return NULL;
}
-static Mice mice;
-static Mice* mrg_mice_this = &mice;
-
-static int mmm_evsource_mice_init ()
+static int event_check_pending (CtxFb *fb)
{
- unsigned char reset[]={0xff};
- /* need to detect which event */
-
- mrg_mice_this->prev_state = 0;
- mrg_mice_this->fd = open ("/dev/input/mice", O_RDONLY | O_NONBLOCK);
- if (mrg_mice_this->fd == -1)
+ CtxTiled *tiled = (void*)fb;
+ int events = 0;
+ for (int i = 0; i < fb->evsource_count; i++)
{
- fprintf (stderr, "error opening /dev/input/mice device, maybe add user to input group if such group
exist, or otherwise make the rights be satisfied.\n");
- return -1;
+ while (evsource_has_event (fb->evsource[i]))
+ {
+ char *event = evsource_get_event (fb->evsource[i]);
+ if (event)
+ {
+ if (fb->vt_active)
+ {
+ ctx_key_press (tiled->ctx, 0, event, 0); // we deliver all events as key-press, the key_press
handler disambiguates
+ events++;
+ }
+ free (event);
+ }
+ }
}
- write (mrg_mice_this->fd, reset, 1);
- _mrg_evsrc_coord = mrg_mice_this;
+ return events;
+}
+
+int ctx_fb_consume_events (Ctx *ctx)
+{
+ CtxFb *fb = (void*)ctx->renderer;
+ ctx_fb_show_frame (fb, 0);
+ event_check_pending (fb);
return 0;
}
-static void mice_destroy ()
+inline static void ctx_fb_reset (CtxFb *fb)
{
- if (mrg_mice_this->fd != -1)
- close (mrg_mice_this->fd);
+ ctx_fb_show_frame (fb, 1);
}
-static int mice_has_event ()
+inline static void ctx_fb_flush (CtxFb *fb)
{
- struct timeval tv;
- int retval;
+ ctx_tiled_flush ((CtxTiled*)fb);
+}
- if (mrg_mice_this->fd == -1)
- return 0;
+void ctx_fb_free (CtxFb *fb)
+{
+ if (fb->is_drm)
+ {
+ ctx_fbdrm_close (fb);
+ }
- fd_set rfds;
- FD_ZERO (&rfds);
- FD_SET(mrg_mice_this->fd, &rfds);
- tv.tv_sec = 0; tv.tv_usec = 0;
- retval = select (mrg_mice_this->fd+1, &rfds, NULL, NULL, &tv);
- if (retval == 1)
- return FD_ISSET (mrg_mice_this->fd, &rfds);
- return 0;
+ ioctl (0, KDSETMODE, KD_TEXT);
+ if (system("stty sane")){};
+ ctx_tiled_free ((CtxTiled*)fb);
+ //free (fb);
}
-static char *mice_get_event ()
+//static unsigned char *fb_icc = NULL;
+//static long fb_icc_length = 0;
+
+int ctx_renderer_is_fb (Ctx *ctx)
{
- const char *ret = "mouse-motion";
- double relx, rely;
- signed char buf[3];
- CtxFb *fb = ev_src_mice.priv;
- read (mrg_mice_this->fd, buf, 3);
- relx = buf[1];
- rely = -buf[2];
+ if (ctx->renderer &&
+ ctx->renderer->free == (void*)ctx_fb_free)
+ return 1;
+ return 0;
+}
- if (relx < 0)
+static CtxFb *ctx_fb = NULL;
+static void vt_switch_cb (int sig)
+{
+ CtxTiled *tiled = (void*)ctx_fb;
+ if (sig == SIGUSR1)
{
- if (relx > -6)
- relx = - relx*relx;
- else
- relx = -36;
+ if (ctx_fb->is_drm)
+ ioctl(ctx_fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
+ ioctl (0, VT_RELDISP, 1);
+ ctx_fb->vt_active = 0;
+ ioctl (0, KDSETMODE, KD_TEXT);
}
else
{
- if (relx < 6)
- relx = relx*relx;
+ ioctl (0, VT_RELDISP, VT_ACKACQ);
+ ctx_fb->vt_active = 1;
+ // queue draw
+ tiled->render_frame = ++tiled->frame;
+ ioctl (0, KDSETMODE, KD_GRAPHICS);
+ if (ctx_fb->is_drm)
+ {
+ ioctl(ctx_fb->fb_fd, DRM_IOCTL_SET_MASTER, 0);
+ ctx_fb_flip (ctx_fb);
+ }
else
- relx = 36;
+ {
+ tiled->ctx->dirty=1;
+
+ for (int row = 0; row < CTX_HASH_ROWS; row++)
+ for (int col = 0; col < CTX_HASH_COLS; col++)
+ {
+ tiled->hashes[(row * CTX_HASH_COLS + col) * 20] += 1;
+ }
+ }
}
+}
- if (rely < 0)
+Ctx *ctx_new_fb (int width, int height, int drm)
+{
+#if CTX_RASTERIZER
+ CtxFb *fb = calloc (sizeof (CtxFb), 1);
+
+ CtxTiled *tiled = (void*)fb;
+ ctx_fb = fb;
+ if (drm)
+ fb->fb = ctx_fbdrm_new (fb, &tiled->width, &tiled->height);
+ if (fb->fb)
{
- if (rely > -6)
- rely = - rely*rely;
- else
- rely = -36;
+ fb->is_drm = 1;
+ width = tiled->width;
+ height = tiled->height;
+ /*
+ we're ignoring the input width and height ,
+ maybe turn them into properties - for
+ more generic handling.
+ */
+ fb->fb_mapped_size = tiled->width * tiled->height * 4;
+ fb->fb_bits = 32;
+ fb->fb_bpp = 4;
}
else
{
- if (rely < 6)
- rely = rely*rely;
+ fb->fb_fd = open ("/dev/fb0", O_RDWR);
+ if (fb->fb_fd > 0)
+ fb->fb_path = strdup ("/dev/fb0");
+ else
+ {
+ fb->fb_fd = open ("/dev/graphics/fb0", O_RDWR);
+ if (fb->fb_fd > 0)
+ {
+ fb->fb_path = strdup ("/dev/graphics/fb0");
+ }
else
- rely = 36;
- }
-
- mrg_mice_this->x += relx;
- mrg_mice_this->y += rely;
-
- if (mrg_mice_this->x < 0)
- mrg_mice_this->x = 0;
- if (mrg_mice_this->y < 0)
- mrg_mice_this->y = 0;
- if (mrg_mice_this->x >= fb->width)
- mrg_mice_this->x = fb->width -1;
- if (mrg_mice_this->y >= fb->height)
- mrg_mice_this->y = fb->height -1;
- int button = 0;
-
- if ((mrg_mice_this->prev_state & 1) != (buf[0] & 1))
{
- if (buf[0] & 1)
- {
- ret = "mouse-press";
- }
- else
- {
- ret = "mouse-release";
- }
- button = 1;
+ free (fb);
+ return NULL;
}
- else if (buf[0] & 1)
- {
- ret = "mouse-drag";
- button = 1;
}
- if (!button)
- {
- if ((mrg_mice_this->prev_state & 2) != (buf[0] & 2))
+ if (ioctl(fb->fb_fd, FBIOGET_FSCREENINFO, &fb->finfo))
{
- if (buf[0] & 2)
- {
- ret = "mouse-press";
- }
- else
- {
- ret = "mouse-release";
- }
- button = 3;
+ fprintf (stderr, "error getting fbinfo\n");
+ close (fb->fb_fd);
+ free (fb->fb_path);
+ free (fb);
+ return NULL;
}
- else if (buf[0] & 2)
+
+ if (ioctl(fb->fb_fd, FBIOGET_VSCREENINFO, &fb->vinfo))
+ {
+ fprintf (stderr, "error getting fbinfo\n");
+ close (fb->fb_fd);
+ free (fb->fb_path);
+ free (fb);
+ return NULL;
+ }
+
+//fprintf (stderr, "%s\n", fb->fb_path);
+ width = tiled->width = fb->vinfo.xres;
+ height = tiled->height = fb->vinfo.yres;
+
+ fb->fb_bits = fb->vinfo.bits_per_pixel;
+//fprintf (stderr, "fb bits: %i\n", fb->fb_bits);
+
+ if (fb->fb_bits == 16)
+ fb->fb_bits =
+ fb->vinfo.red.length +
+ fb->vinfo.green.length +
+ fb->vinfo.blue.length;
+
+ else if (fb->fb_bits == 8)
+ {
+ unsigned short red[256], green[256], blue[256];
+ unsigned short original_red[256];
+ unsigned short original_green[256];
+ unsigned short original_blue[256];
+ struct fb_cmap cmap = {0, 256, red, green, blue, NULL};
+ struct fb_cmap original_cmap = {0, 256, original_red, original_green, original_blue, NULL};
+ int i;
+
+ /* do we really need to restore it ? */
+ if (ioctl (fb->fb_fd, FBIOPUTCMAP, &original_cmap) == -1)
{
- ret = "mouse-drag";
- button = 3;
+ fprintf (stderr, "palette initialization problem %i\n", __LINE__);
}
- }
- if (!button)
- {
- if ((mrg_mice_this->prev_state & 4) != (buf[0] & 4))
+ for (i = 0; i < 256; i++)
{
- if (buf[0] & 4)
- {
- ret = "mouse-press";
- }
- else
- {
- ret = "mouse-release";
- }
- button = 2;
+ red[i] = ((( i >> 5) & 0x7) << 5) << 8;
+ green[i] = ((( i >> 2) & 0x7) << 5) << 8;
+ blue[i] = ((( i >> 0) & 0x3) << 6) << 8;
}
- else if (buf[0] & 4)
+
+ if (ioctl (fb->fb_fd, FBIOPUTCMAP, &cmap) == -1)
{
- ret = "mouse-drag";
- button = 2;
+ fprintf (stderr, "palette initialization problem %i\n", __LINE__);
}
}
- mrg_mice_this->prev_state = buf[0];
-
- //if (!is_active (ev_src_mice.priv))
- // return NULL;
-
- {
- char *r = malloc (64);
- sprintf (r, "%s %.0f %.0f %i", ret, mrg_mice_this->x, mrg_mice_this->y, button);
- return r;
+ fb->fb_bpp = fb->vinfo.bits_per_pixel / 8;
+ fb->fb_mapped_size = fb->finfo.smem_len;
+
+ fb->fb = mmap (NULL, fb->fb_mapped_size, PROT_READ|PROT_WRITE, MAP_SHARED, fb->fb_fd, 0);
}
+ if (!fb->fb)
+ return NULL;
+ tiled->pixels = calloc (fb->fb_mapped_size, 1);
+ ctx_fb_events = 1;
- return NULL;
-}
+#if CTX_BABL
+ babl_init ();
+#endif
-static int mice_get_fd (EvSource *ev_source)
-{
- return mrg_mice_this->fd;
-}
+ ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
-static void mice_set_coord (EvSource *ev_source, double x, double y)
-{
- mrg_mice_this->x = x;
- mrg_mice_this->y = y;
-}
+ tiled->ctx = ctx_new ();
+ tiled->ctx_copy = ctx_new ();
+ tiled->width = width;
+ tiled->height = height;
-EvSource *evsource_mice_new (void)
-{
- if (mmm_evsource_mice_init () == 0)
- {
- mrg_mice_this->x = 0;
- mrg_mice_this->y = 0;
- return &ev_src_mice;
- }
- return NULL;
-}
+ ctx_set_renderer (tiled->ctx, fb);
+ ctx_set_renderer (tiled->ctx_copy, fb);
+ ctx_set_texture_cache (tiled->ctx_copy, tiled->ctx);
+ ctx_set_size (tiled->ctx, width, height);
+ ctx_set_size (tiled->ctx_copy, width, height);
+ tiled->flush = (void*)ctx_fb_flush;
+ tiled->reset = (void*)ctx_fb_reset;
+ tiled->free = (void*)ctx_fb_free;
+ tiled->set_clipboard = (void*)ctx_fb_set_clipboard;
+ tiled->get_clipboard = (void*)ctx_fb_get_clipboard;
-static int evsource_kb_has_event (void);
-static char *evsource_kb_get_event (void);
-static void evsource_kb_destroy (int sign);
-static int evsource_kb_get_fd (void);
+ for (int i = 0; i < _ctx_max_threads; i++)
+ {
+ tiled->host[i] = ctx_new_for_framebuffer (tiled->pixels,
+ tiled->width/CTX_HASH_COLS, tiled->height/CTX_HASH_ROWS,
+ tiled->width * 4, CTX_FORMAT_RGBA8); // this format
+ // is overriden in thread
+ ((CtxRasterizer*)(tiled->host[i]->renderer))->swap_red_green = 1;
+ ctx_set_texture_source (tiled->host[i], tiled->ctx);
+ }
-/* kept out of struct to be reachable by atexit */
-static EvSource ev_src_kb = {
- NULL,
- (void*)evsource_kb_has_event,
- (void*)evsource_kb_get_event,
- (void*)evsource_kb_destroy,
- (void*)evsource_kb_get_fd,
- NULL
-};
+ mtx_init (&tiled->mtx, mtx_plain);
+ cnd_init (&tiled->cond);
-static struct termios orig_attr;
+#define start_thread(no)\
+ if(_ctx_max_threads>no){ \
+ static void *args[2]={(void*)no, };\
+ thrd_t tid;\
+ args[1]=fb;\
+ thrd_create (&tid, (void*)ctx_tiled_render_fun, args);\
+ }
+ start_thread(0);
+ start_thread(1);
+ start_thread(2);
+ start_thread(3);
+ start_thread(4);
+ start_thread(5);
+ start_thread(6);
+ start_thread(7);
+ start_thread(8);
+ start_thread(9);
+ start_thread(10);
+ start_thread(11);
+ start_thread(12);
+ start_thread(13);
+ start_thread(14);
+ start_thread(15);
+#undef start_thread
-int is_active (void *host)
-{
- return 1;
-}
-static void real_evsource_kb_destroy (int sign)
-{
- static int done = 0;
+ ctx_flush (tiled->ctx);
- if (sign == 0)
- return;
+ EvSource *kb = evsource_kb_new ();
+ if (kb)
+ {
+ fb->evsource[fb->evsource_count++] = kb;
+ kb->priv = fb;
+ }
+ EvSource *mice = evsource_mice_new ();
+ if (mice)
+ {
+ fb->evsource[fb->evsource_count++] = mice;
+ mice->priv = fb;
+ }
- if (done)
- return;
- done = 1;
+ fb->vt_active = 1;
+ ioctl(0, KDSETMODE, KD_GRAPHICS);
+ signal (SIGUSR1, vt_switch_cb);
+ signal (SIGUSR2, vt_switch_cb);
+ struct vt_stat st;
+ if (ioctl (0, VT_GETSTATE, &st) == -1)
+ {
+ ctx_log ("VT_GET_MODE on vt %i failed\n", fb->vt);
+ return NULL;
+ }
- switch (sign)
+ fb->vt = st.v_active;
+
+ struct vt_mode mode;
+ mode.mode = VT_PROCESS;
+ mode.relsig = SIGUSR1;
+ mode.acqsig = SIGUSR2;
+ if (ioctl (0, VT_SETMODE, &mode) < 0)
{
- case -11:break; /* will be called from atexit with sign==-11 */
- case SIGSEGV: fprintf (stderr, " SIGSEGV\n");break;
- case SIGABRT: fprintf (stderr, " SIGABRT\n");break;
- case SIGBUS: fprintf (stderr, " SIGBUS\n");break;
- case SIGKILL: fprintf (stderr, " SIGKILL\n");break;
- case SIGINT: fprintf (stderr, " SIGINT\n");break;
- case SIGTERM: fprintf (stderr, " SIGTERM\n");break;
- case SIGQUIT: fprintf (stderr, " SIGQUIT\n");break;
- default: fprintf (stderr, "sign: %i\n", sign);
- fprintf (stderr, "%i %i %i %i %i %i %i\n", SIGSEGV, SIGABRT, SIGBUS, SIGKILL, SIGINT, SIGTERM,
SIGQUIT);
+ ctx_log ("VT_SET_MODE on vt %i failed\n", fb->vt);
+ return NULL;
}
- tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
- //fprintf (stderr, "evsource kb destroy\n");
-}
-static void evsource_kb_destroy (int sign)
-{
- real_evsource_kb_destroy (-11);
+ return tiled->ctx;
+#else
+ return NULL;
+#endif
}
+#else
-static int evsource_kb_init ()
+int ctx_renderer_is_fb (Ctx *ctx)
{
-// ioctl(STDIN_FILENO, KDSKBMODE, K_RAW);
- atexit ((void*) real_evsource_kb_destroy);
- signal (SIGSEGV, (void*) real_evsource_kb_destroy);
- signal (SIGABRT, (void*) real_evsource_kb_destroy);
- signal (SIGBUS, (void*) real_evsource_kb_destroy);
- signal (SIGKILL, (void*) real_evsource_kb_destroy);
- signal (SIGINT, (void*) real_evsource_kb_destroy);
- signal (SIGTERM, (void*) real_evsource_kb_destroy);
- signal (SIGQUIT, (void*) real_evsource_kb_destroy);
-
- struct termios raw;
- if (tcgetattr (STDIN_FILENO, &orig_attr) == -1)
- {
- fprintf (stderr, "error initializing keyboard\n");
- return -1;
- }
- raw = orig_attr;
-
- cfmakeraw (&raw);
-
- raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
- if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
- return 0; // XXX? return other value?
-
return 0;
}
-static int evsource_kb_has_event (void)
-{
- struct timeval tv;
- int retval;
-
- fd_set rfds;
- FD_ZERO (&rfds);
- FD_SET(STDIN_FILENO, &rfds);
- tv.tv_sec = 0; tv.tv_usec = 0;
- retval = select (STDIN_FILENO+1, &rfds, NULL, NULL, &tv);
- return retval == 1;
-}
-
-/* note that a nick can have multiple occurences, the labels
- * should be kept the same for all occurences of a combination.
- *
- * this table is taken from nchanterm.
- */
-typedef struct MmmKeyCode {
- char *nick; /* programmers name for key */
- char sequence[10]; /* terminal sequence */
-} MmmKeyCode;
-static const MmmKeyCode ufb_keycodes[]={
- {"up", "\e[A"},
- {"down", "\e[B"},
- {"right", "\e[C"},
- {"left", "\e[D"},
-
- {"shift-up", "\e[1;2A"},
- {"shift-down", "\e[1;2B"},
- {"shift-right", "\e[1;2C"},
- {"shift-left", "\e[1;2D"},
-
- {"alt-up", "\e[1;3A"},
- {"alt-down", "\e[1;3B"},
- {"alt-right", "\e[1;3C"},
- {"alt-left", "\e[1;3D"},
- {"alt-shift-up", "\e[1;4A"},
- {"alt-shift-down", "\e[1;4B"},
- {"alt-shift-right", "\e[1;4C"},
- {"alt-shift-left", "\e[1;4D"},
-
- {"control-up", "\e[1;5A"},
- {"control-down", "\e[1;5B"},
- {"control-right", "\e[1;5C"},
- {"control-left", "\e[1;5D"},
-
- /* putty */
- {"control-up", "\eOA"},
- {"control-down", "\eOB"},
- {"control-right", "\eOC"},
- {"control-left", "\eOD"},
-
- {"control-shift-up", "\e[1;6A"},
- {"control-shift-down", "\e[1;6B"},
- {"control-shift-right", "\e[1;6C"},
- {"control-shift-left", "\e[1;6D"},
-
- {"control-up", "\eOa"},
- {"control-down", "\eOb"},
- {"control-right", "\eOc"},
- {"control-left", "\eOd"},
-
- {"shift-up", "\e[a"},
- {"shift-down", "\e[b"},
- {"shift-right", "\e[c"},
- {"shift-left", "\e[d"},
+#endif
+#endif
- {"insert", "\e[2~"},
- {"delete", "\e[3~"},
- {"page-up", "\e[5~"},
- {"page-down", "\e[6~"},
- {"home", "\eOH"},
- {"end", "\eOF"},
- {"home", "\e[H"},
- {"end", "\e[F"},
- {"control-delete", "\e[3;5~"},
- {"shift-delete", "\e[3;2~"},
- {"control-shift-delete","\e[3;6~"},
+#if CTX_SDL
- {"F1", "\e[25~"},
- {"F2", "\e[26~"},
- {"F3", "\e[27~"},
- {"F4", "\e[26~"},
+/**/
+typedef struct _CtxSDL CtxSDL;
+struct _CtxSDL
+{
+ CtxTiled tiled;
+ /* where we diverge from fb*/
+ int key_balance;
+ int key_repeat;
+ int lctrl;
+ int lalt;
+ int rctrl;
+ int lshift;
+ int rshift;
- {"F1", "\e[11~"},
- {"F2", "\e[12~"},
- {"F3", "\e[13~"},
- {"F4", "\e[14~"},
- {"F1", "\eOP"},
- {"F2", "\eOQ"},
- {"F3", "\eOR"},
- {"F4", "\eOS"},
- {"F5", "\e[15~"},
- {"F6", "\e[16~"},
- {"F7", "\e[17~"},
- {"F8", "\e[18~"},
- {"F9", "\e[19~"},
- {"F9", "\e[20~"},
- {"F10", "\e[21~"},
- {"F11", "\e[22~"},
- {"F12", "\e[23~"},
- {"tab", {9, '\0'}},
- {"shift-tab", {27, 9, '\0'}}, // also generated by alt-tab in linux console
- {"alt-space", {27, ' ', '\0'}},
- {"shift-tab", "\e[Z"},
- {"backspace", {127, '\0'}},
- {"space", " "},
- {"\e", "\e"},
- {"return", {10,0}},
- {"return", {13,0}},
- /* this section could be autogenerated by code */
- {"control-a", {1,0}},
- {"control-b", {2,0}},
- {"control-c", {3,0}},
- {"control-d", {4,0}},
- {"control-e", {5,0}},
- {"control-f", {6,0}},
- {"control-g", {7,0}},
- {"control-h", {8,0}}, /* backspace? */
- {"control-i", {9,0}},
- {"control-j", {10,0}},
- {"control-k", {11,0}},
- {"control-l", {12,0}},
- {"control-n", {14,0}},
- {"control-o", {15,0}},
- {"control-p", {16,0}},
- {"control-q", {17,0}},
- {"control-r", {18,0}},
- {"control-s", {19,0}},
- {"control-t", {20,0}},
- {"control-u", {21,0}},
- {"control-v", {22,0}},
- {"control-w", {23,0}},
- {"control-x", {24,0}},
- {"control-y", {25,0}},
- {"control-z", {26,0}},
- {"alt-`", "\e`"},
- {"alt-0", "\e0"},
- {"alt-1", "\e1"},
- {"alt-2", "\e2"},
- {"alt-3", "\e3"},
- {"alt-4", "\e4"},
- {"alt-5", "\e5"},
- {"alt-6", "\e6"},
- {"alt-7", "\e7"}, /* backspace? */
- {"alt-8", "\e8"},
- {"alt-9", "\e9"},
- {"alt-+", "\e+"},
- {"alt--", "\e-"},
- {"alt-/", "\e/"},
- {"alt-a", "\ea"},
- {"alt-b", "\eb"},
- {"alt-c", "\ec"},
- {"alt-d", "\ed"},
- {"alt-e", "\ee"},
- {"alt-f", "\ef"},
- {"alt-g", "\eg"},
- {"alt-h", "\eh"}, /* backspace? */
- {"alt-i", "\ei"},
- {"alt-j", "\ej"},
- {"alt-k", "\ek"},
- {"alt-l", "\el"},
- {"alt-n", "\em"},
- {"alt-n", "\en"},
- {"alt-o", "\eo"},
- {"alt-p", "\ep"},
- {"alt-q", "\eq"},
- {"alt-r", "\er"},
- {"alt-s", "\es"},
- {"alt-t", "\et"},
- {"alt-u", "\eu"},
- {"alt-v", "\ev"},
- {"alt-w", "\ew"},
- {"alt-x", "\ex"},
- {"alt-y", "\ey"},
- {"alt-z", "\ez"},
- /* Linux Console */
- {"home", "\e[1~"},
- {"end", "\e[4~"},
- {"F1", "\e[[A"},
- {"F2", "\e[[B"},
- {"F3", "\e[[C"},
- {"F4", "\e[[D"},
- {"F5", "\e[[E"},
- {"F6", "\e[[F"},
- {"F7", "\e[[G"},
- {"F8", "\e[[H"},
- {"F9", "\e[[I"},
- {"F10", "\e[[J"},
- {"F11", "\e[[K"},
- {"F12", "\e[[L"},
- {NULL, }
+ SDL_Window *window;
+ SDL_Renderer *renderer;
+ SDL_Texture *texture;
+
+// cnd_t cond;
+// mtx_t mtx;
};
-static int fb_keyboard_match_keycode (const char *buf, int length, const MmmKeyCode **ret)
-{
- int i;
- int matches = 0;
- if (!strncmp (buf, "\e[M", MIN(length,3)))
- {
- if (length >= 6)
- return 9001;
- return 2342;
- }
- for (i = 0; ufb_keycodes[i].nick; i++)
- if (!strncmp (buf, ufb_keycodes[i].sequence, length))
- {
- matches ++;
- if ((int)strlen (ufb_keycodes[i].sequence) == length && ret)
- {
- *ret = &ufb_keycodes[i];
- return 1;
- }
- }
- if (matches != 1 && ret)
- *ret = NULL;
- return matches==1?2:matches;
-}
+#include "stb_image_write.h"
-static char *evsource_kb_get_event (void)
+void ctx_screenshot (Ctx *ctx, const char *output_path)
{
- unsigned char buf[20];
- int length;
+#if CTX_SCREENSHOT
+ int valid = 0;
+ CtxSDL *sdl = (void*)ctx->renderer;
+ if (ctx_renderer_is_sdl (ctx)) valid = 1;
+#if CTX_FB
+ if (ctx_renderer_is_fb (ctx)) valid = 1;
+#endif
- for (length = 0; length < 10; length ++)
- if (read (STDIN_FILENO, &buf[length], 1) != -1)
- {
- const MmmKeyCode *match = NULL;
+ if (!valid)
+ return;
- if (!is_active (ev_src_kb.priv))
- return NULL;
+#if CTX_FB
+ // we rely on the same layout
+ for (int i = 0; i < sdl->width * sdl->height; i++)
+ {
+ int tmp = sdl->pixels[i*4];
+ sdl->pixels[i*4] = sdl->pixels[i*4 + 2];
+ sdl->pixels[i*4 + 2] = tmp;
+ }
+#endif
- /* special case ESC, so that we can use it alone in keybindings */
- if (length == 0 && buf[0] == 27)
- {
- struct timeval tv;
- fd_set rfds;
- FD_ZERO (&rfds);
- FD_SET (STDIN_FILENO, &rfds);
- tv.tv_sec = 0;
- tv.tv_usec = 1000 * 120;
- if (select (STDIN_FILENO+1, &rfds, NULL, NULL, &tv) == 0)
- return strdup ("escape");
- }
+ stbi_write_png (output_path, sdl->width, sdl->height, 4, sdl->pixels, sdl->width*4);
- switch (fb_keyboard_match_keycode ((void*)buf, length + 1, &match))
- {
- case 1: /* unique match */
- if (!match)
- return NULL;
- return strdup (match->nick);
- break;
- case 0: /* no matches, bail*/
- {
- static char ret[256];
- if (length == 0 && ctx_utf8_len (buf[0])>1) /* read a
- * single unicode
- * utf8 character
- */
- {
- read (STDIN_FILENO, &buf[length+1], ctx_utf8_len(buf[0])-1);
- buf[ctx_utf8_len(buf[0])]=0;
- strcpy (ret, (void*)buf);
- return strdup(ret); //XXX: simplify
- }
- if (length == 0) /* ascii */
- {
- buf[1]=0;
- strcpy (ret, (void*)buf);
- return strdup(ret);
- }
- sprintf (ret, "unhandled %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c'",
- length >=0 ? buf[0] : 0,
- length >=0 ? buf[0]>31?buf[0]:'?' : ' ',
- length >=1 ? buf[1] : 0,
- length >=1 ? buf[1]>31?buf[1]:'?' : ' ',
- length >=2 ? buf[2] : 0,
- length >=2 ? buf[2]>31?buf[2]:'?' : ' ',
- length >=3 ? buf[3] : 0,
- length >=3 ? buf[3]>31?buf[3]:'?' : ' ',
- length >=4 ? buf[4] : 0,
- length >=4 ? buf[4]>31?buf[4]:'?' : ' ',
- length >=5 ? buf[5] : 0,
- length >=5 ? buf[5]>31?buf[5]:'?' : ' ',
- length >=6 ? buf[6] : 0,
- length >=6 ? buf[6]>31?buf[6]:'?' : ' '
- );
- return strdup(ret);
- }
- return NULL;
- default: /* continue */
- break;
- }
- }
- else
- return strdup("key read eek");
- return strdup("fail");
+#if CTX_FB
+ for (int i = 0; i < sdl->width * sdl->height; i++)
+ {
+ int tmp = sdl->pixels[i*4];
+ sdl->pixels[i*4] = sdl->pixels[i*4 + 2];
+ sdl->pixels[i*4 + 2] = tmp;
+ }
+#endif
+#endif
}
-static int evsource_kb_get_fd (void)
+void ctx_sdl_set_title (void *self, const char *new_title)
{
- return STDIN_FILENO;
+ CtxSDL *sdl = self;
+ SDL_SetWindowTitle (sdl->window, new_title);
}
-
-EvSource *evsource_kb_new (void)
+static void ctx_sdl_show_frame (CtxSDL *sdl, int block)
{
- if (evsource_kb_init() == 0)
+ CtxTiled *tiled = &sdl->tiled;
+ if (tiled->shown_cursor != tiled->ctx->cursor)
{
- return &ev_src_kb;
+ tiled->shown_cursor = tiled->ctx->cursor;
+ SDL_Cursor *new_cursor = NULL;
+ switch (tiled->shown_cursor)
+ {
+ case CTX_CURSOR_UNSET: // XXX: document how this differs from none
+ // perhaps falling back to arrow?
+ break;
+ case CTX_CURSOR_NONE:
+ new_cursor = NULL;
+ break;
+ case CTX_CURSOR_ARROW:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
+ break;
+ case CTX_CURSOR_CROSSHAIR:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
+ break;
+ case CTX_CURSOR_WAIT:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
+ break;
+ case CTX_CURSOR_HAND:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
+ break;
+ case CTX_CURSOR_IBEAM:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
+ break;
+ case CTX_CURSOR_MOVE:
+ case CTX_CURSOR_RESIZE_ALL:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
+ break;
+ case CTX_CURSOR_RESIZE_N:
+ case CTX_CURSOR_RESIZE_S:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
+ break;
+ case CTX_CURSOR_RESIZE_E:
+ case CTX_CURSOR_RESIZE_W:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
+ break;
+ case CTX_CURSOR_RESIZE_NE:
+ case CTX_CURSOR_RESIZE_SW:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
+ break;
+ case CTX_CURSOR_RESIZE_NW:
+ case CTX_CURSOR_RESIZE_SE:
+ new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
+ break;
+ }
+ if (new_cursor)
+ {
+ SDL_Cursor *old_cursor = SDL_GetCursor();
+ SDL_SetCursor (new_cursor);
+ SDL_ShowCursor (1);
+ if (old_cursor)
+ SDL_FreeCursor (old_cursor);
+ }
+ else
+ {
+ SDL_ShowCursor (0);
+ }
}
- return NULL;
-}
-static int event_check_pending (CtxFb *fb)
-{
- int events = 0;
- for (int i = 0; i < fb->evsource_count; i++)
+ if (tiled->shown_frame == tiled->render_frame)
{
- while (evsource_has_event (fb->evsource[i]))
+ return;
+ }
+
+ if (block)
+ {
+ int count = 0;
+ while (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
{
- char *event = evsource_get_event (fb->evsource[i]);
- if (event)
+ usleep (50);
+ count ++;
+ if (count > 2000)
{
- if (fb->vt_active)
- {
- ctx_key_press (fb->ctx, 0, event, 0); // we deliver all events as key-press, it disamibuates
- events++;
- }
- free (event);
+ tiled->shown_frame = tiled->render_frame;
+ return;
}
}
}
- return events;
-}
+ else
+ {
+ if (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
+ return;
+ }
-int ctx_fb_consume_events (Ctx *ctx)
-{
- CtxFb *fb = (void*)ctx->renderer;
- ctx_fb_show_frame (fb, 0);
- event_check_pending (fb);
- return 0;
+ if (tiled->min_row == 100)
+ {
+ }
+ else
+ {
+#if 1
+ int x = tiled->min_col * tiled->width/CTX_HASH_COLS;
+ int y = tiled->min_row * tiled->height/CTX_HASH_ROWS;
+ int x1 = (tiled->max_col+1) * tiled->width/CTX_HASH_COLS;
+ int y1 = (tiled->max_row+1) * tiled->height/CTX_HASH_ROWS;
+ int width = x1 - x;
+ int height = y1 - y;
+#endif
+ tiled->min_row = 100;
+ tiled->max_row = 0;
+ tiled->min_col = 100;
+ tiled->max_col = 0;
+
+ SDL_Rect r = {x, y, width, height};
+ SDL_UpdateTexture (sdl->texture, &r,
+ //(void*)sdl->pixels,
+ (void*)(tiled->pixels + y * tiled->width * 4 + x * 4),
+
+ tiled->width * 4);
+ SDL_RenderClear (sdl->renderer);
+ SDL_RenderCopy (sdl->renderer, sdl->texture, NULL, NULL);
+ SDL_RenderPresent (sdl->renderer);
+ }
+ tiled->shown_frame = tiled->render_frame;
}
-inline static void ctx_fb_reset (CtxFb *fb)
+static const char *ctx_sdl_keysym_to_name (unsigned int sym, int *r_keycode)
{
- ctx_fb_show_frame (fb, 1);
+ static char buf[16]="";
+ buf[ctx_unichar_to_utf8 (sym, (void*)buf)]=0;
+ int code = sym;
+ const char *name = &buf[0];
+ switch (sym)
+ {
+ case SDLK_RSHIFT: code = 16 ; break;
+ case SDLK_LSHIFT: code = 16 ; break;
+ case SDLK_LCTRL: code = 17 ; break;
+ case SDLK_RCTRL: code = 17 ; break;
+ case SDLK_LALT: code = 18 ; break;
+ case SDLK_RALT: code = 18 ; break;
+ case SDLK_CAPSLOCK: name = "capslock"; code = 20 ; break;
+ //case SDLK_NUMLOCK: name = "numlock"; code = 144 ; break;
+ //case SDLK_SCROLLLOCK: name = "scrollock"; code = 145 ; break;
+
+ case SDLK_F1: name = "F1"; code = 112; break;
+ case SDLK_F2: name = "F2"; code = 113; break;
+ case SDLK_F3: name = "F3"; code = 114; break;
+ case SDLK_F4: name = "F4"; code = 115; break;
+ case SDLK_F5: name = "F5"; code = 116; break;
+ case SDLK_F6: name = "F6"; code = 117; break;
+ case SDLK_F7: name = "F7"; code = 118; break;
+ case SDLK_F8: name = "F8"; code = 119; break;
+ case SDLK_F9: name = "F9"; code = 120; break;
+ case SDLK_F10: name = "F10"; code = 121; break;
+ case SDLK_F11: name = "F11"; code = 122; break;
+ case SDLK_F12: name = "F12"; code = 123; break;
+ case SDLK_ESCAPE: name = "escape"; break;
+ case SDLK_DOWN: name = "down"; code = 40; break;
+ case SDLK_LEFT: name = "left"; code = 37; break;
+ case SDLK_UP: name = "up"; code = 38; break;
+ case SDLK_RIGHT: name = "right"; code = 39; break;
+ case SDLK_BACKSPACE: name = "backspace"; break;
+ case SDLK_SPACE: name = "space"; break;
+ case SDLK_TAB: name = "tab"; break;
+ case SDLK_DELETE: name = "delete"; code = 46; break;
+ case SDLK_INSERT: name = "insert"; code = 45; break;
+ case SDLK_RETURN:
+ //if (key_repeat == 0) // return never should repeat
+ name = "return"; // on a DEC like terminal
+ break;
+ case SDLK_HOME: name = "home"; code = 36; break;
+ case SDLK_END: name = "end"; code = 35; break;
+ case SDLK_PAGEDOWN: name = "page-down"; code = 34; break;
+ case SDLK_PAGEUP: name = "page-up"; code = 33; break;
+ case ',': code = 188; break;
+ case '.': code = 190; break;
+ case '/': code = 191; break;
+ case '`': code = 192; break;
+ case '[': code = 219; break;
+ case '\\': code = 220; break;
+ case ']': code = 221; break;
+ case '\'': code = 222; break;
+ default:
+ ;
+ }
+ if (sym >= 'a' && sym <='z') code -= 32;
+ if (r_keycode)
+ {
+ *r_keycode = code;
+ }
+ return name;
}
-inline static void ctx_fb_flush (CtxFb *fb)
+int ctx_sdl_consume_events (Ctx *ctx)
{
- if (fb->shown_frame == fb->render_frame)
+ CtxTiled *tiled = (void*)ctx->renderer;
+ CtxSDL *sdl = (void*)ctx->renderer;
+ SDL_Event event;
+ int got_events = 0;
+
+ ctx_sdl_show_frame (sdl, 0);
+
+ while (SDL_PollEvent (&event))
{
- int dirty_tiles = 0;
- ctx_set_drawlist (fb->ctx_copy, &fb->ctx->drawlist.entries[0],
- fb->ctx->drawlist.count * 9);
- if (_ctx_enable_hash_cache)
+ got_events ++;
+ switch (event.type)
{
- Ctx *hasher = ctx_hasher_new (fb->width, fb->height,
- CTX_HASH_COLS, CTX_HASH_ROWS);
- ctx_render_ctx (fb->ctx_copy, hasher);
-
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++)
+ case SDL_MOUSEBUTTONDOWN:
+ SDL_CaptureMouse (1);
+ ctx_pointer_press (ctx, event.button.x, event.button.y, event.button.button, 0);
+ break;
+ case SDL_MOUSEBUTTONUP:
+ SDL_CaptureMouse (0);
+ ctx_pointer_release (ctx, event.button.x, event.button.y, event.button.button, 0);
+ break;
+ case SDL_MOUSEMOTION:
+ // XXX : look at mask and generate motion for each pressed
+ // button
+ ctx_pointer_motion (ctx, event.motion.x, event.motion.y, 1, 0);
+ break;
+ case SDL_FINGERMOTION:
+ ctx_pointer_motion (ctx, event.tfinger.x * tiled->width, event.tfinger.y * tiled->height,
+ (event.tfinger.fingerId%10) + 4, 0);
+ break;
+ case SDL_FINGERDOWN:
{
- uint8_t *new_hash = ctx_hasher_get_hash (hasher, col, row);
- if (new_hash && memcmp (new_hash, &fb->hashes[(row * CTX_HASH_COLS + col) * 20], 20))
+ static int fdowns = 0;
+ fdowns ++;
+ if (fdowns > 1) // the very first finger down from SDL seems to be
+ // mirrored as mouse events, later ones not - at
+ // least under wayland
+ {
+ ctx_pointer_press (ctx, event.tfinger.x * tiled->width, event.tfinger.y * tiled->height,
+ (event.tfinger.fingerId%10) + 4, 0);
+ }
+ }
+ break;
+ case SDL_FINGERUP:
+ ctx_pointer_release (ctx, event.tfinger.x * tiled->width, event.tfinger.y * tiled->height,
+ (event.tfinger.fingerId%10) + 4, 0);
+ break;
+#if 1
+ case SDL_TEXTINPUT:
+ // if (!active)
+ // break;
+ if (!sdl->lctrl && !sdl->rctrl && !sdl->lalt
+ //&& ( (vt && vt_keyrepeat (vt) ) || (key_repeat==0) )
+ )
{
- memcpy (&fb->hashes[(row * CTX_HASH_COLS + col)*20], new_hash, 20);
- fb->tile_affinity[row * CTX_HASH_COLS + col] = 1;
- dirty_tiles++;
+ const char *name = event.text.text;
+ int keycode = 0;
+ if (!strcmp (name, " ") ) { name = "space"; }
+ if (name[0] && name[1] == 0)
+ {
+ keycode = name[0];
+ keycode = toupper (keycode);
+ switch (keycode)
+ {
+ case '.': keycode = 190; break;
+ case ';': keycode = 59; break;
+ case ',': keycode = 188; break;
+ case '/': keycode = 191; break;
+ case '\'': keycode = 222; break;
+ case '`': keycode = 192; break;
+ case '[': keycode = 219; break;
+ case ']': keycode = 221; break;
+ case '\\': keycode = 220; break;
+ }
+ }
+ ctx_key_press (ctx, keycode, name, 0);
+ //got_event = 1;
+ }
+ break;
+#endif
+ case SDL_KEYDOWN:
+ {
+ char buf[32] = "";
+ const char *name = buf;
+ if (!event.key.repeat)
+ {
+ sdl->key_balance ++;
+ sdl->key_repeat = 0;
+ }
+ else
+ {
+ sdl->key_repeat ++;
+ }
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_LSHIFT: sdl->lshift = 1; break;
+ case SDLK_RSHIFT: sdl->rshift = 1; break;
+ case SDLK_LCTRL: sdl->lctrl = 1; break;
+ case SDLK_LALT: sdl->lalt = 1; break;
+ case SDLK_RCTRL: sdl->rctrl = 1; break;
+ }
+ if (sdl->lshift | sdl->rshift | sdl->lctrl | sdl->lalt | sdl->rctrl)
+ {
+ ctx->events.modifier_state ^= ~(CTX_MODIFIER_STATE_CONTROL|
+ CTX_MODIFIER_STATE_ALT|
+ CTX_MODIFIER_STATE_SHIFT);
+ if (sdl->lshift | sdl->rshift)
+ ctx->events.modifier_state |= CTX_MODIFIER_STATE_SHIFT;
+ if (sdl->lctrl | sdl->rctrl)
+ ctx->events.modifier_state |= CTX_MODIFIER_STATE_CONTROL;
+ if (sdl->lalt)
+ ctx->events.modifier_state |= CTX_MODIFIER_STATE_ALT;
+ }
+ int keycode;
+ name = ctx_sdl_keysym_to_name (event.key.keysym.sym, &keycode);
+ ctx_key_down (ctx, keycode, name, 0);
+
+ if (strlen (name)
+ &&(event.key.keysym.mod & (KMOD_CTRL) ||
+ event.key.keysym.mod & (KMOD_ALT) ||
+ strlen (name) >= 2))
+ {
+ if (event.key.keysym.mod & (KMOD_CTRL) )
+ {
+ static char buf[64] = "";
+ sprintf (buf, "control-%s", name);
+ name = buf;
+ }
+ if (event.key.keysym.mod & (KMOD_ALT) )
+ {
+ static char buf[128] = "";
+ sprintf (buf, "alt-%s", name);
+ name = buf;
+ }
+ if (event.key.keysym.mod & (KMOD_SHIFT) )
+ {
+ static char buf[196] = "";
+ sprintf (buf, "shift-%s", name);
+ name = buf;
+ }
+ if (strcmp (name, "space"))
+ {
+ ctx_key_press (ctx, keycode, name, 0);
+ }
}
else
{
- fb->tile_affinity[row * CTX_HASH_COLS + col] = -1;
+#if 0
+ ctx_key_press (ctx, 0, buf, 0);
+#endif
+ }
+ }
+ break;
+ case SDL_KEYUP:
+ {
+ sdl->key_balance --;
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_LSHIFT: sdl->lshift = 0; break;
+ case SDLK_RSHIFT: sdl->rshift = 0; break;
+ case SDLK_LCTRL: sdl->lctrl = 0; break;
+ case SDLK_RCTRL: sdl->rctrl = 0; break;
+ case SDLK_LALT: sdl->lalt = 0; break;
+ }
+
+ {
+ ctx->events.modifier_state ^= ~(CTX_MODIFIER_STATE_CONTROL|
+ CTX_MODIFIER_STATE_ALT|
+ CTX_MODIFIER_STATE_SHIFT);
+ if (sdl->lshift | sdl->rshift)
+ ctx->events.modifier_state |= CTX_MODIFIER_STATE_SHIFT;
+ if (sdl->lctrl | sdl->rctrl)
+ ctx->events.modifier_state |= CTX_MODIFIER_STATE_CONTROL;
+ if (sdl->lalt)
+ ctx->events.modifier_state |= CTX_MODIFIER_STATE_ALT;
}
- }
- free (((CtxHasher*)(hasher->renderer))->hashes);
- ctx_free (hasher);
- }
- else
- {
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++)
- {
- fb->tile_affinity[row * CTX_HASH_COLS + col] = 1;
- dirty_tiles++;
- }
- }
- int dirty_no = 0;
- if (dirty_tiles)
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++)
- {
- if (fb->tile_affinity[row * CTX_HASH_COLS + col] != -1)
- {
- fb->tile_affinity[row * CTX_HASH_COLS + col] = dirty_no * (_ctx_max_threads) / dirty_tiles;
- dirty_no++;
- if (col > fb->max_col) fb->max_col = col;
- if (col < fb->min_col) fb->min_col = col;
- if (row > fb->max_row) fb->max_row = row;
- if (row < fb->min_row) fb->min_row = row;
+ int keycode;
+ const char *name = ctx_sdl_keysym_to_name (event.key.keysym.sym, &keycode);
+ ctx_key_up (ctx, keycode, name, 0);
}
- }
+ break;
+ case SDL_QUIT:
+ ctx_quit (ctx);
+ break;
+ case SDL_WINDOWEVENT:
+ if (event.window.event == SDL_WINDOWEVENT_RESIZED)
+ {
+ ctx_sdl_show_frame (sdl, 1);
+ int width = event.window.data1;
+ int height = event.window.data2;
+ SDL_DestroyTexture (sdl->texture);
+ sdl->texture = SDL_CreateTexture (sdl->renderer, SDL_PIXELFORMAT_ABGR8888,
+ SDL_TEXTUREACCESS_STREAMING, width, height);
+ free (tiled->pixels);
+ tiled->pixels = calloc (4, width * height);
-#if CTX_DAMAGE_CONTROL
- for (int i = 0; i < fb->width * fb->height; i++)
- {
- int new_ = (fb->scratch_fb[i*4+0]+ fb->scratch_fb[i*4+1]+ fb->scratch_fb[i*4+2])/3;
- if (new_>1) new_--;
- fb->scratch_fb[i*4]= (fb->scratch_fb[i*4] + new_)/2;
- fb->scratch_fb[i*4+1]= (fb->scratch_fb[i*4+1] + new_)/2;
- fb->scratch_fb[i*4+2]= (fb->scratch_fb[i*4+1] + new_)/2;
+ tiled->width = width;
+ tiled->height = height;
+ ctx_set_size (tiled->ctx, width, height);
+ ctx_set_size (tiled->ctx_copy, width, height);
+ }
+ break;
}
-#endif
-
-
- fb->render_frame = ++fb->frame;
-
- mtx_lock (&fb->mtx);
- cnd_broadcast (&fb->cond);
- mtx_unlock (&fb->mtx);
}
+ return 1;
}
-
-void ctx_fb_free (CtxFb *fb)
+#else
+void ctx_screenshot (Ctx *ctx, const char *path)
{
- mtx_lock (&fb->mtx);
- cnd_broadcast (&fb->cond);
- mtx_unlock (&fb->mtx);
-
- memset (fb->fb, 0, fb->width * fb->height * 4);
- for (int i = 0 ; i < _ctx_max_threads; i++)
- ctx_free (fb->host[i]);
+}
+#endif
- if (fb->is_drm)
- {
- ctx_fbdrm_close (fb);
- }
+#if CTX_SDL
- ioctl (0, KDSETMODE, KD_TEXT);
- system("stty sane");
- free (fb->scratch_fb);
- //free (fb);
+static void ctx_sdl_set_clipboard (CtxSDL *sdl, const char *text)
+{
+ if (text)
+ SDL_SetClipboardText (text);
}
-static unsigned char *fb_icc = NULL;
-static long fb_icc_length = 0;
-
-static
-void fb_render_fun (void **data)
+static char *ctx_sdl_get_clipboard (CtxSDL *sdl)
{
- int no = (size_t)data[0];
- CtxFb *fb = data[1];
+ return SDL_GetClipboardText ();
+}
- while (!fb->quit)
- {
- mtx_lock (&fb->mtx);
- cnd_wait (&fb->cond, &fb->mtx);
- mtx_unlock (&fb->mtx);
+inline static void ctx_sdl_reset (CtxSDL *sdl)
+{
+ ctx_sdl_show_frame (sdl, 1);
+}
- if (fb->render_frame != fb->rendered_frame[no])
- {
- int hno = 0;
+inline static void ctx_sdl_flush (CtxSDL *sdl)
+{
+ ctx_tiled_flush ((void*)sdl);
+ //CtxTiled *tiled = (void*)sdl;
+}
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++, hno++)
- {
- if (fb->tile_affinity[hno]==no)
- {
- int x0 = ((fb->width)/CTX_HASH_COLS) * col;
- int y0 = ((fb->height)/CTX_HASH_ROWS) * row;
- int width = fb->width / CTX_HASH_COLS;
- int height = fb->height / CTX_HASH_ROWS;
+void ctx_sdl_free (CtxSDL *sdl)
+{
- Ctx *host = fb->host[no];
- CtxRasterizer *rasterizer = (CtxRasterizer*)host->renderer;
- /* merge horizontally adjecant tiles of same affinity into one job
- * this reduces redundant overhead and gets better cache behavior
- *
- * giving different threads more explicitly different rows
- * could be a good idea.
- */
- while (col + 1 < CTX_HASH_COLS &&
- fb->tile_affinity[hno+1] == no)
- {
- width += fb->width / CTX_HASH_COLS;
- col++;
- hno++;
- }
- ctx_rasterizer_init (rasterizer,
- host, fb->ctx, &host->state,
- &fb->scratch_fb[fb->width * 4 * y0 + x0 * 4],
- 0, 0, width, height,
- fb->width*4, CTX_FORMAT_RGBA8,
- fb->antialias);
- /* this is the format used */
- if (fb->fb_bits == 32)
- rasterizer->swap_red_green = 1;
- if (fb_icc_length)
- ctx_colorspace (host, CTX_COLOR_SPACE_DEVICE_RGB, fb_icc, fb_icc_length);
- ctx_translate (host, -x0, -y0);
- ctx_render_ctx (fb->ctx_copy, host);
- }
- }
- fb->rendered_frame[no] = fb->render_frame;
+ if (sdl->texture)
+ SDL_DestroyTexture (sdl->texture);
+ if (sdl->renderer)
+ SDL_DestroyRenderer (sdl->renderer);
+ if (sdl->window)
+ SDL_DestroyWindow (sdl->window);
- if (fb_render_threads_done (fb) == _ctx_max_threads)
- {
- // ctx_render_stream (fb->ctx_copy, stdout, 1);
- // ctx_reset (fb->ctx_copy);
- }
- }
- }
- fb->thread_quit ++;
+ ctx_tiled_free ((CtxTiled*)sdl);
}
-int ctx_renderer_is_fb (Ctx *ctx)
+
+int ctx_renderer_is_sdl (Ctx *ctx)
{
if (ctx->renderer &&
- ctx->renderer->free == (void*)ctx_fb_free)
+ ctx->renderer->free == (void*)ctx_sdl_free)
return 1;
return 0;
}
-static CtxFb *ctx_fb = NULL;
-static void vt_switch_cb (int sig)
-{
- if (sig == SIGUSR1)
- {
- if (ctx_fb->is_drm)
- ioctl(ctx_fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
- ioctl (0, VT_RELDISP, 1);
- ctx_fb->vt_active = 0;
- ioctl (0, KDSETMODE, KD_TEXT);
- }
- else
- {
- ioctl (0, VT_RELDISP, VT_ACKACQ);
- ctx_fb->vt_active = 1;
- // queue draw
- ctx_fb->render_frame = ++ctx_fb->frame;
- ioctl (0, KDSETMODE, KD_GRAPHICS);
- if (ctx_fb->is_drm)
- {
- ioctl(ctx_fb->fb_fd, DRM_IOCTL_SET_MASTER, 0);
- ctx_fb_flip (ctx_fb);
- }
- else
- {
- ctx_fb->ctx->dirty=1;
-
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++)
- {
- ctx_fb->hashes[(row * CTX_HASH_COLS + col) * 20] += 1;
- }
- }
-
- }
-}
-Ctx *ctx_new_fb (int width, int height, int drm)
+Ctx *ctx_new_sdl (int width, int height)
{
#if CTX_RASTERIZER
- CtxFb *fb = calloc (sizeof (CtxFb), 1);
-
- ctx_fb = fb;
- if (drm)
- fb->fb = ctx_fbdrm_new (fb, &fb->width, &fb->height);
- if (fb->fb)
- {
- fb->is_drm = 1;
- width = fb->width;
- height = fb->height;
- fb->fb_mapped_size = fb->width * fb->height * 4;
- fb->fb_bits = 32;
- fb->fb_bpp = 4;
- }
- else
- {
- fb->fb_fd = open ("/dev/fb0", O_RDWR);
- if (fb->fb_fd > 0)
- fb->fb_path = strdup ("/dev/fb0");
- else
- {
- fb->fb_fd = open ("/dev/graphics/fb0", O_RDWR);
- if (fb->fb_fd > 0)
- {
- fb->fb_path = strdup ("/dev/graphics/fb0");
- }
- else
- {
- free (fb);
- return NULL;
- }
- }
-
- if (ioctl(fb->fb_fd, FBIOGET_FSCREENINFO, &fb->finfo))
- {
- fprintf (stderr, "error getting fbinfo\n");
- close (fb->fb_fd);
- free (fb->fb_path);
- free (fb);
- return NULL;
- }
-
- if (ioctl(fb->fb_fd, FBIOGET_VSCREENINFO, &fb->vinfo))
- {
- fprintf (stderr, "error getting fbinfo\n");
- close (fb->fb_fd);
- free (fb->fb_path);
- free (fb);
- return NULL;
- }
-
-//fprintf (stderr, "%s\n", fb->fb_path);
- width = fb->width = fb->vinfo.xres;
- height = fb->height = fb->vinfo.yres;
-
- fb->fb_bits = fb->vinfo.bits_per_pixel;
-//fprintf (stderr, "fb bits: %i\n", fb->fb_bits);
- if (fb->fb_bits == 16)
- fb->fb_bits =
- fb->vinfo.red.length +
- fb->vinfo.green.length +
- fb->vinfo.blue.length;
+ CtxSDL *sdl = (CtxSDL*)calloc (sizeof (CtxSDL), 1);
+ CtxTiled *tiled = (void*)sdl;
- else if (fb->fb_bits == 8)
+ ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
+ if (width <= 0 || height <= 0)
{
- unsigned short red[256], green[256], blue[256];
- unsigned short original_red[256];
- unsigned short original_green[256];
- unsigned short original_blue[256];
- struct fb_cmap cmap = {0, 256, red, green, blue, NULL};
- struct fb_cmap original_cmap = {0, 256, original_red, original_green, original_blue, NULL};
- int i;
-
- /* do we really need to restore it ? */
- if (ioctl (fb->fb_fd, FBIOPUTCMAP, &original_cmap) == -1)
- {
- fprintf (stderr, "palette initialization problem %i\n", __LINE__);
- }
-
- for (i = 0; i < 256; i++)
- {
- red[i] = ((( i >> 5) & 0x7) << 5) << 8;
- green[i] = ((( i >> 2) & 0x7) << 5) << 8;
- blue[i] = ((( i >> 0) & 0x3) << 6) << 8;
- }
-
- if (ioctl (fb->fb_fd, FBIOPUTCMAP, &cmap) == -1)
- {
- fprintf (stderr, "palette initialization problem %i\n", __LINE__);
- }
+ width = 1920;
+ height = 1080;
}
-
- fb->fb_bpp = fb->vinfo.bits_per_pixel / 8;
- fb->fb_mapped_size = fb->finfo.smem_len;
-
- fb->fb = mmap (NULL, fb->fb_mapped_size, PROT_READ|PROT_WRITE, MAP_SHARED, fb->fb_fd, 0);
+ sdl->window = SDL_CreateWindow("ctx", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height,
SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE);
+ //sdl->renderer = SDL_CreateRenderer (sdl->window, -1, SDL_RENDERER_SOFTWARE);
+ sdl->renderer = SDL_CreateRenderer (sdl->window, -1, 0);
+ if (!sdl->renderer)
+ {
+ ctx_free (tiled->ctx);
+ free (sdl);
+ return NULL;
}
- if (!fb->fb)
- return NULL;
- fb->scratch_fb = calloc (fb->fb_mapped_size, 1);
- ctx_fb_events = 1;
-
#if CTX_BABL
babl_init ();
#endif
- _ctx_file_get_contents ("/tmp/ctx.icc", &fb_icc, &fb_icc_length);
+ ctx_sdl_events = 1;
+ sdl->texture = SDL_CreateTexture (sdl->renderer,
+ SDL_PIXELFORMAT_ABGR8888,
+ SDL_TEXTUREACCESS_STREAMING,
+ width, height);
- fb->ctx = ctx_new ();
- fb->ctx_copy = ctx_new ();
- fb->width = width;
- fb->height = height;
+ SDL_StartTextInput ();
+ SDL_EnableScreenSaver ();
+ tiled->ctx = ctx_new ();
+ tiled->ctx_copy = ctx_new ();
+ tiled->width = width;
+ tiled->height = height;
+ tiled->cols = 80;
+ tiled->rows = 20;
+ ctx_set_renderer (tiled->ctx, sdl);
+ ctx_set_renderer (tiled->ctx_copy, sdl);
+ ctx_set_texture_cache (tiled->ctx_copy, tiled->ctx);
- ctx_set_renderer (fb->ctx, fb);
- ctx_set_renderer (fb->ctx_copy, fb);
+ tiled->pixels = (uint8_t*)malloc (width * height * 4);
-#if 0
- if (fb_icc_length)
- {
- ctx_colorspace (fb->ctx, CTX_COLOR_SPACE_DEVICE_RGB, fb_icc, fb_icc_length);
- ctx_colorspace (fb->ctx_copy, CTX_COLOR_SPACE_DEVICE_RGB, fb_icc, fb_icc_length);
- }
-#endif
+ ctx_set_size (tiled->ctx, width, height);
+ ctx_set_size (tiled->ctx_copy, width, height);
- ctx_set_size (fb->ctx, width, height);
- ctx_set_size (fb->ctx_copy, width, height);
- fb->flush = (void*)ctx_fb_flush;
- fb->reset = (void*)ctx_fb_reset;
- fb->free = (void*)ctx_fb_free;
- fb->set_clipboard = (void*)ctx_fb_set_clipboard;
- fb->get_clipboard = (void*)ctx_fb_get_clipboard;
+ tiled->flush = (void*)ctx_sdl_flush;
+ tiled->reset = (void*)ctx_sdl_reset;
+ tiled->free = (void*)ctx_sdl_free;
+ tiled->set_clipboard = (void*)ctx_sdl_set_clipboard;
+ tiled->get_clipboard = (void*)ctx_sdl_get_clipboard;
for (int i = 0; i < _ctx_max_threads; i++)
{
- fb->host[i] = ctx_new_for_framebuffer (fb->scratch_fb,
- fb->width/CTX_HASH_COLS, fb->height/CTX_HASH_ROWS,
- fb->width * 4, CTX_FORMAT_RGBA8); // this format
- // is overriden in thread
- ctx_set_texture_source (fb->host[i], fb->ctx);
+ tiled->host[i] = ctx_new_for_framebuffer (tiled->pixels,
+ tiled->width/CTX_HASH_COLS, tiled->height/CTX_HASH_ROWS,
+ tiled->width * 4, CTX_FORMAT_RGBA8);
+ ctx_set_texture_source (tiled->host[i], tiled->ctx);
}
-
- mtx_init (&fb->mtx, mtx_plain);
- cnd_init (&fb->cond);
+ mtx_init (&tiled->mtx, mtx_plain);
+ cnd_init (&tiled->cond);
#define start_thread(no)\
if(_ctx_max_threads>no){ \
static void *args[2]={(void*)no, };\
thrd_t tid;\
- args[1]=fb;\
- thrd_create (&tid, (void*)fb_render_fun, args);\
+ args[1]=sdl;\
+ thrd_create (&tid, (void*)ctx_tiled_render_fun, args);\
}
start_thread(0);
start_thread(1);
@@ -20163,1126 +22823,1031 @@ Ctx *ctx_new_fb (int width, int height, int drm)
start_thread(15);
#undef start_thread
- ctx_flush (fb->ctx);
-
- EvSource *kb = evsource_kb_new ();
- if (kb)
- {
- fb->evsource[fb->evsource_count++] = kb;
- kb->priv = fb;
- }
- EvSource *mice = evsource_mice_new ();
- if (mice)
- {
- fb->evsource[fb->evsource_count++] = mice;
- mice->priv = fb;
- }
-
- fb->vt_active = 1;
- ioctl(0, KDSETMODE, KD_GRAPHICS);
- signal (SIGUSR1, vt_switch_cb);
- signal (SIGUSR2, vt_switch_cb);
- struct vt_stat st;
- if (ioctl (0, VT_GETSTATE, &st) == -1)
- {
- ctx_log ("VT_GET_MODE on vt %i failed\n", fb->vt);
- return NULL;
- }
-
- fb->vt = st.v_active;
-
- struct vt_mode mode;
- mode.mode = VT_PROCESS;
- mode.relsig = SIGUSR1;
- mode.acqsig = SIGUSR2;
- if (ioctl (0, VT_SETMODE, &mode) < 0)
- {
- ctx_log ("VT_SET_MODE on vt %i failed\n", fb->vt);
- return NULL;
- }
-
- return fb->ctx;
+ ctx_flush (tiled->ctx);
+ return tiled->ctx;
#else
return NULL;
#endif
}
#else
-int ctx_renderer_is_fb (Ctx *ctx)
+int ctx_renderer_is_sdl (Ctx *ctx)
{
return 0;
}
#endif
-#endif
#if CTX_EVENTS
#include <fcntl.h>
#include <sys/ioctl.h>
-typedef struct _CtxBraille CtxBraille;
-struct _CtxBraille
-{
- void (*render) (void *braille, CtxCommand *command);
- void (*reset) (void *braille);
- void (*flush) (void *braille);
- char *(*get_clipboard) (void *ctxctx);
- void (*set_clipboard) (void *ctxctx, const char *text);
- void (*free) (void *braille);
- Ctx *ctx;
- int width;
- int height;
- int cols;
- int rows;
- int was_down;
- uint8_t *pixels;
- Ctx *host;
-};
-
-static inline int _ctx_rgba8_manhattan_diff (const uint8_t *a, const uint8_t *b)
-{
- int c;
- int diff = 0;
- for (c = 0; c<3;c++)
- diff += ctx_pow2(a[c]-b[c]);
- return diff;
-}
-
-
-static inline void _ctx_utf8_output_buf (uint8_t *pixels,
- int format,
- int width,
- int height,
- int stride,
- int reverse)
-{
- const char *utf8_gray_scale[]= {" ","░","▒","▓","█","█", NULL};
- int no = 0;
- printf ("\e[?25l"); // cursor off
- switch (format)
- {
- case CTX_FORMAT_GRAY2:
- {
- for (int y= 0; y < height; y++)
- {
- no = y * stride;
- for (int x = 0; x < width; x++)
- {
- int val4= (pixels[no] & (3 << ( (x % 4) *2) ) ) >> ( (x%4) *2);
- int val = (int) CTX_CLAMP (5.0 * val4 / 3.0, 0, 5);
- if (!reverse)
- { val = 5-val; }
- printf ("%s", utf8_gray_scale[val]);
- if ( (x % 4) == 3)
- { no++; }
- }
- printf ("\n");
- }
- }
- break;
- case CTX_FORMAT_GRAY1:
- for (int row = 0; row < height/4; row++)
- {
- for (int col = 0; col < width /2; col++)
- {
- int unicode = 0;
- int bitno = 0;
- for (int x = 0; x < 2; x++)
- for (int y = 0; y < 3; y++)
- {
- int no = (row * 4 + y) * stride + (col*2+x) /8;
- int set = pixels[no] & (1<< ( (col * 2 + x) % 8) );
- if (reverse) { set = !set; }
- if (set)
- { unicode |= (1<< (bitno) ); }
- bitno++;
- }
- {
- int x = 0;
- int y = 3;
- int no = (row * 4 + y) * stride + (col*2+x) /8;
- int setA = pixels[no] & (1<< ( (col * 2 + x) % 8) );
- no = (row * 4 + y) * stride + (col*2+x+1) /8;
- int setB = pixels[no] & (1<< ( (col * 2 + x + 1) % 8) );
- if (reverse) { setA = !setA; }
- if (reverse) { setB = !setB; }
- if (setA != 0 && setB==0)
- { unicode += 0x2840; }
- else if (setA == 0 && setB)
- { unicode += 0x2880; }
- else if ( (setA != 0) && (setB != 0) )
- { unicode += 0x28C0; }
- else
- { unicode += 0x2800; }
- uint8_t utf8[5];
- utf8[ctx_unichar_to_utf8 (unicode, utf8)]=0;
- printf ("%s", utf8);
- }
- }
- printf ("\n");
- }
- break;
- case CTX_FORMAT_RGBA8:
- {
- for (int row = 0; row < height/4; row++)
- {
- for (int col = 0; col < width /2; col++)
- {
- int unicode = 0;
- int bitno = 0;
-
- uint8_t rgba2[4] = {0,0,0,255};
- uint8_t rgba1[4] = {0,0,0,255};
- int rgbasum[4] = {0,};
- int col_count = 0;
-
- for (int xi = 0; xi < 2; xi++)
- for (int yi = 0; yi < 4; yi++)
- {
- int noi = (row * 4 + yi) * stride + (col*2+xi) * 4;
- int diff = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba2);
- if (diff > 32*32)
- {
- for (int c = 0; c < 3; c++)
- {
- rgbasum[c] += pixels[noi+c];
- }
- col_count++;
- }
- }
- if (col_count)
- for (int c = 0; c < 3; c++)
- {
- rgba1[c] = rgbasum[c] / col_count;
- }
-
-
-
- // to determine color .. find two most different
- // colors in set.. and threshold between them..
- // even better dither between them.
- //
- printf ("\e[38;2;%i;%i;%im", rgba1[0], rgba1[1], rgba1[2]);
- //printf ("\e[48;2;%i;%i;%im", rgba2[0], rgba2[1], rgba2[2]);
-
- for (int x = 0; x < 2; x++)
- for (int y = 0; y < 3; y++)
- {
- int no = (row * 4 + y) * stride + (col*2+x) * 4;
-#define CHECK_IS_SET \
- (_ctx_rgba8_manhattan_diff (&pixels[no], rgba1)< \
- _ctx_rgba8_manhattan_diff (&pixels[no], rgba2))
-
- int set = CHECK_IS_SET;
- if (reverse) { set = !set; }
- if (set)
- { unicode |= (1<< (bitno) ); }
- bitno++;
- }
- {
- int x = 0;
- int y = 3;
- int no = (row * 4 + y) * stride + (col*2+x) * 4;
- int setA = CHECK_IS_SET;
- no = (row * 4 + y) * stride + (col*2+x+1) * 4;
- int setB = CHECK_IS_SET;
-#undef CHECK_IS_SET
- if (reverse) { setA = !setA; }
- if (reverse) { setB = !setB; }
- if (setA != 0 && setB==0)
- { unicode += 0x2840; }
- else if (setA == 0 && setB)
- { unicode += 0x2880; }
- else if ( (setA != 0) && (setB != 0) )
- { unicode += 0x28C0; }
- else
- { unicode += 0x2800; }
- uint8_t utf8[5];
- utf8[ctx_unichar_to_utf8 (unicode, utf8)]=0;
- printf ("%s", utf8);
- }
- }
- printf ("\n\r");
- }
- printf ("\e[38;2;%i;%i;%im", 255,255,255);
- }
- break;
-
- case CTX_FORMAT_GRAY4:
- {
- int no = 0;
- for (int y= 0; y < height; y++)
- {
- no = y * stride;
- for (int x = 0; x < width; x++)
- {
- int val = (pixels[no] & (15 << ( (x % 2) *4) ) ) >> ( (x%2) *4);
- val = val * 6 / 16;
- if (reverse) { val = 5-val; }
- val = CTX_CLAMP (val, 0, 4);
- printf ("%s", utf8_gray_scale[val]);
- if (x % 2 == 1)
- { no++; }
- }
- printf ("\n");
- }
- }
- break;
- case CTX_FORMAT_CMYK8:
- {
- for (int c = 0; c < 4; c++)
- {
- int no = 0;
- for (int y= 0; y < height; y++)
- {
- for (int x = 0; x < width; x++, no+=4)
- {
- int val = (int) CTX_CLAMP (pixels[no+c]/255.0*6.0, 0, 5);
- if (reverse)
- { val = 5-val; }
- printf ("%s", utf8_gray_scale[val]);
- }
- printf ("\n");
- }
- }
- }
- break;
- case CTX_FORMAT_RGB8:
- {
- for (int c = 0; c < 3; c++)
- {
- int no = 0;
- for (int y= 0; y < height; y++)
- {
- for (int x = 0; x < width; x++, no+=3)
- {
- int val = (int) CTX_CLAMP (pixels[no+c]/255.0*6.0, 0, 5);
- if (reverse)
- { val = 5-val; }
- printf ("%s", utf8_gray_scale[val]);
- }
- printf ("\n");
- }
- }
- }
- break;
- case CTX_FORMAT_CMYKAF:
- {
- for (int c = 0; c < 5; c++)
- {
- int no = 0;
- for (int y= 0; y < height; y++)
- {
- for (int x = 0; x < width; x++, no+=5)
- {
- int val = (int) CTX_CLAMP ( (pixels[no+c]*6.0), 0, 5);
- if (reverse)
- { val = 5-val; }
- printf ("%s", utf8_gray_scale[val]);
- }
- printf ("\n");
- }
- }
- }
- }
- printf ("\e[?25h"); // cursor on
-}
-
-inline static void ctx_braille_flush (CtxBraille *braille)
+typedef struct CtxTermCell
{
- int width = braille->width;
- int height = braille->height;
- ctx_render_ctx (braille->ctx, braille->host);
- printf ("\e[H");
- _ctx_utf8_output_buf (braille->pixels,
- CTX_FORMAT_RGBA8,
- width, height, width * 4, 0);
-#if CTX_BRAILLE_TEXT
- CtxRasterizer *rasterizer = (CtxRasterizer*)(braille->host->renderer);
- // XXX instead sort and inject along with braille
- for (CtxList *l = rasterizer->glyphs; l; l = l->next)
- {
- CtxTermGlyph *glyph = l->data;
- printf ("\e[0m\e[%i;%iH%c", glyph->row, glyph->col, glyph->unichar);
- free (glyph);
- }
- while (rasterizer->glyphs)
- ctx_list_remove (&rasterizer->glyphs, rasterizer->glyphs->data);
-#endif
-}
+ char utf8[5];
+ uint8_t fg[4];
+ uint8_t bg[4];
-void ctx_braille_free (CtxBraille *braille)
-{
- nc_at_exit ();
- free (braille->pixels);
- ctx_free (braille->host);
- free (braille);
- /* we're not destoring the ctx member, this is function is called in ctx' teardown */
-}
+ char prev_utf8[5];
+ uint8_t prev_fg[4];
+ uint8_t prev_bg[4];
+} CtxTermCell;
-int ctx_renderer_is_braille (Ctx *ctx)
+typedef struct CtxTermLine
{
- if (ctx->renderer &&
- ctx->renderer->free == (void*)ctx_braille_free)
- return 1;
- return 0;
-}
+ CtxTermCell *cells;
+ int maxcol;
+ int size;
+} CtxTermLine;
-Ctx *ctx_new_braille (int width, int height)
+typedef enum
{
- Ctx *ctx = ctx_new ();
-#if CTX_RASTERIZER
- fprintf (stdout, "\e[?1049h");
- CtxBraille *braille = (CtxBraille*)calloc (sizeof (CtxBraille), 1);
- int maxwidth = ctx_terminal_cols () * 2;
- int maxheight = (ctx_terminal_rows ()-1) * 4;
- if (width <= 0 || height <= 0)
- {
- width = maxwidth;
- height = maxheight;
- }
- if (width > maxwidth) width = maxwidth;
- if (height > maxheight) height = maxheight;
- braille->ctx = ctx;
- braille->width = width;
- braille->height = height;
- braille->cols = (width + 1) / 2;
- braille->rows = (height + 3) / 4;
- braille->pixels = (uint8_t*)malloc (width * height * 4);
- braille->host = ctx_new_for_framebuffer (braille->pixels,
- width, height,
- width * 4, CTX_FORMAT_RGBA8);
-#if CTX_BRAILLE_TEXT
- ((CtxRasterizer*)braille->host->renderer)->term_glyphs=1;
-#endif
- _ctx_mouse (ctx, NC_MOUSE_DRAG);
- ctx_set_renderer (ctx, braille);
- ctx_set_size (ctx, width, height);
- ctx_font_size (ctx, 4.0f);
- braille->flush = (void(*)(void*))ctx_braille_flush;
- braille->free = (void(*)(void*))ctx_braille_free;
-#endif
-
-
- return ctx;
-}
-
-#endif
-
-#if CTX_SDL
-#include <threads.h>
+ CTX_TERM_ASCII,
+ CTX_TERM_ASCII_MONO,
+ CTX_TERM_SEXTANT,
+ CTX_TERM_BRAILLE_MONO,
+ CTX_TERM_BRAILLE,
+ CTX_TERM_QUARTER,
+} CtxTermMode;
-typedef struct _CtxSDL CtxSDL;
-struct _CtxSDL
+typedef struct _CtxTerm CtxTerm;
+struct _CtxTerm
{
- void (*render) (void *braille, CtxCommand *command);
- void (*reset) (void *braille);
- void (*flush) (void *braille);
+ void (*render) (void *term, CtxCommand *command);
+ void (*reset) (void *term);
+ void (*flush) (void *term);
char *(*get_clipboard) (void *ctxctx);
void (*set_clipboard) (void *ctxctx, const char *text);
- void (*free) (void *braille);
- Ctx *ctx;
- int width;
- int height;
- int cols;
- int rows;
- int was_down;
- uint8_t *pixels;
- Ctx *ctx_copy;
- Ctx *host[CTX_MAX_THREADS];
- CtxAntialias antialias;
- int quit;
- _Atomic int thread_quit;
- int shown_frame;
- int render_frame;
- int rendered_frame[CTX_MAX_THREADS];
- int frame;
- int min_col; // hasher cols and rows
- int min_row;
- int max_col;
- int max_row;
- uint8_t hashes[CTX_HASH_ROWS * CTX_HASH_COLS * 20];
- int8_t tile_affinity[CTX_HASH_ROWS * CTX_HASH_COLS]; // which render thread no is
- // responsible for a tile
- //
-
- int pointer_down[3];
- int key_balance;
- int key_repeat;
- int lctrl;
- int lalt;
- int rctrl;
-
- CtxCursor shown_cursor;
-
- /* where we diverge from fb*/
- SDL_Window *window;
- SDL_Renderer *renderer;
- SDL_Texture *texture;
-
- cnd_t cond;
- mtx_t mtx;
+ void (*free) (void *term);
+ Ctx *ctx;
+ int width;
+ int height;
+ int cols;
+ int rows;
+ int was_down;
+
+ uint8_t *pixels;
+
+ Ctx *host;
+ CtxList *lines;
+ CtxTermMode mode;
};
-#include "stb_image_write.h"
-
-void ctx_screenshot (Ctx *ctx, const char *output_path)
-{
-#if CTX_SCREENSHOT
- int valid = 0;
- CtxSDL *sdl = (void*)ctx->renderer;
-
- if (ctx_renderer_is_sdl (ctx)) valid = 1;
-#if CTX_FB
- if (ctx_renderer_is_fb (ctx)) valid = 1;
-#endif
-
- if (!valid)
- return;
-
-#if CTX_FB
- for (int i = 0; i < sdl->width * sdl->height; i++)
- {
- int tmp = sdl->pixels[i*4];
- sdl->pixels[i*4] = sdl->pixels[i*4 + 2];
- sdl->pixels[i*4 + 2] = tmp;
- }
-#endif
-
- stbi_write_png (output_path, sdl->width, sdl->height, 4, sdl->pixels, sdl->width*4);
+static int ctx_term_ch = 8;
+static int ctx_term_cw = 8;
-#if CTX_FB
- for (int i = 0; i < sdl->width * sdl->height; i++)
+void ctx_term_set (CtxTerm *term,
+ int col, int row, const char *utf8,
+ uint8_t *fg, uint8_t *bg)
+{
+ if (col < 1 || row < 1 || col > term->cols || row > term->rows) return;
+ while (ctx_list_length (term->lines) < row)
{
- int tmp = sdl->pixels[i*4];
- sdl->pixels[i*4] = sdl->pixels[i*4 + 2];
- sdl->pixels[i*4 + 2] = tmp;
+ ctx_list_append (&term->lines, calloc (sizeof (CtxTermLine), 1));
}
-#endif
-#endif
+ 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);
+ memset (&line->cells[line->size], 0, sizeof (CtxTermCell) * (new_size - line->size) );
+ line->size = new_size;
+ }
+ if (col > line->maxcol) line->maxcol = col;
+ strncpy (line->cells[col-1].utf8, (char*)utf8, 4);
+ memcpy (line->cells[col-1].fg, fg, 4);
+ memcpy (line->cells[col-1].bg, bg, 4);
}
-void ctx_sdl_set_title (void *self, const char *new_title)
+static int _ctx_term256 = 0; // XXX TODO implement autodetect for this
+static long _ctx_curfg = -1;
+static long _ctx_curbg = -1;
+
+static long ctx_rgb_to_long (int r,int g, int b)
{
- CtxSDL *sdl = self;
- SDL_SetWindowTitle (sdl->window, new_title);
+ return r * 256 * 256 + g * 256 + b;
}
-static inline int
-sdl_render_threads_done (CtxSDL *sdl)
+
+static void ctx_term_set_fg (int red, int green, int blue)
{
- int sum = 0;
- for (int i = 0; i < _ctx_max_threads; i++)
+ long lc = ctx_rgb_to_long (red, green, blue);
+ if (lc == _ctx_curfg)
+ return;
+ _ctx_curfg=lc;
+ if (_ctx_term256 == 0)
{
- if (sdl->rendered_frame[i] == sdl->render_frame)
- sum ++;
+ printf("\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;
+ if (gray > 23) gray = 23;
+
+ if (r > 5) r = 5;
+ if (g > 5) g = 5;
+ if (b > 5) b = 5;
+
+ 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);
+ }
+ else
+ printf("\e[38;5;%im", 16 + r * 6 * 6 + g * 6 + b);
}
- return sum;
}
-static void ctx_sdl_show_frame (CtxSDL *sdl, int block)
+static void ctx_term_set_bg(int red, int green, int blue)
{
- if (sdl->shown_cursor != sdl->ctx->cursor)
+ long lc = ctx_rgb_to_long (red, green, blue);
+//if (lc == _ctx_curbg)
+// return;
+ _ctx_curbg=lc;
+ if (_ctx_term256 == 0)
{
- sdl->shown_cursor = sdl->ctx->cursor;
- SDL_Cursor *new_cursor = NULL;
- switch (sdl->shown_cursor)
- {
- case CTX_CURSOR_UNSET: // XXX: document how this differs from none
- // perhaps falling back to arrow?
- break;
- case CTX_CURSOR_NONE:
- new_cursor = NULL;
- break;
- case CTX_CURSOR_ARROW:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
- break;
- case CTX_CURSOR_CROSSHAIR:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
- break;
- case CTX_CURSOR_WAIT:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
- break;
- case CTX_CURSOR_HAND:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
- break;
- case CTX_CURSOR_IBEAM:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
- break;
- case CTX_CURSOR_MOVE:
- case CTX_CURSOR_RESIZE_ALL:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
- break;
- case CTX_CURSOR_RESIZE_N:
- case CTX_CURSOR_RESIZE_S:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
- break;
- case CTX_CURSOR_RESIZE_E:
- case CTX_CURSOR_RESIZE_W:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
- break;
- case CTX_CURSOR_RESIZE_NE:
- case CTX_CURSOR_RESIZE_SW:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
- break;
- case CTX_CURSOR_RESIZE_NW:
- case CTX_CURSOR_RESIZE_SE:
- new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
- break;
- }
- if (new_cursor)
+ printf("\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;
+ if (gray > 23) gray = 23;
+
+ if (r > 5) r = 5;
+ if (g > 5) g = 5;
+ if (b > 5) b = 5;
+
+ if (((int)(r/1.66)== (int)(g/1.66)) && ((int)(g/1.66) == ((int)(b/1.66))))
{
- SDL_Cursor *old_cursor = SDL_GetCursor();
- SDL_SetCursor (new_cursor);
- SDL_ShowCursor (1);
- if (old_cursor)
- SDL_FreeCursor (old_cursor);
+ printf("\e[48;5;%im", 16 + 216 + gray);
}
else
- {
- SDL_ShowCursor (0);
- }
+ printf("\e[48;5;%im", 16 + r * 6 * 6 + g * 6 + b);
}
+}
- if (sdl->shown_frame == sdl->render_frame)
- {
- return;
- }
+static int _ctx_term_force_full = 0;
- if (block)
+void ctx_term_scanout (CtxTerm *term)
+{
+ int row = 1;
+ printf ("\e[H");
+// printf ("\e[?25l");
+ printf ("\e[0m");
+ for (CtxList *l = term->lines; l; l = l->next)
{
- int count = 0;
- while (sdl_render_threads_done (sdl) != _ctx_max_threads)
+ CtxTermLine *line = l->data;
+ for (int col = 1; col <= line->maxcol; col++)
{
- usleep (50);
- count ++;
- if (count > 2000)
+ CtxTermCell *cell = &line->cells[col-1];
+
+ if (strcmp(cell->utf8, cell->prev_utf8) ||
+ memcmp(cell->fg, cell->prev_fg, 3) ||
+ memcmp(cell->bg, cell->prev_bg, 3) || _ctx_term_force_full)
{
- sdl->shown_frame = sdl->render_frame;
- return;
+ ctx_term_set_fg (cell->fg[0], cell->fg[1], cell->fg[2]);
+ ctx_term_set_bg (cell->bg[0], cell->bg[1], cell->bg[2]);
+ printf ("%s", cell->utf8);
+ }
+ else
+ {
+ // TODO: accumulate succesive such, and compress them
+ // into one
+ printf ("\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");
+ row ++;
}
- else
- {
- if (sdl_render_threads_done (sdl) != _ctx_max_threads)
- return;
- }
-
- if (sdl->min_row == 100)
- {
- }
- else
- {
-#if 0
- int x = sdl->min_col * sdl->width/CTX_HASH_COLS;
- int y = sdl->min_row * sdl->height/CTX_HASH_ROWS;
- int x1 = (sdl->max_col+1) * sdl->width/CTX_HASH_COLS;
- int y1 = (sdl->max_row+1) * sdl->height/CTX_HASH_ROWS;
- int width = x1 - x;
- int height = y1 - y;
-#endif
- sdl->min_row = 100;
- sdl->max_row = 0;
- sdl->min_col = 100;
- sdl->max_col = 0;
+ printf ("\e[0m");
+ //printf ("\e[?25h");
+ //
+}
- //SDL_Rect r = {x, y, width, height};
- SDL_UpdateTexture (sdl->texture, NULL, //&r,
- (void*)sdl->pixels,
- //(void*)(sdl->pixels + y * sdl->width * 4 + x * 4),
-
- sdl->width * sizeof (Uint32));
- SDL_RenderClear (sdl->renderer);
- SDL_RenderCopy (sdl->renderer, sdl->texture, NULL, NULL);
- SDL_RenderPresent (sdl->renderer);
- }
+// xx
+// xx
+// xx
+//
- sdl->shown_frame = sdl->render_frame;
+static inline int _ctx_rgba8_manhattan_diff (const uint8_t *a, const uint8_t *b)
+{
+ int c;
+ int diff = 0;
+ for (c = 0; c<3;c++)
+ diff += ctx_pow2(a[c]-b[c]);
+ return sqrtf(diff);
+ return diff;
}
-int ctx_sdl_consume_events (Ctx *ctx)
+static void ctx_term_output_buf_half (uint8_t *pixels,
+ int width,
+ int height,
+ CtxTerm *term)
{
- CtxSDL *sdl = (void*)ctx->renderer;
- SDL_Event event;
- int got_events = 0;
-
- ctx_sdl_show_frame (sdl, 0);
+ int stride = width * 4;
+ const char *sextants[]={
+ " ","▘","▝","▀","▖","▌", "▞", "▛", "▗", "▚", "▐", "▜","▄","▙","▟","█",
- while (SDL_PollEvent (&event))
- {
- got_events ++;
- switch (event.type)
+ };
+ for (int row = 0; row < height/2; row++)
{
- case SDL_MOUSEBUTTONDOWN:
- SDL_CaptureMouse (1);
- ctx_pointer_press (ctx, event.button.x, event.button.y, event.button.button, 0);
- break;
- case SDL_MOUSEBUTTONUP:
- SDL_CaptureMouse (0);
- ctx_pointer_release (ctx, event.button.x, event.button.y, event.button.button, 0);
- break;
- case SDL_MOUSEMOTION:
- // XXX : look at mask and generate motion for each pressed
- // button
- ctx_pointer_motion (ctx, event.motion.x, event.motion.y, 1, 0);
- break;
- case SDL_FINGERMOTION:
- ctx_pointer_motion (ctx, event.tfinger.x * sdl->width, event.tfinger.y * sdl->height,
- (event.tfinger.fingerId%10) + 4, 0);
- break;
- case SDL_FINGERDOWN:
- {
- static int fdowns = 0;
- fdowns ++;
- if (fdowns > 1) // the very first finger down from SDL seems to be
- // mirrored as mouse events, later ones not - at
- // least under wayland
+ for (int col = 0; col < width-3; col++)
{
- ctx_pointer_press (ctx, event.tfinger.x *sdl->width, event.tfinger.y * sdl->height,
- (event.tfinger.fingerId%10) + 4, 0);
- }
+ int unicode = 0;
+ int bitno = 0;
+ uint8_t rgba[2][4] = {
+ {255,255,255,0},
+ {0,0,0,0}};
+ int i = 0;
+
+ int rgbasum[2][4] = {0,};
+ int sumcount[2];
+
+ int curdiff = 0;
+ /* first find starting point colors */
+ for (int yi = 0; yi < ctx_term_ch; yi++)
+ for (int xi = 0; xi < ctx_term_cw; xi++, i++)
+ {
+ int noi = (row * ctx_term_ch + yi) * stride + (col*ctx_term_cw+xi) * 4;
+
+ if (rgba[0][3] == 0)
+ {
+ for (int c = 0; c < 3; c++)
+ rgba[0][c] = pixels[noi + c];
+ rgba[0][3] = 255; // used only as mark of in-use
+ }
+ else
+ {
+ int diff = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[0]);
+ if (diff > curdiff)
+ {
+ curdiff = diff;
+ for (int c = 0; c < 3; c++)
+ rgba[1][c] = pixels[noi + c];
+ }
+ }
+
+ }
+
+ for (int iters = 0; iters < 1; iters++)
+ {
+ i= 0;
+ for (int i = 0; i < 4; i ++)
+ rgbasum[0][i] = rgbasum[1][i]=0;
+ sumcount[0] = sumcount[1] = 0;
+
+ for (int yi = 0; yi < ctx_term_ch; yi++)
+ for (int xi = 0; xi < ctx_term_cw; xi++, i++)
+ {
+ int noi = (row * ctx_term_ch + yi) * stride + (col*ctx_term_cw+xi) * 4;
+
+ int diff1 = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[0]);
+ int diff2 = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[1]);
+ int cluster = 0;
+ if (diff1 <= diff2)
+ cluster = 0;
+ else
+ cluster = 1;
+ sumcount[cluster]++;
+ for (int c = 0; c < 3; c++)
+ rgbasum[cluster][c] += pixels[noi+c];
+ }
+
+
+ if (sumcount[0])
+ for (int c = 0; c < 3; c++)
+ {
+ rgba[0][c] = rgbasum[0][c] / sumcount[0];
+ }
+ if (sumcount[1])
+ for (int c = 0; c < 3; c++)
+ {
+ rgba[1][c] = rgbasum[1][c] / sumcount[1];
+ }
+ }
+
+ int pixels_set = 0;
+ for (int y = 0; y < ctx_term_ch; y++)
+ for (int x = 0; x < ctx_term_cw; x++)
+ {
+ int no = (row * ctx_term_ch + y) * stride + (col*ctx_term_cw+x) * 4;
+#define CHECK_IS_SET \
+ (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
+ _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
+
+ int set = CHECK_IS_SET;
+#undef CHECK_IS_SET
+ if (set)
+ { unicode |= (1<< (bitno) );
+ pixels_set ++;
+ }
+ bitno++;
+ }
+ if (pixels_set == 4)
+ ctx_term_set (term, col +1, row + 1, " ",
+ rgba[1], rgba[0]);
+ else
+ ctx_term_set (term, col +1, row + 1, sextants[unicode],
+ rgba[0], rgba[1]);
}
- break;
- case SDL_FINGERUP:
- ctx_pointer_release (ctx, event.tfinger.x * sdl->width, event.tfinger.y * sdl->height,
- (event.tfinger.fingerId%10) + 4, 0);
- break;
- case SDL_KEYUP:
+ }
+}
+
+void ctx_term_find_color_pair (CtxTerm *term, int x0, int y0, int w, int h,
+ uint8_t rgba[2][4])
+ //uint8_t *rgba0, uint8_t *rgba1)
+{
+int curdiff = 0;
+int stride = term->width * 4;
+uint8_t *pixels = term->pixels;
+/* first find starting point colors */
+for (int y = y0; y < y0 + h; y++)
+ for (int x = x0; x < x0 + w; x++)
+ {
+ int noi = (y) * stride + (x) * 4;
+
+ if (rgba[0][3] == 0)
{
- sdl->key_balance --;
- switch (event.key.keysym.sym)
- {
- case SDLK_LCTRL: sdl->lctrl = 0; break;
- case SDLK_RCTRL: sdl->rctrl = 0; break;
- case SDLK_LALT: sdl->lalt = 0; break;
- }
+ for (int c = 0; c < 3; c++)
+ rgba[0][c] = pixels[noi + c];
+ rgba[0][3] = 255; // used only as mark of in-use
}
- break;
-#if 1
- case SDL_TEXTINPUT:
- // if (!active)
- // break;
- if (!sdl->lctrl && !sdl->rctrl && !sdl->lalt
- //&& ( (vt && vt_keyrepeat (vt) ) || (key_repeat==0) )
- )
+ else
+ {
+ int diff = _ctx_rgba8_manhattan_diff (&pixels[noi], &rgba[0][0]);
+ if (diff > curdiff)
{
- const char *name = event.text.text;
- if (!strcmp (name, " ") ) { name = "space"; }
- ctx_key_press (ctx, 0, name, 0);
- //got_event = 1;
+ curdiff = diff;
+ for (int c = 0; c < 3; c++)
+ rgba[1][c] = pixels[noi + c];
}
- break;
-#endif
- case SDL_KEYDOWN:
- {
- char buf[32] = "";
- char *name = buf;
- if (!event.key.repeat)
+ }
+ }
+ int rgbasum[2][4] = {0,};
+ int sumcount[2];
+
+ for (int iters = 0; iters < 1; iters++)
+ {
+ for (int i = 0; i < 4; i ++)
+ rgbasum[0][i] = rgbasum[1][i]=0;
+ sumcount[0] = sumcount[1] = 0;
+
+ for (int y = y0; y < y0 + h; y++)
+ for (int x = x0; x < x0 + w; x++)
+ {
+ int noi = (y) * stride + (x) * 4;
+
+ int diff1 = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[0]);
+ int diff2 = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[1]);
+ int cluster = 0;
+ if (diff1 <= diff2)
+ cluster = 0;
+ else
+ cluster = 1;
+ sumcount[cluster]++;
+ for (int c = 0; c < 3; c++)
+ rgbasum[cluster][c] += pixels[noi+c];
+ }
+
+
+ if (sumcount[0])
+ for (int c = 0; c < 3; c++)
{
- sdl->key_balance ++;
- sdl->key_repeat = 0;
+ rgba[0][c] = rgbasum[0][c] / sumcount[0];
}
- else
+ if (sumcount[1])
+ for (int c = 0; c < 3; c++)
{
- sdl->key_repeat ++;
+ rgba[1][c] = rgbasum[1][c] / sumcount[1];
}
- buf[ctx_unichar_to_utf8 (event.key.keysym.sym, (void*)buf)]=0;
- switch (event.key.keysym.sym)
- {
- case SDLK_LCTRL: sdl->lctrl = 1; break;
- case SDLK_LALT: sdl->lalt = 1; break;
- case SDLK_RCTRL: sdl->rctrl = 1; break;
- case SDLK_F1: name = "F1"; break;
- case SDLK_F2: name = "F2"; break;
- case SDLK_F3: name = "F3"; break;
- case SDLK_F4: name = "F4"; break;
- case SDLK_F5: name = "F5"; break;
- case SDLK_F6: name = "F6"; break;
- case SDLK_F7: name = "F7"; break;
- case SDLK_F8: name = "F8"; break;
- case SDLK_F9: name = "F9"; break;
- case SDLK_F10: name = "F10"; break;
- case SDLK_F11: name = "F11"; break;
- case SDLK_F12: name = "F12"; break;
- case SDLK_ESCAPE: name = "escape"; break;
- case SDLK_DOWN: name = "down"; break;
- case SDLK_LEFT: name = "left"; break;
- case SDLK_UP: name = "up"; break;
- case SDLK_RIGHT: name = "right"; break;
- case SDLK_BACKSPACE: name = "backspace"; break;
- case SDLK_SPACE: name = "space"; break;
- case SDLK_TAB: name = "tab"; break;
- case SDLK_DELETE: name = "delete"; break;
- case SDLK_INSERT: name = "insert"; break;
- case SDLK_RETURN:
- //if (key_repeat == 0) // return never should repeat
- name = "return"; // on a DEC like terminal
- break;
- case SDLK_HOME: name = "home"; break;
- case SDLK_END: name = "end"; break;
- case SDLK_PAGEDOWN: name = "page-down"; break;
- case SDLK_PAGEUP: name = "page-up"; break;
- default:
- ;
}
- if (strlen (name)
- &&(event.key.keysym.mod & (KMOD_CTRL) ||
- event.key.keysym.mod & (KMOD_ALT) ||
- strlen (name) >= 2))
- {
- if (event.key.keysym.mod & (KMOD_CTRL) )
+
+}
+
+
+
+static void ctx_term_output_buf_quarter (uint8_t *pixels,
+ int width,
+ int height,
+ CtxTerm *term)
+{
+ int stride = width * 4;
+ const char *sextants[]={
+ " ","▘","▝","▀","▖","▌", "▞", "▛", "▗", "▚", "▐", "▜","▄","▙","▟","█"
+
+ };
+ for (int row = 0; row < height/ctx_term_ch; row++)
+ {
+ for (int col = 0; col < width /ctx_term_cw; col++)
+ {
+ int unicode = 0;
+ int bitno = 0;
+ uint8_t rgba[2][4] = {
+ {255,255,255,0},
+ {0,0,0,0}};
+ ctx_term_find_color_pair (term, col * ctx_term_cw,
+ row * ctx_term_ch,
+ ctx_term_cw,
+ ctx_term_ch, rgba);
+
+ int pixels_set = 0;
+ for (int y = 0; y < 2; y++)
+ for (int x = 0; x < ctx_term_cw; x++)
{
- static char buf[64] = "";
- sprintf (buf, "control-%s", name);
- name = buf;
+ int no = (row * ctx_term_ch + y) * stride + (col*ctx_term_cw+x) * 4;
+#define CHECK_IS_SET \
+ (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
+ _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
+
+ int set = CHECK_IS_SET;
+#undef CHECK_IS_SET
+ if (set)
+ { unicode |= (1<< (bitno) );
+ pixels_set ++;
+ }
+ bitno++;
}
- if (event.key.keysym.mod & (KMOD_ALT) )
+ if (pixels_set == 4)
+ ctx_term_set (term, col +1, row + 1, " ",
+ rgba[1], rgba[0]);
+ else
+ ctx_term_set (term, col +1, row + 1, sextants[unicode],
+ rgba[0], rgba[1]);
+ }
+ }
+}
+
+
+static void ctx_term_output_buf_sextant (uint8_t *pixels,
+ int width,
+ int height,
+ CtxTerm *term)
+{
+ int stride = width * 4;
+
+ const char *sextants[]={
+ "
","🬀","🬁","🬂","🬃","🬄","🬅","🬆","🬇","🬈","🬉","🬊","🬋","🬌","🬍","🬎","🬏","🬐","🬑","🬒","🬓","▌","🬔","🬕","🬖","🬗","🬘","🬙","🬚","🬛","🬜","🬝","🬞","🬟","🬠","🬡","🬢","🬣","🬤","🬥","🬦","🬧","▐","🬨","🬩","🬪","🬫","🬬","🬭","🬮","🬯","🬰","🬱","🬲","🬳","🬴","🬵","🬶","🬷","🬸","🬹","🬺","🬻","█"
+ };
+
+ for (int row = 0; row < height/ctx_term_ch; row++)
+ {
+ for (int col = 0; col < width /ctx_term_cw; col++)
+ {
+ int unicode = 0;
+ int bitno = 0;
+ uint8_t rgba[2][4] = {
+ {255,255,255,0},
+ {0,0,0,0}};
+
+ ctx_term_find_color_pair (term, col * ctx_term_cw,
+ row * ctx_term_ch,
+ ctx_term_cw,
+ ctx_term_ch, rgba);
+
+ int pixels_set = 0;
+ for (int y = 0; y < ctx_term_ch; y++)
+ for (int x = 0; x < ctx_term_cw; x++)
{
- static char buf[128] = "";
- sprintf (buf, "alt-%s", name);
- name = buf;
+ int no = (row * ctx_term_ch + y) * stride + (col*ctx_term_cw+x) * 4;
+#define CHECK_IS_SET \
+ (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
+ _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
+
+ int set = CHECK_IS_SET;
+#undef CHECK_IS_SET
+ if (set)
+ { unicode |= (1<< (bitno) );
+ pixels_set ++;
+ }
+ bitno++;
}
- if (event.key.keysym.mod & (KMOD_SHIFT) )
+
+ if (pixels_set == 6)
+ ctx_term_set (term, col +1, row + 1, " ",
+ rgba[1], rgba[0]);
+ else
+ ctx_term_set (term, col +1, row + 1, sextants[unicode], rgba[0], rgba[1]);
+ }
+ }
+}
+
+static void ctx_term_output_buf_ascii (uint8_t *pixels,
+ int width,
+ int height,
+ CtxTerm *term,
+ int mono)
+{
+ /* this is a crude ascii-mode built on a quick mapping of sexels to ascii */
+ int stride = width * 4;
+ const char *sextants[]={
+ " ","`","'","^","🬃","`","~","\"","-","\"","'","\"","-","\"","~","^",",",";",
+ "=","/","i","[","p","P","z",")","/","7","f",">","/","F",",","\\",":",":",
+ "\\","\\","(","T","j","T","]","?","s","\\","<","q","_","=","=","=","c","L",
+ "Q","C","a","b","J","]","m","b","d","@"
+ };
+ uint8_t black[4] = {0,0,0,255};
+ for (int row = 0; row < height/ctx_term_ch; row++)
+ {
+ for (int col = 0; col < width /ctx_term_cw; col++)
+ {
+ int unicode = 0;
+ int bitno = 0;
+ uint8_t rgba[2][4] = {
+ {255,255,255,0},
+ {0,0,0,0}};
+
+ ctx_term_find_color_pair (term, col * ctx_term_cw,
+ row * ctx_term_ch,
+ ctx_term_cw,
+ ctx_term_ch, rgba);
+
+
+ if (_ctx_rgba8_manhattan_diff (black, rgba[1]) >
+ _ctx_rgba8_manhattan_diff (black, rgba[0]))
+ {
+ for (int c = 0; c < 4; c ++)
+ {
+ int tmp = rgba[0][c];
+ rgba[0][c] = rgba[1][c];
+ rgba[1][c] = tmp;
+ }
+ }
+ if (mono)
+ {
+ rgba[1][0] = 0;
+ rgba[1][1] = 0;
+ rgba[1][2] = 0;
+ }
+
+
+ int brightest_dark_diff = _ctx_rgba8_manhattan_diff (black, rgba[0]);
+
+ int pixels_set = 0;
+ for (int y = 0; y < ctx_term_ch; y++)
+ for (int x = 0; x < ctx_term_cw; x++)
{
- static char buf[196] = "";
- sprintf (buf, "shift-%s", name);
- name = buf;
+ int no = (row * ctx_term_ch + y) * stride + (col*ctx_term_cw+x) * 4;
+#define CHECK_IS_SET \
+ (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
+ _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
+
+ int set = CHECK_IS_SET;
+#undef CHECK_IS_SET
+ if (set)
+ { unicode |= (1<< (bitno) );
+ pixels_set ++;
+ }
+ bitno++;
}
- if (strcmp (name, "space"))
+
+
+ if (pixels_set == 6 && brightest_dark_diff < 40)
+ ctx_term_set (term, col +1, row + 1, " ",
+ rgba[1], rgba[0]);
+ else
+ ctx_term_set (term, col +1, row + 1, sextants[unicode],
+ rgba[0], rgba[1]);
+ }
+ }
+}
+
+static void ctx_term_output_buf_braille (uint8_t *pixels,
+ int width,
+ int height,
+ CtxTerm *term,
+ int mono)
+{
+ int reverse = 0;
+ int stride = width * 4;
+ uint8_t black[4] = {0,0,0,255};
+ for (int row = 0; row < height/ctx_term_ch; row++)
+ {
+ for (int col = 0; col < width /ctx_term_cw; col++)
+ {
+ int unicode = 0;
+ int bitno = 0;
+ uint8_t rgba[2][4] = {
+ {255,255,255,0},
+ {0,0,0,0}};
+
+ ctx_term_find_color_pair (term, col * ctx_term_cw,
+ row * ctx_term_ch,
+ ctx_term_cw,
+ ctx_term_ch, rgba);
+
+
+ /* make darkest consistently be background */
+ if (_ctx_rgba8_manhattan_diff (black, rgba[1]) >
+ _ctx_rgba8_manhattan_diff (black, rgba[0]))
+ {
+ for (int c = 0; c < 4; c ++)
+ {
+ int tmp = rgba[0][c];
+ rgba[0][c] = rgba[1][c];
+ rgba[1][c] = tmp;
+ }
+ }
+ if (mono)
+ {
+ rgba[1][0] = 0;
+ rgba[1][1] = 0;
+ rgba[1][2] = 0;
+ }
+
+ int pixels_set = 0;
+ for (int x = 0; x < 2; x++)
+ for (int y = 0; y < 3; y++)
{
- ctx_key_press (ctx, 0, name, 0);
+ int no = (row * 4 + y) * stride + (col*2+x) * 4;
+#define CHECK_IS_SET \
+ (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
+ _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
+
+ int set = CHECK_IS_SET;
+ if (reverse) { set = !set; }
+ if (set)
+ { unicode |= (1<< (bitno) );
+ pixels_set ++;
+ }
+ bitno++;
}
- }
- else
{
+ int x = 0;
+ int y = 3;
+ int no = (row * 4 + y) * stride + (col*2+x) * 4;
+ int setA = CHECK_IS_SET;
+ no = (row * 4 + y) * stride + (col*2+x+1) * 4;
+ int setB = CHECK_IS_SET;
+
+ pixels_set += setA;
+ pixels_set += setB;
+#undef CHECK_IS_SET
+ if (reverse) { setA = !setA; }
+ if (reverse) { setB = !setB; }
+ if (setA != 0 && setB==0)
+ { unicode += 0x2840; }
+ else if (setA == 0 && setB)
+ { unicode += 0x2880; }
+ else if ( (setA != 0) && (setB != 0) )
+ { unicode += 0x28C0; }
+ else
+ { unicode += 0x2800; }
+ char utf8[5];
+ utf8[ctx_unichar_to_utf8 (unicode, (uint8_t*)utf8)]=0;
+
#if 0
- ctx_key_press (ctx, 0, buf, 0);
+ if (pixels_set == 8)
+ {
+ if (rgba[0][0] < 32 && rgba[0][1] < 32 && rgba[0][2] < 32)
+ {
+ ctx_term_set (term, col +1, row + 1, " ",
+ rgba[1], rgba[0]);
+ continue;
+ }
+ }
#endif
+ {
+ ctx_term_set (term, col +1, row + 1, utf8,
+ rgba[0], rgba[1]);
+ }
}
}
- break;
- case SDL_QUIT:
- ctx_quit (ctx);
- break;
- case SDL_WINDOWEVENT:
- if (event.window.event == SDL_WINDOWEVENT_RESIZED)
- {
- ctx_sdl_show_frame (sdl, 1);
- int width = event.window.data1;
- int height = event.window.data2;
- SDL_DestroyTexture (sdl->texture);
- sdl->texture = SDL_CreateTexture (sdl->renderer, SDL_PIXELFORMAT_ABGR8888,
- SDL_TEXTUREACCESS_STREAMING, width, height);
- free (sdl->pixels);
- sdl->pixels = calloc (4, width * height);
-
- sdl->width = width;
- sdl->height = height;
- ctx_set_size (sdl->ctx, width, height);
- ctx_set_size (sdl->ctx_copy, width, height);
- }
- break;
}
- }
- return 1;
}
-#else
-void ctx_screenshot (Ctx *ctx, const char *path)
+
+
+inline static void ctx_term_render (void *ctx,
+ CtxCommand *command)
{
+ CtxTerm *term = (void*)ctx;
+ /* directly forward */
+ ctx_process (term->host, &command->entry);
}
+
+inline static void ctx_term_flush (CtxTerm *term)
+{
+ int width = term->width;
+ int height = term->height;
+ switch (term->mode)
+ {
+ case CTX_TERM_QUARTER:
+ ctx_term_output_buf_quarter (term->pixels,
+ width, height, term);
+ break;
+ case CTX_TERM_ASCII:
+ ctx_term_output_buf_ascii (term->pixels,
+ width, height, term, 0);
+ break;
+ case CTX_TERM_ASCII_MONO:
+ ctx_term_output_buf_ascii (term->pixels,
+ width, height, term, 1);
+ break;
+ case CTX_TERM_SEXTANT:
+ ctx_term_output_buf_sextant (term->pixels,
+ width, height, term);
+ break;
+ case CTX_TERM_BRAILLE:
+ ctx_term_output_buf_braille (term->pixels,
+ width, height, term, 0);
+ break;
+ case CTX_TERM_BRAILLE_MONO:
+ ctx_term_output_buf_braille (term->pixels,
+ width, height, term, 1);
+ break;
+ }
+#if CTX_BRAILLE_TEXT
+ CtxRasterizer *rasterizer = (CtxRasterizer*)(term->host->renderer);
+ // XXX instead sort and inject along with braille
+ //
+
+ //uint8_t rgba_bg[4]={0,0,0,0};
+ //uint8_t rgba_fg[4]={255,0,255,255};
+
+ for (CtxList *l = rasterizer->glyphs; l; l = l->next)
+ {
+ CtxTermGlyph *glyph = l->data;
+
+ uint8_t *pixels = term->pixels;
+ long rgb_sum[4]={0,0,0};
+ for (int v = 0; v < ctx_term_ch; v ++)
+ for (int u = 0; u < ctx_term_cw; u ++)
+ {
+ int i = ((glyph->row-1) * ctx_term_ch + v) * rasterizer->blit_width +
+ ((glyph->col-1) * ctx_term_cw + u);
+ for (int c = 0; c < 3; c ++)
+ rgb_sum[c] += pixels[i*4+c];
+ }
+ for (int c = 0; c < 3; c ++)
+ glyph->rgba_bg[c] = rgb_sum[c] / (ctx_term_ch * ctx_term_cw);
+ char utf8[8];
+ 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);
+ }
+
+ printf ("\e[H");
+ printf ("\e[0m");
+ ctx_term_scanout (term);
+ printf ("\e[0m");
+ fflush(NULL);
+ while (rasterizer->glyphs)
+ ctx_list_remove (&rasterizer->glyphs, rasterizer->glyphs->data);
#endif
+}
-#if CTX_SDL
+void ctx_term_free (CtxTerm *term)
+{
+ while (term->lines)
+ {
+ 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);
+ /* we're not destoring the ctx member, this is function is called in ctx' teardown */
+}
-static void ctx_sdl_set_clipboard (CtxSDL *sdl, const char *text)
+int ctx_renderer_is_term (Ctx *ctx)
{
- if (text)
- SDL_SetClipboardText (text);
+ if (ctx->renderer &&
+ ctx->renderer->free == (void*)ctx_term_free)
+ return 1;
+ return 0;
}
-static char *ctx_sdl_get_clipboard (CtxSDL *sdl)
+float ctx_term_get_cell_width (Ctx *ctx)
{
- return SDL_GetClipboardText ();
+ return ctx_term_cw;
}
-inline static void ctx_sdl_reset (CtxSDL *sdl)
+float ctx_term_get_cell_height (Ctx *ctx)
{
- ctx_sdl_show_frame (sdl, 1);
+ return ctx_term_ch;
}
-inline static void ctx_sdl_flush (CtxSDL *sdl)
+Ctx *ctx_new_term (int width, int height)
{
- if (sdl->shown_frame == sdl->render_frame)
+ Ctx *ctx = ctx_new ();
+#if CTX_RASTERIZER
+ CtxTerm *term = (CtxTerm*)calloc (sizeof (CtxTerm), 1);
+
+ const char *mode = getenv ("CTX_TERM_MODE");
+ ctx_term_cw = 2;
+ ctx_term_ch = 3;
+
+ if (!mode) term->mode = CTX_TERM_SEXTANT;
+ else if (!strcmp (mode, "sextant")) term->mode = CTX_TERM_SEXTANT;
+ else if (!strcmp (mode, "ascii")) term->mode = CTX_TERM_ASCII;
+ else if (!strcmp (mode, "ascii-mono")) term->mode = CTX_TERM_ASCII_MONO;
+ else if (!strcmp (mode, "quarter")) term->mode = CTX_TERM_QUARTER;
+ else if (!strcmp (mode, "braille")){
+ term->mode = CTX_TERM_BRAILLE;
+ ctx_term_ch = 4;
+ }
+ else if (!strcmp (mode, "braille-mono")){
+ term->mode = CTX_TERM_BRAILLE_MONO;
+ ctx_term_ch = 4;
+ }
+ else {
+ fprintf (stderr, "recognized values for CTX_TERM_MODE:\n"
+ " sextant ascii quarter braille braille-mono\n");
+ exit (1);
+ }
+
+ mode = getenv ("CTX_TERM_FORCE_FULL");
+ if (mode && strcmp (mode, "0") && strcmp (mode, "no"))
+ _ctx_term_force_full = 1;
+
+ fprintf (stdout, "\e[?1049h");
+ fprintf (stdout, "\e[?25l"); // cursor off
+
+ int maxwidth = ctx_terminal_cols () * ctx_term_cw;
+ int maxheight = (ctx_terminal_rows ()) * ctx_term_ch;
+ if (width <= 0 || height <= 0)
{
- int dirty_tiles = 0;
- ctx_set_drawlist (sdl->ctx_copy, &sdl->ctx->drawlist.entries[0],
- sdl->ctx->drawlist.count * 9);
- if (_ctx_enable_hash_cache)
- {
- Ctx *hasher = ctx_hasher_new (sdl->width, sdl->height,
- CTX_HASH_COLS, CTX_HASH_ROWS);
- ctx_render_ctx (sdl->ctx_copy, hasher);
+ width = maxwidth;
+ height = maxheight;
+ }
+ if (width > maxwidth) width = maxwidth;
+ if (height > maxheight) height = maxheight;
+ term->ctx = ctx;
+ term->width = width;
+ term->height = 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->host = ctx_new_for_framebuffer (term->pixels,
+ width, height,
+ width * 4, CTX_FORMAT_RGBA8);
+#if CTX_BRAILLE_TEXT
+ ((CtxRasterizer*)term->host->renderer)->term_glyphs=1;
+#endif
+ _ctx_mouse (ctx, NC_MOUSE_DRAG);
+ ctx_set_renderer (ctx, term);
+ ctx_set_size (ctx, width, height);
+ ctx_font_size (ctx, ctx_term_ch);
+ term->render = ctx_term_render;
+ term->flush = (void(*)(void*))ctx_term_flush;
+ term->free = (void(*)(void*))ctx_term_free;
+#endif
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++)
- {
- uint8_t *new_hash = ctx_hasher_get_hash (hasher, col, row);
- if (new_hash && memcmp (new_hash, &sdl->hashes[(row * CTX_HASH_COLS + col) * 20], 20))
- {
- memcpy (&sdl->hashes[(row * CTX_HASH_COLS + col)*20], new_hash, 20);
- sdl->tile_affinity[row * CTX_HASH_COLS + col] = 1;
- dirty_tiles++;
- }
- else
- {
- sdl->tile_affinity[row * CTX_HASH_COLS + col] = -1;
- }
- }
- free (((CtxHasher*)(hasher->renderer))->hashes);
- ctx_free (hasher);
- }
- else
- {
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++)
- {
- sdl->tile_affinity[row * CTX_HASH_COLS + col] = 1;
- dirty_tiles++;
- }
- }
- int dirty_no = 0;
- if (dirty_tiles)
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++)
- {
- if (sdl->tile_affinity[row * CTX_HASH_COLS + col] != -1)
- {
- sdl->tile_affinity[row * CTX_HASH_COLS + col] = dirty_no * (_ctx_max_threads) / dirty_tiles;
- dirty_no++;
- if (col > sdl->max_col) sdl->max_col = col;
- if (col < sdl->min_col) sdl->min_col = col;
- if (row > sdl->max_row) sdl->max_row = row;
- if (row < sdl->min_row) sdl->min_row = row;
- }
- }
-#if CTX_DAMAGE_CONTROL
- for (int i = 0; i < sdl->width * sdl->height; i++)
- {
- int new_ = (sdl->pixels[i*4+0]+ sdl->pixels[i*4+1]+ sdl->pixels[i*4+2])/3;
- //if (new_>1) new_--;
- sdl->pixels[i*4] = (sdl->pixels[i*4] + 255)/2;
- sdl->pixels[i*4+1]= (sdl->pixels[i*4+1] + new_)/2;
- sdl->pixels[i*4+2]= (sdl->pixels[i*4+1] + new_)/2;
- }
+ return ctx;
+}
+
#endif
- sdl->render_frame = ++sdl->frame;
+#if CTX_EVENTS
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
- mtx_lock (&sdl->mtx);
- cnd_broadcast (&sdl->cond);
- mtx_unlock (&sdl->mtx);
+typedef struct _CtxTermImg CtxTermImg;
+struct _CtxTermImg
+{
+ void (*render) (void *termimg, CtxCommand *command);
+ void (*reset) (void *termimg);
+ void (*flush) (void *termimg);
+ char *(*get_clipboard) (void *ctxctx);
+ void (*set_clipboard) (void *ctxctx, const char *text);
+ void (*free) (void *termimg);
+ Ctx *ctx;
+ int width;
+ int height;
+ int cols;
+ int rows;
+ int was_down;
+ // we need to have the above members in that order up to here
+ uint8_t *pixels;
+ Ctx *host;
+ CtxList *lines;
+};
- }
+inline static void ctx_termimg_render (void *ctx,
+ CtxCommand *command)
+{
+ CtxTermImg *termimg = (void*)ctx;
+ /* directly forward */
+ ctx_process (termimg->host, &command->entry);
}
-void ctx_sdl_free (CtxSDL *sdl)
+inline static void ctx_termimg_flush (CtxTermImg *termimg)
{
- sdl->quit = 1;
- mtx_lock (&sdl->mtx);
- cnd_broadcast (&sdl->cond);
- mtx_unlock (&sdl->mtx);
+ int width = termimg->width;
+ int height = termimg->height;
+ if (!termimg->pixels) return;
+ char *encoded = malloc (width * height * 3 * 3);
+ ctx_bin2base64 (termimg->pixels, width * height * 3,
+ encoded);
+ int encoded_len = strlen (encoded);
- while (sdl->thread_quit < _ctx_max_threads)
- usleep (1000); // XXX : properly wait for threads instead
- if (sdl->pixels)
- {
- free (sdl->pixels);
- sdl->pixels = NULL;
- for (int i = 0 ; i < _ctx_max_threads; i++)
+ int i = 0;
+
+ printf ("\e[H");
+ printf ("\e_Gf=24,s=%i,v=%i,t=d,a=T,m=1;\e\\", width, height);
+ while (i < encoded_len)
{
- ctx_free (sdl->host[i]);
- sdl->host[i]=NULL;
- }
- SDL_DestroyTexture (sdl->texture);
- SDL_DestroyRenderer (sdl->renderer);
- SDL_DestroyWindow (sdl->window);
- ctx_free (sdl->ctx_copy);
+ if (i + 4096 < encoded_len)
+ {
+ printf ("\e_Gm=1;");
+ }
+ else
+ {
+ printf ("\e_Gm=0;");
+ }
+ for (int n = 0; n < 4000 && i < encoded_len; n++)
+ {
+ printf ("%c", encoded[i]);
+ i++;
+ }
+ printf ("\e\\");
}
- //free (sdl); // kept alive for threads quit check..
- /* we're not destoring the ctx member, this is function is called in ctx' teardown */
+ free (encoded);
+
+ fflush (NULL);
}
-static unsigned char *sdl_icc = NULL;
-static long sdl_icc_length = 0;
-
-static
-void sdl_render_fun (void **data)
+void ctx_termimg_free (CtxTermImg *termimg)
{
- int no = (size_t)data[0];
- CtxSDL *sdl = data[1];
-
- while (!sdl->quit)
+ while (termimg->lines)
{
- Ctx *host = sdl->host[no];
-
- mtx_lock (&sdl->mtx);
- cnd_wait(&sdl->cond, &sdl->mtx);
- mtx_unlock (&sdl->mtx);
-
- if (sdl->render_frame != sdl->rendered_frame[no])
- {
- int hno = 0;
- for (int row = 0; row < CTX_HASH_ROWS; row++)
- for (int col = 0; col < CTX_HASH_COLS; col++, hno++)
- {
- if (sdl->tile_affinity[hno]==no)
- {
- int x0 = ((sdl->width)/CTX_HASH_COLS) * col;
- int y0 = ((sdl->height)/CTX_HASH_ROWS) * row;
- int width = sdl->width / CTX_HASH_COLS;
- int height = sdl->height / CTX_HASH_ROWS;
-
- CtxRasterizer *rasterizer = (CtxRasterizer*)host->renderer;
-#if 1 // merge horizontally adjecant tiles of same affinity into one job
- while (col + 1 < CTX_HASH_COLS &&
- sdl->tile_affinity[hno+1] == no)
- {
- width += sdl->width / CTX_HASH_COLS;
- col++;
- hno++;
- }
-#endif
- ctx_rasterizer_init (rasterizer,
- host, sdl->ctx, &host->state,
- &sdl->pixels[sdl->width * 4 * y0 + x0 * 4],
- 0, 0, width, height,
- sdl->width*4, CTX_FORMAT_RGBA8,
- sdl->antialias);
- 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 (sdl->ctx_copy, host);
- }
- }
- sdl->rendered_frame[no] = sdl->render_frame;
- }
+ free (termimg->lines->data);
+ ctx_list_remove (&termimg->lines, termimg->lines->data);
}
-
- sdl->thread_quit++; // need atomic?
+ printf ("\e[?25h"); // cursor on
+ nc_at_exit ();
+ free (termimg->pixels);
+ ctx_free (termimg->host);
+ free (termimg);
+ /* we're not destoring the ctx member, this is function is called in ctx' teardown */
}
-int ctx_renderer_is_sdl (Ctx *ctx)
+int ctx_renderer_is_termimg (Ctx *ctx)
{
if (ctx->renderer &&
- ctx->renderer->free == (void*)ctx_sdl_free)
+ ctx->renderer->free == (void*)ctx_termimg_free)
return 1;
return 0;
}
-
-Ctx *ctx_new_sdl (int width, int height)
+Ctx *ctx_new_termimg (int width, int height)
{
+ Ctx *ctx = ctx_new ();
#if CTX_RASTERIZER
+ fprintf (stdout, "\e[?1049h");
+ fprintf (stdout, "\e[?25l"); // cursor off
+ CtxTermImg *termimg = (CtxTermImg*)calloc (sizeof (CtxTermImg), 1);
- CtxSDL *sdl = (CtxSDL*)calloc (sizeof (CtxSDL), 1);
- _ctx_file_get_contents ("/tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
- if (width <= 0 || height <= 0)
- {
- width = 1920;
- height = 1080;
- }
- sdl->window = SDL_CreateWindow("ctx", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height,
SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE);
- //sdl->renderer = SDL_CreateRenderer (sdl->window, -1, SDL_RENDERER_SOFTWARE);
- sdl->renderer = SDL_CreateRenderer (sdl->window, -1, 0);
- if (!sdl->renderer)
- {
- ctx_free (sdl->ctx);
- free (sdl);
- return NULL;
- }
-#if CTX_BABL
- babl_init ();
-#endif
-
- ctx_sdl_events = 1;
- sdl->texture = SDL_CreateTexture (sdl->renderer,
- SDL_PIXELFORMAT_ABGR8888,
- SDL_TEXTUREACCESS_STREAMING,
- width, height);
- SDL_StartTextInput ();
- SDL_EnableScreenSaver ();
+ int maxwidth = ctx_terminal_width ();
- sdl->ctx = ctx_new ();
- sdl->ctx_copy = ctx_new ();
- sdl->width = width;
- sdl->height = height;
- sdl->cols = 80;
- sdl->rows = 20;
- ctx_set_renderer (sdl->ctx, sdl);
- ctx_set_renderer (sdl->ctx_copy, sdl);
-
- sdl->pixels = (uint8_t*)malloc (width * height * 4);
-
- ctx_set_size (sdl->ctx, width, height);
- ctx_set_size (sdl->ctx_copy, width, height);
- sdl->flush = (void*)ctx_sdl_flush;
- sdl->reset = (void*)ctx_sdl_reset;
- sdl->free = (void*)ctx_sdl_free;
- sdl->set_clipboard = (void*)ctx_sdl_set_clipboard;
- sdl->get_clipboard = (void*)ctx_sdl_get_clipboard;
+ int colwidth = maxwidth/ctx_terminal_cols ();
+ maxwidth-=colwidth;
- for (int i = 0; i < _ctx_max_threads; i++)
+ int maxheight = ctx_terminal_height ();
+ if (width <= 0 || height <= 0)
{
- sdl->host[i] = ctx_new_for_framebuffer (sdl->pixels,
- sdl->width/CTX_HASH_COLS, sdl->height/CTX_HASH_ROWS,
- sdl->width * 4, CTX_FORMAT_RGBA8);
- ctx_set_texture_source (sdl->host[i], sdl->ctx);
- }
-
- mtx_init (&sdl->mtx, mtx_plain);
- cnd_init (&sdl->cond);
-
-#define start_thread(no)\
- if(_ctx_max_threads>no){ \
- static void *args[2]={(void*)no, };\
- thrd_t tid;\
- args[1]=sdl;\
- thrd_create (&tid, (void*)sdl_render_fun, args);\
+ width = maxwidth;
+ height = maxheight;
}
- start_thread(0);
- start_thread(1);
- start_thread(2);
- start_thread(3);
- start_thread(4);
- start_thread(5);
- start_thread(6);
- start_thread(7);
- start_thread(8);
- start_thread(9);
- start_thread(10);
- start_thread(11);
- start_thread(12);
- start_thread(13);
- start_thread(14);
- start_thread(15);
-#undef start_thread
-
- ctx_flush (sdl->ctx);
- return sdl->ctx;
-#else
- return NULL;
+ if (width > maxwidth) width = maxwidth;
+ if (height > maxheight) height = maxheight;
+ termimg->ctx = ctx;
+ termimg->width = width;
+ termimg->height = height;
+ termimg->lines = 0;
+ termimg->pixels = (uint8_t*)malloc (width * height * 3);
+ termimg->host = ctx_new_for_framebuffer (termimg->pixels,
+ width, height,
+ width * 3, CTX_FORMAT_RGB8);
+ _ctx_mouse (ctx, NC_MOUSE_DRAG);
+ ctx_set_renderer (ctx, termimg);
+ ctx_set_size (ctx, width, height);
+ ctx_font_size (ctx, 14.0f);
+ termimg->render = ctx_termimg_render;
+ termimg->flush = (void(*)(void*))ctx_termimg_flush;
+ termimg->free = (void(*)(void*))ctx_termimg_free;
#endif
-}
-#else
-int ctx_renderer_is_sdl (Ctx *ctx)
-{
- return 0;
+ return ctx;
}
+
#endif
#if CTX_FORMATTER
@@ -21376,7 +23941,7 @@ const char *_ctx_code_to_name (int code)
case CTX_SET_PIXEL: return "setPixel"; break;
case CTX_GLOBAL_ALPHA: return "globalAlpha"; break;
case CTX_TEXT: return "text"; break;
- case CTX_TEXT_STROKE: return "textStroke"; break;
+ case CTX_STROKE_TEXT: return "strokeText"; break;
case CTX_SAVE: return "save"; break;
case CTX_RESTORE: return "restore"; break;
case CTX_NEW_PAGE: return "newPage"; break;
@@ -21399,6 +23964,7 @@ const char *_ctx_code_to_name (int code)
case CTX_REL_ARC_TO: return "relArcTo"; break;
case CTX_GLYPH: return "glyph"; break;
case CTX_TEXTURE: return "texture"; break;
+ case CTX_DEFINE_TEXTURE: return "defineTexture"; break;
case CTX_IDENTITY: return "identity"; break;
case CTX_CLOSE_PATH: return "closePath"; break;
case CTX_PRESERVE: return "preserve"; break;
@@ -21434,6 +24000,8 @@ const char *_ctx_code_to_name (int code)
case CTX_LINE_JOIN: return "lineJoin"; break;
case CTX_LINE_CAP: return "lineCap"; break;
case CTX_LINE_WIDTH: return "lineWidth"; break;
+ case CTX_LINE_DASH_OFFSET: return "lineDashOffset"; break;
+ case CTX_IMAGE_SMOOTHING: return "imageSmoothing"; break;
case CTX_SHADOW_BLUR: return "shadowBlur"; break;
case CTX_FILL_RULE: return "fillRule"; break;
}
@@ -21479,6 +24047,8 @@ static void _ctx_print_name (CtxFormatter *formatter, int code)
case CTX_LINE_JOIN: name[1]='j'; break;
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_IMAGE_SMOOTHING: name[1]='S'; break;
case CTX_SHADOW_BLUR: name[1]='s'; break;
case CTX_SHADOW_COLOR: name[1]='C'; break;
case CTX_SHADOW_OFFSET_X: name[1]='x'; break;
@@ -21616,6 +24186,18 @@ ctx_print_entry_enum (CtxFormatter *formatter, CtxEntry *entry, int args)
_ctx_print_endcmd (formatter);
}
+
+static void
+ctx_print_a85 (CtxFormatter *formatter, uint8_t *data, int length)
+{
+ char *tmp = 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);
+}
+
static void
ctx_print_escaped_string (CtxFormatter *formatter, const char *string)
{
@@ -21659,6 +24241,12 @@ ctx_print_float (CtxFormatter *formatter, float val)
ctx_formatter_addstr (formatter, temp, -1);
}
+static void
+ctx_print_int (CtxFormatter *formatter, int val)
+{
+ ctx_formatter_addstrf (formatter, "%i", val);
+}
+
static void
ctx_print_entry (CtxFormatter *formatter, CtxEntry *entry, int args)
{
@@ -21718,7 +24306,43 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
ctx_print_entry (formatter, entry, 2);
break;
case CTX_TEXTURE:
- ctx_print_entry (formatter, entry, 3);
+ _ctx_print_name (formatter, entry->code);
+ ctx_formatter_addstrf (formatter, "\"");
+ ctx_print_escaped_string (formatter, c->texture.eid);
+ ctx_formatter_addstrf (formatter, "\", ");
+ ctx_print_float (formatter, c->texture.x);
+ ctx_formatter_addstrf (formatter, ", ");
+ ctx_print_float (formatter, c->texture.y);
+ ctx_formatter_addstrf (formatter, " ");
+ _ctx_print_endcmd (formatter);
+ break;
+
+ case CTX_DEFINE_TEXTURE:
+ _ctx_print_name (formatter, entry->code);
+ ctx_formatter_addstrf (formatter, "\"");
+ ctx_print_escaped_string (formatter, c->define_texture.eid);
+ ctx_formatter_addstrf (formatter, "\", ");
+ ctx_print_int (formatter, c->define_texture.width);
+ ctx_formatter_addstrf (formatter, ", ");
+ ctx_print_int (formatter, c->define_texture.height);
+ ctx_formatter_addstrf (formatter, ",%i, ", c->define_texture.format);
+
+ uint8_t *pixel_data = ctx_define_texture_pixel_data (entry);
+#if 1
+
+ int stride = ctx_pixel_format_get_stride (c->define_texture.format, c->define_texture.width);
+ //fprintf (stderr, "encoding %i bytes\n", c->define_texture.height *stride);
+ ctx_print_a85 (formatter, pixel_data, c->define_texture.height * stride);
+#else
+ ctx_formatter_addstrf (formatter, "\"");
+ ctx_print_escaped_string (formatter, pixel_data);
+ ctx_formatter_addstrf (formatter, "\" ");
+
+#endif
+
+ _ctx_print_endcmd (formatter);
+ break;
+
break;
case CTX_REL_ARC_TO:
case CTX_ARC_TO:
@@ -21745,6 +24369,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
case CTX_MITER_LIMIT:
case CTX_ROTATE:
case CTX_LINE_WIDTH:
+ case CTX_LINE_DASH_OFFSET:
case CTX_GLOBAL_ALPHA:
case CTX_SHADOW_BLUR:
case CTX_SHADOW_OFFSET_X:
@@ -21777,14 +24402,21 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
if (formatter->longform || 1)
{
_ctx_indent (formatter);
- switch ( (int) c->set_color.model)
+ int model = (int) c->set_color.model;
+ const char *suffix="";
+ if (model & 512)
+ {
+ model = model & 511;
+ suffix = "S";
+ }
+ switch (model)
{
case CTX_GRAY:
- ctx_formatter_addstrf (formatter, "gray ");
+ ctx_formatter_addstrf (formatter, "gray%s ", suffix);
ctx_print_float (formatter, c->graya.g);
break;
case CTX_GRAYA:
- ctx_formatter_addstrf (formatter, "graya ");
+ ctx_formatter_addstrf (formatter, "graya%s ", suffix);
ctx_print_float (formatter, c->graya.g);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->graya.a);
@@ -21792,7 +24424,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
case CTX_RGBA:
if (c->rgba.a != 1.0)
{
- ctx_formatter_addstrf (formatter, "rgba ");
+ ctx_formatter_addstrf (formatter, "rgba%s ", suffix);
ctx_print_float (formatter, c->rgba.r);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->rgba.g);
@@ -21806,12 +24438,12 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
case CTX_RGB:
if (c->rgba.r == c->rgba.g && c->rgba.g == c->rgba.b)
{
- ctx_formatter_addstrf (formatter, "gray ");
+ ctx_formatter_addstrf (formatter, "gray%s ", suffix);
ctx_print_float (formatter, c->rgba.r);
ctx_formatter_addstrf (formatter, " ");
break;
}
- ctx_formatter_addstrf (formatter, "rgb ");
+ ctx_formatter_addstrf (formatter, "rgb%s ", suffix);
ctx_print_float (formatter, c->rgba.r);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->rgba.g);
@@ -21819,7 +24451,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
ctx_print_float (formatter, c->rgba.b);
break;
case CTX_DRGB:
- ctx_formatter_addstrf (formatter, "drgb ");
+ ctx_formatter_addstrf (formatter, "drgb%s ", suffix);
ctx_print_float (formatter, c->rgba.r);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->rgba.g);
@@ -21827,7 +24459,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
ctx_print_float (formatter, c->rgba.b);
break;
case CTX_DRGBA:
- ctx_formatter_addstrf (formatter, "drgba ");
+ ctx_formatter_addstrf (formatter, "drgba%s ", suffix);
ctx_print_float (formatter, c->rgba.r);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->rgba.g);
@@ -21837,7 +24469,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
ctx_print_float (formatter, c->rgba.a);
break;
case CTX_CMYK:
- ctx_formatter_addstrf (formatter, "cmyk ");
+ ctx_formatter_addstrf (formatter, "cmyk%s ", suffix);
ctx_print_float (formatter, c->cmyka.c);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->cmyka.m);
@@ -21847,7 +24479,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
ctx_print_float (formatter, c->cmyka.k);
break;
case CTX_CMYKA:
- ctx_formatter_addstrf (formatter, "cmyka ");
+ ctx_formatter_addstrf (formatter, "cmyka%s ", suffix);
ctx_print_float (formatter, c->cmyka.c);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->cmyka.m);
@@ -21859,7 +24491,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
ctx_print_float (formatter, c->cmyka.a);
break;
case CTX_DCMYK:
- ctx_formatter_addstrf (formatter, "dcmyk ");
+ ctx_formatter_addstrf (formatter, "dcmyk%s ", suffix);
ctx_print_float (formatter, c->cmyka.c);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->cmyka.m);
@@ -21869,7 +24501,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
ctx_print_float (formatter, c->cmyka.k);
break;
case CTX_DCMYKA:
- ctx_formatter_addstrf (formatter, "dcmyka ");
+ ctx_formatter_addstrf (formatter, "dcmyka%s ", suffix);
ctx_print_float (formatter, c->cmyka.c);
ctx_formatter_addstrf (formatter, " ");
ctx_print_float (formatter, c->cmyka.m);
@@ -21943,6 +24575,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
case CTX_LINE_JOIN:
case CTX_COMPOSITING_MODE:
case CTX_BLEND_MODE:
+ case CTX_IMAGE_SMOOTHING:
ctx_print_entry_enum (formatter, entry, 1);
break;
case CTX_GRADIENT_STOP:
@@ -21956,7 +24589,7 @@ ctx_formatter_process (void *user_data, CtxCommand *c)
_ctx_print_endcmd (formatter);
break;
case CTX_TEXT:
- case CTX_TEXT_STROKE:
+ case CTX_STROKE_TEXT:
case CTX_FONT:
_ctx_print_name (formatter, entry->code);
ctx_formatter_addstrf (formatter, "\"");
@@ -22094,7 +24727,6 @@ void ctx_dirty_rect (Ctx *ctx, int *x, int *y, int *width, int *height)
if (y) { *y = ctx->state.min_y; }
if (width) { *width = ctx->state.max_x - ctx->state.min_x; }
if (height) { *height = ctx->state.max_y - ctx->state.min_y; }
- //fprintf (stderr, "%i %i %ix%i\n", *x, *y, *width, *height);
}
#if CTX_CURRENT_PATH
@@ -22170,93 +24802,482 @@ ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
}
if (got_coord)
{
- minx = ctx_minf (minx, x);
- miny = ctx_minf (miny, y);
- maxx = ctx_maxf (maxx, x);
- maxy = ctx_maxf (maxy, y);
+ minx = ctx_minf (minx, x);
+ miny = ctx_minf (miny, y);
+ maxx = ctx_maxf (maxx, x);
+ maxy = ctx_maxf (maxy, y);
+ }
+ }
+
+ if (ex1) *ex1 = minx;
+ if (ey1) *ey1 = miny;
+ if (ex2) *ex2 = maxx;
+ if (ey2) *ey2 = maxy;
+}
+
+#else
+void
+ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
+{
+}
+#endif
+
+
+static void
+ctx_gstate_push (CtxState *state)
+{
+ if (state->gstate_no + 1 >= CTX_MAX_STATES)
+ { return; }
+ state->gstate_stack[state->gstate_no] = state->gstate;
+ state->gstate_no++;
+ ctx_state_set (state, CTX_new_state, 0.0);
+ state->has_clipped=0;
+}
+
+static void
+ctx_gstate_pop (CtxState *state)
+{
+ if (state->gstate_no <= 0)
+ { return; }
+ state->gstate = state->gstate_stack[state->gstate_no-1];
+ state->gstate_no--;
+}
+
+void
+ctx_close_path (Ctx *ctx)
+{
+ CTX_PROCESS_VOID (CTX_CLOSE_PATH);
+}
+
+int _ctx_is_rasterizer (Ctx *ctx);
+
+void
+ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh,
+ CtxPixelFormat format, int dst_stride,
+ uint8_t *dst_data)
+{
+ if (0)
+ {
+ }
+#if CTX_RASTERIZER
+ else if (_ctx_is_rasterizer (ctx))
+ {
+ CtxRasterizer *rasterizer = (CtxRasterizer*)ctx->renderer;
+ if (rasterizer->format->pixel_format == format)
+ {
+ if (dst_stride <= 0) dst_stride = ctx_pixel_format_get_stride (format, sw);
+ int bytes_per_pix = rasterizer->format->bpp/8;
+ int y = 0;
+ for (int v = sy; v < sy + sh; v++, y++)
+ {
+ int x = 0;
+ for (int u = sx; u < sx + sw; u++, x++)
+ {
+ uint8_t* src_buf = (uint8_t*)rasterizer->buf;
+ memcpy (&dst_data[y * dst_stride + x * bytes_per_pix], &src_buf[v * rasterizer->blit_stride + u
* bytes_per_pix], bytes_per_pix);
+ }
+ }
+ return;
+ }
+ }
+#endif
+#if CTX_FB
+ else if (format == CTX_FORMAT_RGBA8 &&
+ (
+ ctx_renderer_is_fb (ctx)
+#if CTX_SDL
+ || ctx_renderer_is_sdl (ctx)
+#endif
+ ))
+ {
+ CtxTiled *tiled = (CtxTiled*)ctx->renderer;
+ {
+ if (dst_stride <= 0) dst_stride = ctx_pixel_format_get_stride (format, sw);
+ int bytes_per_pix = 4;
+ int y = 0;
+ for (int v = sy; v < sy + sh; v++, y++)
+ {
+ int x = 0;
+ for (int u = sx; u < sx + sw; u++, x++)
+ {
+ 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);
+ }
+ }
+ return;
+ }
+ }
+#endif
+}
+
+void
+ctx_put_image_data (Ctx *ctx, int w, int h, int stride, int format,
+ uint8_t *data,
+ int ox, int oy,
+ int dirtyX, int dirtyY,
+ int dirtyWidth, int dirtyHeight)
+{
+ char eid[65]="";
+ ctx_save (ctx);
+ ctx_identity (ctx);
+ ctx_define_texture (ctx, NULL, w, h, stride, format, data, eid);
+ if (eid[0])
+ {
+ // XXX set compositor to source
+ ctx_compositing_mode (ctx, CTX_COMPOSITE_COPY);
+ ctx_draw_texture_clipped (ctx, eid, ox, oy, w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+ }
+ ctx_restore (ctx);
+}
+
+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;
+ for (CtxList *l = ctx->eid_db; l; l = l->next)
+ {
+ CtxEidInfo *eid_info = (CtxEidInfo*)l->data;
+ if (ctx->frame - eid_info->frame >= 2)
+ {
+ ctx_list_prepend (&to_remove, eid_info);
+ }
+ else if (!strcmp (eid_info->eid, eid) &&
+ ctx->frame - eid_info->frame < 2)
+ {
+ //FILE *f = fopen ("/tmp/l", "a");
+ // fprintf (f, "%i good:%i %i %s\n", getpid(), ctx->frame, eid_info->frame, eid);
+ //fclose (f);
+ eid_info->frame = ctx->frame;
+ if (w) *w = eid_info->width;
+ if (h) *h = eid_info->height;
+ ret = 1;
}
}
-
- if (ex1) *ex1 = minx;
- if (ey1) *ey1 = miny;
- if (ex2) *ex2 = maxx;
- if (ey2) *ey2 = maxy;
+ while (to_remove)
+ {
+ CtxEidInfo *eid_info = (CtxEidInfo*)to_remove->data;
+ //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_list_remove (&ctx->eid_db, eid_info);
+ ctx_list_remove (&to_remove, eid_info);
+ }
+ return ret;
}
-#else
-void
-ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
+void ctx_texture (Ctx *ctx, const char *eid, float x, float y)
{
-}
-#endif
-
+ int eid_len = strlen (eid);
+ char ascii[41]="";
+ if (eid_len > 50)
+ {
+ CtxSHA1 *sha1 = ctx_sha1_new ();
+ uint8_t hash[20]="";
+ ctx_sha1_process (sha1, (uint8_t*)eid, eid_len);
+ ctx_sha1_done (sha1, hash);
+ ctx_sha1_free (sha1);
+ const char *hex="0123456789abcdef";
+ for (int i = 0; i < 20; i ++)
+ {
+ ascii[i*2]=hex[hash[i]/16];
+ ascii[i*2+1]=hex[hash[i]%16];
+ }
+ ascii[40]=0;
+ eid=ascii;
+ }
-static void
-ctx_gstate_push (CtxState *state)
+ //FILE *f = fopen ("/tmp/l", "a");
+ if (ctx_eid_valid (ctx, eid, 0, 0))
+ {
+ ctx_process_cmd_str_float (ctx, CTX_TEXTURE, eid, x, y);
+ //fprintf (f, "setting texture eid %s\n", eid);
+ }
+ else
+ {
+ //fprintf (f, "tried setting invalid texture eid %s\n", eid);
+ }
+ //fclose (f);
+}
+int
+_ctx_frame (Ctx *ctx)
{
- if (state->gstate_no + 1 >= CTX_MAX_STATES)
- { return; }
- state->gstate_stack[state->gstate_no] = state->gstate;
- state->gstate_no++;
- ctx_state_set (state, CTX_new_state, 0.0);
- state->has_clipped=0;
+ return ctx->frame;
}
-static void
-ctx_gstate_pop (CtxState *state)
+void ctx_define_texture (Ctx *ctx, const char *eid, int width, int height, int stride, int format, void
*data, char *ret_eid)
{
- if (state->gstate_no <= 0)
- { return; }
- state->gstate = state->gstate_stack[state->gstate_no-1];
- state->gstate_no--;
-}
+ uint8_t hash[20]="";
+ char ascii[41]="";
+ int dst_stride = width;
+
+ dst_stride = ctx_pixel_format_get_stride ((CtxPixelFormat)format, width);
+ if (stride <= 0)
+ stride = dst_stride;
+
+ int data_len = height * dst_stride;
+
+ if (eid == NULL)
+ {
+ CtxSHA1 *sha1 = ctx_sha1_new ();
+
+ {
+ uint8_t *src = (uint8_t*)data;
+ for (int y = 0; y < height; y++)
+ {
+ ctx_sha1_process (sha1, src, dst_stride);
+ src += stride;
+ }
+ }
+ ctx_sha1_done (sha1, hash);
+ ctx_sha1_free (sha1);
+ const char *hex="0123456789abcdef";
+ for (int i = 0; i < 20; i ++)
+ {
+ ascii[i*2]=hex[hash[i]/16];
+ ascii[i*2+1]=hex[hash[i]%16];
+ }
+ ascii[40]=0;
+ eid = ascii;
+ }
+
+ int eid_len = strlen (eid);
+
+ if (eid_len > 50)
+ {
+ CtxSHA1 *sha1 = ctx_sha1_new ();
+ uint8_t hash[20]="";
+ ctx_sha1_process (sha1, (uint8_t*)eid, eid_len);
+ ctx_sha1_done (sha1, hash);
+ ctx_sha1_free (sha1);
+ const char *hex="0123456789abcdef";
+ for (int i = 0; i < 20; i ++)
+ {
+ ascii[i*2]=hex[hash[i]/16];
+ ascii[i*2+1]=hex[hash[i]%16];
+ }
+ ascii[40]=0;
+ eid = ascii;
+ eid_len = 40;
+ }
+
+ // we now have eid
+
+ if (ctx_eid_valid (ctx, eid, 0, 0))
+ {
+ ctx_texture (ctx, eid, 0.0, 0.0);
+ }
+ else
+
+ {
+ CtxEntry *commands;
+ int command_size = 1 + (data_len+1+1)/9 + 1 + (eid_len+1+1)/9 + 1 + 8;
+ if (ctx->renderer && ctx->renderer->process)
+ {
+ commands = (CtxEntry*)calloc (sizeof (CtxEntry), command_size);
+ }
+ else
+ {
+ commands = NULL;
+ ctx_drawlist_resize (&ctx->drawlist, ctx->drawlist.count + command_size);
+ commands = &(ctx->drawlist.entries[ctx->drawlist.count]);
+ memset (commands, 0, sizeof (CtxEntry) * command_size);
+ }
+ /* bottleneck, we can avoid copying sometimes - and even when copying
+ * we should cut this down to one copy, direct to the drawlist.
+ *
+ */
+ commands[0] = ctx_u32 (CTX_DEFINE_TEXTURE, width, height);
+ commands[1].data.u16[0] = format;
+
+ int pos = 2;
+
+ commands[pos].code = CTX_DATA;
+ commands[pos].data.u32[0] = eid_len;
+ commands[pos].data.u32[1] = (eid_len+1+1)/9 + 1;
+ memcpy ((char *) &commands[pos+1].data.u8[0], eid, eid_len);
+ ((char *) &commands[pos+1].data.u8[0])[eid_len]=0;
+
+ pos = 2 + 1 + ctx_conts_for_entry (&commands[2]);
+ commands[pos].code = CTX_DATA;
+ commands[pos].data.u32[0] = data_len;
+ commands[pos].data.u32[1] = (data_len+1+1)/9 + 1;
+ {
+ uint8_t *src = (uint8_t*)data;
+ uint8_t *dst = &commands[pos+1].data.u8[0];
+ for (int y = 0; y < height; y++)
+ {
+ memcpy (dst, src, dst_stride);
+ src += stride;
+ dst += dst_stride;
+ }
+ }
+ ((char *) &commands[pos+1].data.u8[0])[data_len]=0;
+ if (ctx->renderer && ctx->renderer->process)
+ {
+ ctx_process (ctx, commands);
+ free (commands);
+ }
+ else
+ {
+ ctx->drawlist.count += ctx_conts_for_entry (commands) + 1;
+ }
+ CtxEidInfo *eid_info = (CtxEidInfo*)calloc (sizeof (CtxEidInfo), 1);
+ eid_info->eid = strdup (eid);
+ eid_info->width = width;
+ eid_info->height = height;
+ eid_info->frame = ctx->texture_cache->frame;
+ //fprintf (stderr, "%i\n", eid_info->frame);
+ ctx_list_prepend (&ctx->texture_cache->eid_db, eid_info);
+ }
+ if (ret_eid)
+ {
+ strcpy (ret_eid, eid);
+ ret_eid[64]=0;
+ }
+}
void
-ctx_close_path (Ctx *ctx)
+ctx_texture_load (Ctx *ctx, const char *path, int *tw, int *th, char *reid)
{
- CTX_PROCESS_VOID (CTX_CLOSE_PATH);
-}
+ const char *eid = path;
+ char ascii[41]="";
+ int eid_len = strlen (eid);
+ if (eid_len > 50)
+ {
+ CtxSHA1 *sha1 = ctx_sha1_new ();
+ uint8_t hash[20]="";
+ ctx_sha1_process (sha1, (uint8_t*)eid, eid_len);
+ ctx_sha1_done (sha1, hash);
+ ctx_sha1_free (sha1);
+ const char *hex="0123456789abcdef";
+ for (int i = 0; i < 20; i ++)
+ {
+ ascii[i*2]=hex[hash[i]/16];
+ ascii[i*2+1]=hex[hash[i]%16];
+ }
+ ascii[40]=0;
+ eid = ascii;
+ }
+ if (ctx_eid_valid (ctx, eid , tw, th))
+ {
+ if (reid)
+ {
+ strcpy (reid, eid);
+ }
+ return;
+ }
-uint8_t *
-ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh, int format, int stride)
-{
- // NYI
- return NULL;
+#ifdef STBI_INCLUDE_STB_IMAGE_H
+ CtxPixelFormat pixel_format = CTX_FORMAT_RGBA8;
+ int w, h, components;
+ unsigned char *pixels = NULL;
+
+ if (!strncmp (path, "file://", 7))
+ {
+ pixels = stbi_load (path + 7, &w, &h, &components, 0);
+ }
+ else
+ {
+ unsigned char *data = NULL;
+ long length = 0;
+ ctx_get_contents (path, &data, &length);
+ if (data)
+ {
+ pixels = stbi_load_from_memory (data, length, &w, &h, &components, 0);
+ free (data);
+ }
+ }
+
+ if (pixels)
+ {
+ switch (components)
+ {
+ 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;
+ }
+ if (tw) *tw = w;
+ if (th) *th = h;
+ ctx_define_texture (ctx, eid, w, h, w * components, pixel_format, pixels,
+ reid);
+ free (pixels);
+ }
+ else
+ {
+ fprintf (stderr, "texture loading problem for %s\n", path);
+ }
+#endif
}
void
-ctx_put_image_data (Ctx *ctx, uint8_t *data, int w, int h, int format, int stride,
- int dx, int dy, int dirtyX, int dirtyY,
- int dirtyWidth, int dirtyHeight)
+ctx_draw_texture_clipped (Ctx *ctx, const char *eid,
+ float x, float y,
+ float width, float height,
+ float clip_x, float clip_y,
+ float clip_width, float clip_height)
+{
+ int tex_width = 0;
+ int tex_height = 0;
+ if (ctx_eid_valid (ctx, eid , &tex_width, &tex_height))
+ {
+ if (width > 0.0 && height > 0.0)
+ {
+ ctx_save (ctx);
+#if 0
+ if (clip_width > 0.0f)
+ {
+ ctx_rectangle (ctx, clip_x, clip_y, clip_width, clip_height);
+ ctx_clip (ctx);
+ }
+#endif
+ ctx_rectangle (ctx, x, y, width, height);
+ if (clip_width > 0.0f)
+ {
+ ctx_translate (ctx, -clip_x, -clip_y);
+ ctx_scale (ctx, width/clip_width, height/clip_height);
+ }
+ else
+ {
+ ctx_scale (ctx, width/tex_width, height/tex_height);
+ }
+ //ctx_texture (ctx, eid, x / (width/tex_width), y / (height/tex_height));
+ ctx_texture (ctx, eid, x, y);// / (width/tex_width), y / (height/tex_height));
+ ctx_fill (ctx);
+ ctx_restore (ctx);
+ }
+ }
+}
+
+void ctx_draw_texture (Ctx *ctx, const char *eid, float x, float y, float w, float h)
{
- // NYI
+ ctx_draw_texture_clipped (ctx, eid, x, y, w, h, 0,0,0,0);
}
-
-void ctx_texture (Ctx *ctx, int id, float x, float y)
+void ctx_draw_image_clipped (Ctx *ctx, const char *path, float x, float y, float w, float h, float sx, float
sy, float swidth, float sheight)
{
- CtxEntry commands[2];
- if (id < 0) { return; }
- commands[0] = ctx_u32 (CTX_TEXTURE, id, 0);
- commands[1] = ctx_f (CTX_CONT, x, y);
- ctx_process (ctx, commands);
+ char reteid[65];
+ int width, height;
+ ctx_texture_load (ctx, path, &width, &height, reteid);
+ if (reteid[0])
+ {
+ ctx_draw_texture_clipped (ctx, reteid, x, y, w, h, sx, sy, swidth, sheight);
+ }
}
void
-ctx_image_path (Ctx *ctx, const char *path, float x, float y)
+ctx_draw_image (Ctx *ctx, const char *path, float x, float y, float w, float h)
{
- int id = ctx_texture_load (ctx, -1, path, NULL, NULL);
- ctx_texture (ctx, id, x, y);
-
- // query if image exists ..
- // if it doesnt load, decode, encode, upload to path/
+ ctx_draw_image_clipped (ctx, path, x, y, w, h, 0,0,0,0);
}
-
void
ctx_set_pixel_u8 (Ctx *ctx, uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
@@ -22266,7 +25287,6 @@ ctx_set_pixel_u8 (Ctx *ctx, uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_
ctx_process (ctx, &command);
}
-
void
ctx_linear_gradient (Ctx *ctx, float x0, float y0, float x1, float y1)
{
@@ -22290,30 +25310,6 @@ ctx_radial_gradient (Ctx *ctx, float x0, float y0, float r0, float x1, float y1,
ctx_process (ctx, command);
}
-void ctx_gradient_add_stop_u8
-(Ctx *ctx, float pos, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
-{
- CtxEntry entry = ctx_f (CTX_GRADIENT_STOP, pos, 0);
- entry.data.u8[4+0] = r;
- entry.data.u8[4+1] = g;
- entry.data.u8[4+2] = b;
- entry.data.u8[4+3] = a;
- ctx_process (ctx, &entry);
-}
-
-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;
- ir = CTX_CLAMP (ir, 0,255);
- ig = CTX_CLAMP (ig, 0,255);
- ib = CTX_CLAMP (ib, 0,255);
- ia = CTX_CLAMP (ia, 0,255);
- ctx_gradient_add_stop_u8 (ctx, pos, ir, ig, ib, ia);
-}
void ctx_preserve (Ctx *ctx)
{
@@ -22359,16 +25355,18 @@ ctx_collect_events (CtxEvent *event, void *data, void *data2)
{
Ctx *ctx = (Ctx*)data;
CtxEvent *copy;
- if (event->type == CTX_KEY_DOWN && !strcmp (event->string, "idle"))
+ if (event->type == CTX_KEY_PRESS && !strcmp (event->string, "idle"))
return;
copy = (CtxEvent*)malloc (sizeof (CtxEvent));
*copy = *event;
+ if (copy->string)
+ copy->string = strdup (event->string);
ctx_list_append_full (&ctx->events.events, copy, ctx_event_free, NULL);
}
#endif
#if CTX_EVENTS
-static void _ctx_bindings_key_down (CtxEvent *event, void *data1, void *data2);
+static void _ctx_bindings_key_press (CtxEvent *event, void *data1, void *data2);
#endif
void ctx_reset (Ctx *ctx)
@@ -22376,7 +25374,7 @@ void ctx_reset (Ctx *ctx)
/* we do the callback reset first - maybe we need two cbs,
* one for before and one after default impl?
*
- * threaded fb and sdl needs to sync
+ * tiled fb and sdl needs to sync
*/
if (ctx->renderer && ctx->renderer->reset)
ctx->renderer->reset (ctx->renderer);
@@ -22393,19 +25391,16 @@ void ctx_reset (Ctx *ctx)
if (ctx->events.ctx_get_event_enabled)
{
ctx_clear_bindings (ctx);
+ ctx_listen_full (ctx, 0,0,0,0,
+ CTX_KEY_PRESS, _ctx_bindings_key_press, ctx, ctx,
+ NULL, NULL);
ctx_listen_full (ctx, 0,0,0,0,
- CTX_KEY_DOWN, _ctx_bindings_key_down, ctx, ctx,
+ CTX_KEY_UP, ctx_collect_events, ctx, ctx,
NULL, NULL);
-#if 0
- // should be enabled if a mask of CTX_KEY_DOWN|UP is passed to get_event?
- ctx_listen_full (ctx, 0, 0, 0,0,
+ ctx_listen_full (ctx, 0,0,0,0,
CTX_KEY_DOWN, ctx_collect_events, ctx, ctx,
NULL, NULL);
- ctx_listen_full (ctx, 0, 0, 0,0,
- CTX_KEY_UP, ctx_collect_events, ctx, ctx,
- NULL, NULL);
-#endif
ctx_listen_full (ctx, 0, 0, ctx->events.width, ctx->events.height,
(CtxEventType)(CTX_PRESS|CTX_RELEASE|CTX_MOTION), ctx_collect_events, ctx, ctx,
@@ -22425,7 +25420,7 @@ void ctx_clip (Ctx *ctx)
}
void
-ctx_set (Ctx *ctx, uint32_t key_hash, const char *string, int len);
+ctx_set (Ctx *ctx, uint64_t key_hash, const char *string, int len);
void ctx_save (Ctx *ctx)
{
@@ -22452,6 +25447,34 @@ void ctx_line_width (Ctx *ctx, float x)
CTX_PROCESS_F1 (CTX_LINE_WIDTH, x);
}
+float ctx_get_miter_limit (Ctx *ctx)
+{
+ return ctx->state.gstate.miter_limit;
+}
+
+float ctx_get_line_dash_offset (Ctx *ctx)
+{
+ return ctx->state.gstate.line_dash_offset;
+}
+
+void ctx_line_dash_offset (Ctx *ctx, float x)
+{
+ if (ctx->state.gstate.line_dash_offset != x)
+ CTX_PROCESS_F1 (CTX_LINE_DASH_OFFSET, x);
+}
+
+int ctx_get_image_smoothing (Ctx *ctx)
+{
+ return ctx->state.gstate.image_smoothing;
+}
+
+void ctx_image_smoothing (Ctx *ctx, int enabled)
+{
+ if (ctx_get_image_smoothing (ctx) != enabled)
+ CTX_PROCESS_U8 (CTX_IMAGE_SMOOTHING, enabled);
+}
+
+
void ctx_line_dash (Ctx *ctx, float *dashes, int count)
{
ctx_process_cmd_str_with_len (ctx, CTX_LINE_DASH, (char*)(dashes), count, 0, count * 4);
@@ -22535,7 +25558,7 @@ _ctx_font (Ctx *ctx, const char *name)
#if 0
void
-ctx_set (Ctx *ctx, uint32_t key_hash, const char *string, int len)
+ctx_set (Ctx *ctx, uint64_t key_hash, const char *string, int len)
{
if (len <= 0) len = strlen (string);
ctx_process_cmd_str (ctx, CTX_SET, string, key_hash, len);
@@ -22558,15 +25581,29 @@ ctx_get (Ctx *ctx, const char *key)
#endif
void
-ctx_font (Ctx *ctx, const char *name)
+ctx_font_family (Ctx *ctx, const char *name)
{
#if CTX_BACKEND_TEXT
ctx_process_cmd_str (ctx, CTX_FONT, name, 0, 0);
+ _ctx_font (ctx, name);
#else
_ctx_font (ctx, name);
#endif
}
+void
+ctx_font (Ctx *ctx, const char *family_name)
+{
+ // should also parse size
+ ctx_font_family (ctx, family_name);
+}
+
+const char *
+ctx_get_font (Ctx *ctx)
+{
+ return ctx_fonts[ctx->state.gstate.font].name;
+}
+
void ctx_line_to (Ctx *ctx, float x, float y)
{
if (!ctx->state.has_moved)
@@ -22648,11 +25685,47 @@ void ctx_rel_move_to (Ctx *ctx, float x, float y)
CTX_PROCESS_F (CTX_REL_MOVE_TO,x,y);
}
+CtxLineJoin ctx_get_line_join (Ctx *ctx)
+{
+ return ctx->state.gstate.line_join;
+}
+
+CtxCompositingMode ctx_get_compositing_mode (Ctx *ctx)
+{
+ return ctx->state.gstate.compositing_mode;
+}
+
+CtxBlend ctx_get_blend_mode (Ctx *ctx)
+{
+ return ctx->state.gstate.blend_mode;
+}
+
+CtxTextAlign ctx_get_text_align (Ctx *ctx)
+{
+ return (CtxTextAlign)ctx_state_get (&ctx->state, CTX_text_align);
+}
+
+CtxTextBaseline ctx_get_text_baseline (Ctx *ctx)
+{
+ return (CtxTextBaseline)ctx_state_get (&ctx->state, CTX_text_baseline);
+}
+
+CtxLineCap ctx_get_line_cap (Ctx *ctx)
+{
+ return ctx->state.gstate.line_cap;
+}
+
+CtxFillRule ctx_get_fill_rule (Ctx *ctx)
+{
+ return ctx->state.gstate.fill_rule;
+}
+
void ctx_line_cap (Ctx *ctx, CtxLineCap cap)
{
if (ctx->state.gstate.line_cap != cap)
CTX_PROCESS_U8 (CTX_LINE_CAP, cap);
}
+
void ctx_fill_rule (Ctx *ctx, CtxFillRule fill_rule)
{
if (ctx->state.gstate.fill_rule != fill_rule)
@@ -22665,11 +25738,13 @@ void ctx_line_join (Ctx *ctx, CtxLineJoin join)
}
void ctx_blend_mode (Ctx *ctx, CtxBlend mode)
{
- CTX_PROCESS_U8 (CTX_BLEND_MODE, mode);
+ if (ctx->state.gstate.blend_mode != mode)
+ CTX_PROCESS_U8 (CTX_BLEND_MODE, mode);
}
void ctx_compositing_mode (Ctx *ctx, CtxCompositingMode mode)
{
- CTX_PROCESS_U8 (CTX_COMPOSITING_MODE, mode);
+ if (ctx->state.gstate.compositing_mode != mode)
+ CTX_PROCESS_U8 (CTX_COMPOSITING_MODE, mode);
}
void ctx_text_align (Ctx *ctx, CtxTextAlign text_align)
{
@@ -22884,6 +25959,9 @@ ctx_flush (Ctx *ctx)
#endif
if (ctx->renderer && ctx->renderer->flush)
ctx->renderer->flush (ctx->renderer);
+ ctx->frame++;
+ if (ctx->texture_cache != ctx)
+ ctx->texture_cache->frame++;
ctx->drawlist.count = 0;
ctx_state_init (&ctx->state);
}
@@ -22896,6 +25974,9 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
CtxCommand *c = (CtxCommand *) entry;
switch (entry->code)
{
+ case CTX_LINE_DASH_OFFSET:
+ state->gstate.line_dash_offset = ctx_arg_float (0);
+ break;
case CTX_LINE_WIDTH:
state->gstate.line_width = ctx_arg_float (0);
break;
@@ -22950,12 +26031,25 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
(char*)c->colorspace.data,
c->colorspace.data_len);
break;
+ case CTX_IMAGE_SMOOTHING:
+ state->gstate.image_smoothing = c->entry.data.u8[0];
+ break;
case CTX_COLOR:
{
- CtxColor *color = &state->gstate.source.color;
- state->gstate.source.type = CTX_SOURCE_COLOR;
- switch ( (int) ctx_arg_float (0) )
+ CtxColor *color = &state->gstate.source_fill.color;
+
+ if ( ((int) ctx_arg_float (0)) & 512)
+ {
+ color = &state->gstate.source_stroke.color;
+ state->gstate.source_stroke.type = CTX_SOURCE_COLOR;
+ }
+ else
+ {
+ state->gstate.source_fill.type = CTX_SOURCE_COLOR;
+ }
+ //float components[5]={c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, c->cmyka.a};
+ switch ( ((int) ctx_arg_float (0)) & 511)
{
case CTX_RGB:
ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, 1.0f);
@@ -22991,8 +26085,8 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
break;
case CTX_SET_RGBA_U8:
//ctx_source_deinit (&state->gstate.source);
- state->gstate.source.type = CTX_SOURCE_COLOR;
- ctx_color_set_RGBA8 (state, &state->gstate.source.color,
+ state->gstate.source_fill.type = CTX_SOURCE_COLOR;
+ ctx_color_set_RGBA8 (state, &state->gstate.source_fill.color,
ctx_arg_u8 (0),
ctx_arg_u8 (1),
ctx_arg_u8 (2),
@@ -23024,15 +26118,15 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
dy = (y1-y0) / length;
start = (x0 * dx + y0 * dy) / length;
end = (x1 * dx + y1 * dy) / length;
- state->gstate.source.linear_gradient.length = length;
- state->gstate.source.linear_gradient.dx = dx;
- state->gstate.source.linear_gradient.dy = dy;
- state->gstate.source.linear_gradient.start = start;
- state->gstate.source.linear_gradient.end = end;
- state->gstate.source.linear_gradient.rdelta = (end-start)!=0.0?1.0f/(end - start):1.0;
- state->gstate.source.type = CTX_SOURCE_LINEAR_GRADIENT;
- state->gstate.source.transform = state->gstate.transform;
- ctx_matrix_invert (&state->gstate.source.transform);
+ state->gstate.source_fill.linear_gradient.length = length;
+ state->gstate.source_fill.linear_gradient.dx = dx;
+ state->gstate.source_fill.linear_gradient.dy = dy;
+ state->gstate.source_fill.linear_gradient.start = start;
+ state->gstate.source_fill.linear_gradient.end = end;
+ state->gstate.source_fill.linear_gradient.rdelta = (end-start)!=0.0?1.0f/(end - start):1.0;
+ state->gstate.source_fill.type = CTX_SOURCE_LINEAR_GRADIENT;
+ state->gstate.source_fill.transform = state->gstate.transform;
+ ctx_matrix_invert (&state->gstate.source_fill.transform);
}
break;
case CTX_RADIAL_GRADIENT:
@@ -23043,16 +26137,16 @@ ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
float x1 = ctx_arg_float (3);
float y1 = ctx_arg_float (4);
float r1 = ctx_arg_float (5);
- state->gstate.source.radial_gradient.x0 = x0;
- state->gstate.source.radial_gradient.y0 = y0;
- state->gstate.source.radial_gradient.r0 = r0;
- state->gstate.source.radial_gradient.x1 = x1;
- state->gstate.source.radial_gradient.y1 = y1;
- state->gstate.source.radial_gradient.r1 = r1;
- state->gstate.source.radial_gradient.rdelta = (r1 - r0) != 0.0 ? 1.0f/(r1-r0):0.0;
- state->gstate.source.type = CTX_SOURCE_RADIAL_GRADIENT;
- state->gstate.source.transform = state->gstate.transform;
- ctx_matrix_invert (&state->gstate.source.transform);
+ state->gstate.source_fill.radial_gradient.x0 = x0;
+ state->gstate.source_fill.radial_gradient.y0 = y0;
+ state->gstate.source_fill.radial_gradient.r0 = r0;
+ state->gstate.source_fill.radial_gradient.x1 = x1;
+ state->gstate.source_fill.radial_gradient.y1 = y1;
+ state->gstate.source_fill.radial_gradient.r1 = r1;
+ state->gstate.source_fill.radial_gradient.rdelta = (r1 - r0) != 0.0 ? 1.0f/(r1-r0):0.0;
+ state->gstate.source_fill.type = CTX_SOURCE_RADIAL_GRADIENT;
+ state->gstate.source_fill.transform = state->gstate.transform;
+ ctx_matrix_invert (&state->gstate.source_fill.transform);
}
break;
}
@@ -23372,6 +26466,7 @@ ctx_state_init (CtxState *state)
state->gstate.global_alpha_f = 1.0;
state->gstate.font_size = 12;
state->gstate.line_width = 2.0;
+ state->gstate.image_smoothing = 1;
ctx_state_set (state, CTX_line_spacing, 1.0f);
state->min_x = 8192;
state->min_y = 8192;
@@ -23408,6 +26503,7 @@ _ctx_init (Ctx *ctx)
#if CTX_BITPACK
ctx->drawlist.flags |= CTX_TRANSFORMATION_BITPACK;
#endif
+ ctx->texture_cache = ctx;
}
static void ctx_setup ();
@@ -23512,7 +26608,21 @@ ctx_render_ctx (Ctx *ctx, Ctx *d_ctx)
ctx_iterator_init (&iterator, &ctx->drawlist, 0,
CTX_ITERATOR_EXPAND_BITPACK);
while ( (command = ctx_iterator_next (&iterator) ) )
- { ctx_process (d_ctx, &command->entry); }
+ {
+#if 0
+ // if (command->entry.code == 'i' ||
+ // command->entry.code == 'I')
+ {
+
+ if (command->entry.code < 32 ||
+ command->entry.code > '~')
+ fprintf (stderr, "[%i]", command->entry.code);
+ else
+ fprintf (stderr, "%c", command->entry.code);
+ }
+#endif
+ ctx_process (d_ctx, &command->entry);
+ }
}
void ctx_quit (Ctx *ctx)
@@ -23531,13 +26641,33 @@ int ctx_has_quit (Ctx *ctx)
#endif
}
+int ctx_pixel_format_bits_per_pixel (CtxPixelFormat format)
+{
+ CtxPixelFormatInfo *info = ctx_pixel_format_info (format);
+ if (info)
+ return info->bpp;
+ return -1;
+}
-int ctx_pixel_format_bpp (CtxPixelFormat format)
+int ctx_pixel_format_get_stride (CtxPixelFormat format, int width)
{
CtxPixelFormatInfo *info = ctx_pixel_format_info (format);
if (info)
- return info->bpp;
- return -1;
+ {
+ switch (info->bpp)
+ {
+ case 0:
+ case 1:
+ return (width + 7)/8;
+ case 2:
+ return (width + 3)/4;
+ case 4:
+ return (width + 1)/2;
+ default:
+ return width * (info->bpp / 8);
+ }
+ }
+ return width;
}
int ctx_pixel_format_ebpp (CtxPixelFormat format)
@@ -23593,6 +26723,107 @@ void ctx_set_texture_source (Ctx *ctx, Ctx *texture_source)
((CtxRasterizer*)ctx->renderer)->texture_source = texture_source;
}
+void ctx_set_texture_cache (Ctx *ctx, Ctx *texture_cache)
+{
+ ctx->texture_cache = texture_cache;
+}
+
+void ctx_set_transform (Ctx *ctx, float a, float b, float c, float d, float e, float f)
+{
+ ctx_identity (ctx);
+ ctx_apply_transform (ctx, a, b, c, d, e, f);
+}
+#ifndef NO_LIBCURL
+#include <curl/curl.h>
+static size_t
+ctx_string_append_callback (void *contents, size_t size, size_t nmemb, void *userp)
+{
+ CtxString *string = (CtxString*)userp;
+ ctx_string_append_data ((CtxString*)string, contents, size * nmemb);
+ return size * nmemb;
+}
+
+#endif
+
+int
+ctx_get_contents (const char *uri,
+ unsigned char **contents,
+ long *length)
+{
+ char temp_uri[PATH_MAX]; // XXX XXX breaks with data uri's
+ if (uri[0] == '/')
+ {
+ snprintf (temp_uri, sizeof (temp_uri)-1, "file://%s", uri);
+ uri = temp_uri;
+ }
+ else
+ {
+ snprintf (temp_uri, sizeof (temp_uri)-1, uri);
+ uri = temp_uri;
+ }
+
+ if (strchr (uri, '#'))
+ strchr (uri, '#')[0]=0;
+
+ for (CtxList *l = registered_contents; l; l = l->next)
+ {
+ CtxFileContent *c = l->data;
+ if (!strcmp (c->path, uri))
+ {
+ contents = malloc (c->length+1);
+ contents[c->length]=0;
+ if (length) *length = c->length;
+ return 0;
+ }
+ }
+
+ if (!strncmp (uri, "file://", 5))
+ {
+ if (strchr (uri, '?'))
+ strchr (uri, '?')[0]=0;
+ }
+
+ if (!strncmp (uri, "file://", 7))
+ return __ctx_file_get_contents (uri + 7, contents, length);
+ else
+ {
+#ifndef NO_LIBCURL
+ CURL *curl = curl_easy_init ();
+ CURLcode res;
+
+ curl_easy_setopt(curl, CURLOPT_URL, uri);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ CtxString *string = ctx_string_new ("");
+
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ctx_string_append_callback);
+ /* we pass our 'chunk' struct to the callback function */
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)string);
+
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, "ctx/0.0");
+
+ res = curl_easy_perform(curl);
+ /* check for errors */
+ if(res != CURLE_OK) {
+ fprintf(stderr, "curl_easy_perform() failed: %s\n",
+ curl_easy_strerror(res));
+ curl_easy_cleanup (curl);
+ }
+ else
+ {
+ *contents = (unsigned char*)string->str;
+ *length = string->length;
+ ctx_string_free (string, 0);
+ curl_easy_cleanup (curl);
+ return 0;
+ }
+#else
+ return __ctx_file_get_contents (uri, contents, length);
+#endif
+ }
+ return -1;
+}
+
+
#endif
#endif // CTX_IMPLEMENTATION
@@ -23716,7 +26947,6 @@ ctx_fragment_gradient_1d_RGBA8 (CtxRasterizer *rasterizer, float x, float y, uin
}
#endif
-
CTX_INLINE static void
ctx_RGBA8_associate_alpha (uint8_t *u8)
{
@@ -23739,7 +26969,6 @@ ctx_RGBA8_associate_alpha (uint8_t *u8)
}
}
-
CTX_INLINE static void
ctx_u8_associate_alpha (int components, uint8_t *u8)
{
@@ -23883,13 +27112,13 @@ static void
ctx_fragment_image_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
uint8_t *rgba = (uint8_t *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
- CtxBuffer *buffer = g->image.buffer;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ CtxBuffer *buffer = g->texture.buffer->color_managed;
ctx_assert (rasterizer);
ctx_assert (g);
ctx_assert (buffer);
- int u = x - g->image.x0;
- int v = y - g->image.y0;
+ int u = x - g->texture.x0;
+ int v = y - g->texture.y0;
if ( u < 0 || v < 0 ||
u >= buffer->width ||
v >= buffer->height)
@@ -23899,6 +27128,57 @@ ctx_fragment_image_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out
else
{
int bpp = buffer->format->bpp/8;
+ if (rasterizer->state->gstate.image_smoothing)
+ {
+ uint8_t *src00 = (uint8_t *) buffer->data;
+ src00 += v * buffer->stride + u * bpp;
+ uint8_t *src01 = src00;
+ if ( u + 1 < buffer->width)
+ {
+ src01 = src00 + bpp;
+ }
+ uint8_t *src11 = src01;
+ uint8_t *src10 = src00;
+ if ( v + 1 < buffer->height)
+ {
+ src10 = src00 + buffer->stride;
+ src11 = src01 + buffer->stride;
+ }
+ float dx = (x-(int)(x)) * 255.9;
+ float dy = (y-(int)(y)) * 255.9;
+
+ 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[3] = 255;
+ 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);
+ 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[3]=255;
+ break;
+ 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);
+
+ }
+ }
+ }
+ else
+ {
uint8_t *src = (uint8_t *) buffer->data;
src += v * buffer->stride + u * bpp;
switch (bpp)
@@ -23923,132 +27203,450 @@ ctx_fragment_image_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out
{ rgba[c] = src[c]; }
break;
}
+ }
+ if (rasterizer->swap_red_green)
+ {
+ uint8_t tmp = rgba[0];
+ rgba[0] = rgba[2];
+ rgba[2] = tmp;
+ }
+ }
+}
+
+#if CTX_DITHER
+static inline int ctx_dither_mask_a (int x, int y, int c, int divisor)
+{
+ /* https://pippin.gimp.org/a_dither/ */
+ return ( ( ( ( (x + c * 67) + y * 236) * 119) & 255 )-127) / divisor;
+}
+
+inline static void
+ctx_dither_rgba_u8 (uint8_t *rgba, int x, int y, int dither_red_blue, int dither_green)
+{
+ if (dither_red_blue == 0)
+ { return; }
+ for (int c = 0; c < 3; c ++)
+ {
+ int val = rgba[c] + ctx_dither_mask_a (x, y, 0, c==1?dither_green:dither_red_blue);
+ rgba[c] = CTX_CLAMP (val, 0, 255);
+ }
+}
+
+inline static void
+ctx_dither_graya_u8 (uint8_t *rgba, int x, int y, int dither_red_blue, int dither_green)
+{
+ if (dither_red_blue == 0)
+ { return; }
+ for (int c = 0; c < 1; c ++)
+ {
+ int val = rgba[c] + ctx_dither_mask_a (x, y, 0, dither_red_blue);
+ rgba[c] = CTX_CLAMP (val, 0, 255);
+ }
+}
+#endif
+
+CTX_INLINE static void
+ctx_RGBA8_deassociate_alpha (const uint8_t *in, uint8_t *out)
+{
+ uint32_t val = *((uint32_t*)(in));
+ int a = val >> CTX_RGBA8_A_SHIFT;
+ if (a)
+ {
+ if (a ==255)
+ {
+ *((uint32_t*)(out)) = val;
+ } else
+ {
+ uint32_t g = (((val & CTX_RGBA8_G_MASK) * 255 / a) >> 8) & CTX_RGBA8_G_MASK;
+ uint32_t rb =(((val & CTX_RGBA8_RB_MASK) * 255 / a) >> 8) & CTX_RGBA8_RB_MASK;
+ *((uint32_t*)(out)) = g|rb|(a << CTX_RGBA8_A_SHIFT);
+ }
+ }
+ else
+ {
+ *((uint32_t*)(out)) = 0;
+ }
+}
+
+CTX_INLINE static void
+ctx_u8_deassociate_alpha (int components, const uint8_t *in, uint8_t *out)
+{
+ if (in[components-1])
+ {
+ if (in[components-1] != 255)
+ for (int c = 0; c < components-1; c++)
+ out[c] = (in[c] * 255) / in[components-1];
+ else
+ for (int c = 0; c < components-1; c++)
+ out[c] = in[c];
+ out[components-1] = in[components-1];
+ }
+ else
+ {
+ for (int c = 0; c < components; c++)
+ out[c] = 0;
+ }
+}
+
+CTX_INLINE static void
+ctx_float_associate_alpha (int components, float *rgba)
+{
+ float alpha = rgba[components-1];
+ for (int c = 0; c < components-1; c++)
+ rgba[c] *= alpha;
+}
+
+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;
+
+ for (int c = 0; c < components-1; c++)
+ dst[c] = (rgba[c] * ralpha);
+ dst[components-1] = rgba[components-1];
+}
+
+CTX_INLINE static void
+ctx_RGBAF_associate_alpha (float *rgba)
+{
+ ctx_float_associate_alpha (4, rgba);
+}
+
+CTX_INLINE static void
+ctx_RGBAF_deassociate_alpha (float *rgba, float *dst)
+{
+ ctx_float_deassociate_alpha (4, rgba, dst);
+}
+
+/**** rgb8 ***/
+
+static void
+ctx_fragment_image_rgb8_RGBA8_box (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ void *out)
+{
+ uint8_t *rgba = (uint8_t *) out;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ CtxBuffer *buffer = g->texture.buffer->color_managed;
+
+ int u = x - g->texture.x0;
+ int v = y - g->texture.y0;
+ if ( u < 0 || v < 0 ||
+ u >= buffer->width ||
+ v >= buffer->height)
+ {
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
+ }
+ else
+ {
+ int bpp = 3;
+ rgba[3]=255;
+ float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
+ int dim = (1.0 / factor) / 2;
+ uint64_t sum[4]={0,0,0,0};
+ int count = 0;
+ for (int ou = - dim; ou < dim; ou++)
+ for (int ov = - dim; ov < dim; ov++)
+ {
+ uint8_t *src = (uint8_t *) buffer->data;
+ int o = (v+ov) * buffer->width + (u + ou);
+
+ if (o>=0 && o < buffer->width * buffer->height)
+ {
+ src += o * bpp;
+
+ for (int c = 0; c < bpp; c++)
+ sum[c] += src[c];
+ count ++;
+ }
+ }
+ if (count)
+ for (int c = 0; c < bpp; c++)
+ rgba[c] = sum[c]/count;
+
+ if (rasterizer->swap_red_green)
+ {
+ uint8_t tmp = rgba[0];
+ rgba[0] = rgba[2];
+ rgba[2] = tmp;
+ }
+ }
+#if CTX_DITHER
+//ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
+// rasterizer->format->dither_green);
+#endif
+}
+
+static void
+ctx_fragment_image_rgb8_RGBA8_bi (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ void *out)
+{
+ uint8_t *rgba = (uint8_t *) out;
+
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ CtxBuffer *buffer = g->texture.buffer->color_managed;
+
+ int u = x - g->texture.x0;
+ int v = y - g->texture.y0;
+ if ( u < 0 || v < 0 ||
+ u >= buffer->width ||
+ v >= buffer->height)
+ {
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
+ }
+ else
+ {
+ int bpp = 3;
+ rgba[3]=255;
+ uint8_t *src00 = (uint8_t *) buffer->data;
+ src00 += v * buffer->stride + u * bpp;
+ uint8_t *src01 = src00;
+ if ( u + 1 < buffer->width)
+ {
+ src01 = src00 + bpp;
+ }
+ uint8_t *src11 = src01;
+ uint8_t *src10 = src00;
+ if ( v + 1 < buffer->height)
+ {
+ src10 = src00 + buffer->stride;
+ src11 = src01 + buffer->stride;
+ }
+ float dx = (x-(int)(x)) * 255.9;
+ float dy = (y-(int)(y)) * 255.9;
+ 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);
+ }
+
+ if (rasterizer->swap_red_green)
+ {
+ uint8_t tmp = rgba[0];
+ rgba[0] = rgba[2];
+ rgba[2] = tmp;
+ }
+ }
+#if CTX_DITHER
+//ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
+// rasterizer->format->dither_green);
+#endif
+}
+
+static void
+ctx_fragment_image_rgb8_RGBA8_nearest (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ void *out)
+{
+ uint8_t *rgba = (uint8_t *) out;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ CtxBuffer *buffer = g->texture.buffer->color_managed;
+
+ x += 0.5;
+ y += 0.5;
+
+ int u = x - g->texture.x0;
+ int v = y - g->texture.y0;
+ if ( u < 0 || v < 0 ||
+ u >= buffer->width ||
+ v >= buffer->height)
+ {
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
+ }
+ else
+ {
+ int bpp = 3;
+ {
+ uint8_t *src00 = (uint8_t *) buffer->data;
+ src00 += v * buffer->stride + u * bpp;
+ for (int c = 0; c < bpp; c++)
+ { rgba[c] = src00[c]; }
+ }
if (rasterizer->swap_red_green)
{
uint8_t tmp = rgba[0];
rgba[0] = rgba[2];
rgba[2] = tmp;
}
+ rgba[3]=255;
}
-}
-
#if CTX_DITHER
-static inline int ctx_dither_mask_a (int x, int y, int c, int divisor)
-{
- /* https://pippin.gimp.org/a_dither/ */
- return ( ( ( ( (x + c * 67) + y * 236) * 119) & 255 )-127) / divisor;
-}
-
-inline static void
-ctx_dither_rgba_u8 (uint8_t *rgba, int x, int y, int dither_red_blue, int dither_green)
-{
- if (dither_red_blue == 0)
- { return; }
- for (int c = 0; c < 3; c ++)
- {
- int val = rgba[c] + ctx_dither_mask_a (x, y, 0, c==1?dither_green:dither_red_blue);
- rgba[c] = CTX_CLAMP (val, 0, 255);
- }
+ //ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
+ // rasterizer->format->dither_green);
+#endif
}
-inline static void
-ctx_dither_graya_u8 (uint8_t *rgba, int x, int y, int dither_red_blue, int dither_green)
+static void
+ctx_fragment_image_rgb8_RGBA8 (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ void *out)
{
- if (dither_red_blue == 0)
- { return; }
- for (int c = 0; c < 1; c ++)
+ if (rasterizer->state->gstate.image_smoothing)
+ {
+ float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
+ if (factor < 0.5)
{
- int val = rgba[c] + ctx_dither_mask_a (x, y, 0, dither_red_blue);
- rgba[c] = CTX_CLAMP (val, 0, 255);
+ ctx_fragment_image_rgb8_RGBA8_box (rasterizer, x, y, out);
}
-}
-#endif
-
-CTX_INLINE static void
-ctx_RGBA8_deassociate_alpha (const uint8_t *in, uint8_t *out)
-{
- uint32_t val = *((uint32_t*)(in));
- int a = val >> CTX_RGBA8_A_SHIFT;
- if (a)
- {
- if (a ==255)
- {
- *((uint32_t*)(out)) = val;
- } else
+ else if (factor > 0.99 && factor < 1.01)
{
- uint32_t g = (((val & CTX_RGBA8_G_MASK) * 255 / a) >> 8) & CTX_RGBA8_G_MASK;
- uint32_t rb =(((val & CTX_RGBA8_RB_MASK) * 255 / a) >> 8) & CTX_RGBA8_RB_MASK;
- *((uint32_t*)(out)) = g|rb|(a << CTX_RGBA8_A_SHIFT);
- }
+ // XXX missing translate test
+ ctx_fragment_image_rgb8_RGBA8_nearest (rasterizer, x, y, out);
}
else
{
- *((uint32_t*)(out)) = 0;
+ ctx_fragment_image_rgb8_RGBA8_bi (rasterizer, x, y, out);
}
-}
-
-CTX_INLINE static void
-ctx_u8_deassociate_alpha (int components, const uint8_t *in, uint8_t *out)
-{
- if (in[components-1])
- {
- if (in[components-1] != 255)
- for (int c = 0; c < components-1; c++)
- out[c] = (in[c] * 255) / in[components-1];
- else
- for (int c = 0; c < components-1; c++)
- out[c] = in[c];
- out[components-1] = in[components-1];
}
else
{
- for (int c = 0; c < components; c++)
- out[c] = 0;
+ ctx_fragment_image_rgb8_RGBA8_nearest (rasterizer, x, y, out);
}
+#if CTX_DITHER
+ uint8_t *rgba = out;
+ ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
+ rasterizer->format->dither_green);
+#endif
}
-CTX_INLINE static void
-ctx_float_associate_alpha (int components, float *rgba)
-{
- float alpha = rgba[components-1];
- for (int c = 0; c < components-1; c++)
- rgba[c] *= alpha;
-}
-CTX_INLINE static void
-ctx_float_deassociate_alpha (int components, float *rgba, float *dst)
+/************** rgba8 */
+
+static void
+ctx_fragment_image_rgba8_RGBA8_box (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ void *out)
{
- float ralpha = rgba[components-1];
- if (ralpha != 0.0) ralpha = 1.0/ralpha;
+ uint8_t *rgba = (uint8_t *) out;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ CtxBuffer *buffer = g->texture.buffer->color_managed;
- for (int c = 0; c < components-1; c++)
- dst[c] = (rgba[c] * ralpha);
- dst[components-1] = rgba[components-1];
-}
+ int u = x - g->texture.x0;
+ int v = y - g->texture.y0;
+ if ( u < 0 || v < 0 ||
+ u >= buffer->width ||
+ v >= buffer->height)
+ {
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
+ }
+ else
+ {
+ int bpp = 4;
+ float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
+ int dim = (1.0 / factor) / 2;
+ uint64_t sum[4]={0,0,0,0};
+ int count = 0;
+ for (int ou = - dim; ou < dim; ou++)
+ for (int ov = - dim; ov < dim; ov++)
+ {
+ uint8_t *src = (uint8_t *) buffer->data;
+ int o = (v+ov) * buffer->width + (u + ou);
-CTX_INLINE static void
-ctx_RGBAF_associate_alpha (float *rgba)
-{
- ctx_float_associate_alpha (4, rgba);
+ if (o>=0 && o < buffer->width * buffer->height)
+ {
+ src += o * bpp;
+
+ for (int c = 0; c < bpp; c++)
+ sum[c] += src[c];
+ count ++;
+ }
+ }
+ if (count)
+ for (int c = 0; c < bpp; c++)
+ rgba[c] = sum[c]/count;
+
+ if (rasterizer->swap_red_green)
+ {
+ uint8_t tmp = rgba[0];
+ rgba[0] = rgba[2];
+ rgba[2] = tmp;
+ }
+ }
+#if CTX_DITHER
+//ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
+// rasterizer->format->dither_green);
+#endif
}
-CTX_INLINE static void
-ctx_RGBAF_deassociate_alpha (float *rgba, float *dst)
+static void
+ctx_fragment_image_rgba8_RGBA8_bi (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ void *out)
{
- ctx_float_deassociate_alpha (4, rgba, dst);
+ uint8_t *rgba = (uint8_t *) out;
+
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ CtxBuffer *buffer = g->texture.buffer->color_managed;
+
+ int u = x - g->texture.x0;
+ int v = y - g->texture.y0;
+ if ( u < 0 || v < 0 ||
+ u >= buffer->width ||
+ v >= buffer->height)
+ {
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
+ }
+ else
+ {
+ int bpp = 4;
+ uint8_t *src00 = (uint8_t *) buffer->data;
+ src00 += v * buffer->stride + u * bpp;
+ uint8_t *src01 = src00;
+ if ( u + 1 < buffer->width)
+ {
+ src01 = src00 + bpp;
+ }
+ uint8_t *src11 = src01;
+ uint8_t *src10 = src00;
+ if ( v + 1 < buffer->height)
+ {
+ src10 = src00 + buffer->stride;
+ src11 = src01 + buffer->stride;
+ }
+ float dx = (x-(int)(x)) * 255.9;
+ float dy = (y-(int)(y)) * 255.9;
+ 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);
+ }
+
+ if (rasterizer->swap_red_green)
+ {
+ uint8_t tmp = rgba[0];
+ rgba[0] = rgba[2];
+ rgba[2] = tmp;
+ }
+ }
+#if CTX_DITHER
+//ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
+// rasterizer->format->dither_green);
+#endif
}
static void
-ctx_fragment_image_rgba8_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
+ctx_fragment_image_rgba8_RGBA8_nearest (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ void *out)
{
uint8_t *rgba = (uint8_t *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
- CtxBuffer *buffer = g->image.buffer;
- ctx_assert (rasterizer);
- ctx_assert (g);
- ctx_assert (buffer);
- int u = x - g->image.x0;
- int v = y - g->image.y0;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ CtxBuffer *buffer = g->texture.buffer->color_managed;
+
+ x += 0.5;
+ y += 0.5;
+
+ int u = x - g->texture.x0;
+ int v = y - g->texture.y0;
if ( u < 0 || v < 0 ||
u >= buffer->width ||
v >= buffer->height)
@@ -24058,19 +27656,54 @@ ctx_fragment_image_rgba8_RGBA8 (CtxRasterizer *rasterizer, float x, float y, voi
else
{
int bpp = 4;
- uint8_t *src = (uint8_t *) buffer->data;
- src += v * buffer->stride + u * bpp;
- for (int c = 0; c < 4; c++)
- { rgba[c] = src[c]; }
+ {
+ uint8_t *src00 = (uint8_t *) buffer->data;
+ src00 += v * buffer->stride + u * bpp;
+ for (int c = 0; c < bpp; c++)
+ { rgba[c] = src00[c]; }
+ }
+ if (rasterizer->swap_red_green)
+ {
+ uint8_t tmp = rgba[0];
+ rgba[0] = rgba[2];
+ rgba[2] = tmp;
+ }
+ }
+#if CTX_DITHER
+ //ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
+ // rasterizer->format->dither_green);
+#endif
+}
- if (rasterizer->swap_red_green)
+static void
+ctx_fragment_image_rgba8_RGBA8 (CtxRasterizer *rasterizer,
+ float x,
+ float y,
+ void *out)
+{
+ if (rasterizer->state->gstate.image_smoothing)
{
- uint8_t tmp = rgba[0];
- rgba[0] = rgba[2];
- rgba[2] = tmp;
- }
+ float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
+ if (factor < 0.5)
+ {
+ ctx_fragment_image_rgba8_RGBA8_box (rasterizer, x, y, out);
+ }
+ else if (factor > 0.99 && factor < 1.01)
+ {
+ // XXX: also verify translate == 0 for this fast path to be valid
+ ctx_fragment_image_rgba8_RGBA8_nearest (rasterizer, x, y, out);
+ }
+ else
+ {
+ ctx_fragment_image_rgba8_RGBA8_bi (rasterizer, x, y, out);
}
+ }
+ else
+ {
+ ctx_fragment_image_rgba8_RGBA8_nearest (rasterizer, x, y, out);
+ }
#if CTX_DITHER
+ uint8_t *rgba = out;
ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
rasterizer->format->dither_green);
#endif
@@ -24080,13 +27713,13 @@ static void
ctx_fragment_image_gray1_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
uint8_t *rgba = (uint8_t *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
- CtxBuffer *buffer = g->image.buffer;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ CtxBuffer *buffer = g->texture.buffer;
ctx_assert (rasterizer);
ctx_assert (g);
ctx_assert (buffer);
- int u = x - g->image.x0;
- int v = y - g->image.y0;
+ int u = x - g->texture.x0;
+ int v = y - g->texture.y0;
if ( u < 0 || v < 0 ||
u >= buffer->width ||
v >= buffer->height)
@@ -24104,55 +27737,19 @@ ctx_fragment_image_gray1_RGBA8 (CtxRasterizer *rasterizer, float x, float y, voi
else
{
for (int c = 0; c < 4; c++)
- { rgba[c] = g->image.rgba[c]; }
+ { rgba[c] = 255;
+ }//g->texture.rgba[c];
+ //}
}
}
}
-static void
-ctx_fragment_image_rgb8_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
-{
- uint8_t *rgba = (uint8_t *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
- CtxBuffer *buffer = g->image.buffer;
- ctx_assert (rasterizer);
- ctx_assert (g);
- ctx_assert (buffer);
- int u = x - g->image.x0;
- int v = y - g->image.y0;
- if ( (u < 0) || (v < 0) ||
- (u >= buffer->width-1) ||
- (v >= buffer->height-1) )
- {
- rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
- }
- else
- {
- int bpp = 3;
- uint8_t *src = (uint8_t *) buffer->data;
- src += v * buffer->stride + u * bpp;
- for (int c = 0; c < 3; c++)
- { rgba[c] = src[c]; }
- rgba[3] = 255;
- if (rasterizer->swap_red_green)
- {
- uint8_t tmp = rgba[0];
- rgba[0] = rgba[2];
- rgba[2] = tmp;
- }
- }
-#if CTX_DITHER
- ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
- rasterizer->format->dither_green);
-#endif
-}
-
#if CTX_GRADIENTS
static void
ctx_fragment_radial_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
uint8_t *rgba = (uint8_t *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = (ctx_hypotf (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y) -
g->radial_gradient.r0) * (g->radial_gradient.rdelta);
#if CTX_GRADIENT_CACHE
@@ -24171,7 +27768,7 @@ static void
ctx_fragment_linear_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
uint8_t *rgba = (uint8_t *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
g->linear_gradient.length) -
g->linear_gradient.start) * (g->linear_gradient.rdelta);
@@ -24193,7 +27790,7 @@ static void
ctx_fragment_color_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
uint8_t *rgba = (uint8_t *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
ctx_color_get_rgba8 (rasterizer->state, &g->color, rgba);
if (rasterizer->swap_red_green)
{
@@ -24209,7 +27806,7 @@ static void
ctx_fragment_linear_gradient_RGBAF (CtxRasterizer *rasterizer, float x, float y, void *out)
{
float *rgba = (float *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
g->linear_gradient.length) -
g->linear_gradient.start) * (g->linear_gradient.rdelta);
@@ -24220,7 +27817,7 @@ static void
ctx_fragment_radial_gradient_RGBAF (CtxRasterizer *rasterizer, float x, float y, void *out)
{
float *rgba = (float *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = ctx_hypotf (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y);
v = (v - g->radial_gradient.r0) * (g->radial_gradient.rdelta);
ctx_fragment_gradient_1d_RGBAF (rasterizer, v, 0.0f, rgba);
@@ -24232,7 +27829,7 @@ static void
ctx_fragment_color_RGBAF (CtxRasterizer *rasterizer, float x, float y, void *out)
{
float *rgba = (float *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
ctx_color_get_rgba (rasterizer->state, &g->color, rgba);
}
@@ -24241,7 +27838,7 @@ static void ctx_fragment_image_RGBAF (CtxRasterizer *rasterizer, float x, float
float *outf = (float *) out;
uint8_t rgba[4];
CtxGState *gstate = &rasterizer->state->gstate;
- CtxBuffer *buffer = gstate->source.image.buffer;
+ CtxBuffer *buffer = gstate->source_fill.texture.buffer;
switch (buffer->format->bpp)
{
case 1: ctx_fragment_image_gray1_RGBA8 (rasterizer, x, y, rgba); break;
@@ -24255,9 +27852,9 @@ static void ctx_fragment_image_RGBAF (CtxRasterizer *rasterizer, float x, float
static CtxFragment ctx_rasterizer_get_fragment_RGBAF (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
- case CTX_SOURCE_IMAGE: return ctx_fragment_image_RGBAF;
+ case CTX_SOURCE_TEXTURE: return ctx_fragment_image_RGBAF;
case CTX_SOURCE_COLOR: return ctx_fragment_color_RGBAF;
#if CTX_GRADIENTS
case CTX_SOURCE_LINEAR_GRADIENT: return ctx_fragment_linear_gradient_RGBAF;
@@ -24271,15 +27868,48 @@ static CtxFragment ctx_rasterizer_get_fragment_RGBAF (CtxRasterizer *rasterizer)
static CtxFragment ctx_rasterizer_get_fragment_RGBA8 (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
- CtxBuffer *buffer = gstate->source.image.buffer;
- switch (gstate->source.type)
+ CtxBuffer *buffer = gstate->source_fill.texture.buffer;
+ switch (gstate->source_fill.type)
{
- case CTX_SOURCE_IMAGE:
+ case CTX_SOURCE_TEXTURE:
switch (buffer->format->bpp)
{
case 1: return ctx_fragment_image_gray1_RGBA8;
- case 24: return ctx_fragment_image_rgb8_RGBA8;
- case 32: return ctx_fragment_image_rgba8_RGBA8;
+ case 24:
+ {
+ if (gstate->image_smoothing)
+ {
+ float factor = ctx_matrix_get_scale (&gstate->transform);
+ if (factor < 0.5)
+ return ctx_fragment_image_rgb8_RGBA8_box;
+ else if (factor > 0.99 && factor < 1.01)
+ return ctx_fragment_image_rgb8_RGBA8_nearest;
+ else
+ return ctx_fragment_image_rgb8_RGBA8_bi;
+ }
+ else
+ {
+ return ctx_fragment_image_rgb8_RGBA8_nearest;
+ }
+ }
+ break;
+ case 32:
+ {
+ if (gstate->image_smoothing)
+ {
+ float factor = ctx_matrix_get_scale (&gstate->transform);
+ if (factor < 0.5)
+ return ctx_fragment_image_rgba8_RGBA8_box;
+ else if (factor > 0.99 && factor < 1.01)
+ return ctx_fragment_image_rgba8_RGBA8_nearest;
+ else
+ return ctx_fragment_image_rgba8_RGBA8_bi;
+ }
+ else
+ {
+ return ctx_fragment_image_rgba8_RGBA8_nearest;
+ }
+ }
default: return ctx_fragment_image_RGBA8;
}
case CTX_SOURCE_COLOR: return ctx_fragment_color_RGBA8;
@@ -24302,14 +27932,14 @@ ctx_init_uv (CtxRasterizer *rasterizer,
float u1 = *u0 + count;
float v1 = *v0;
- ctx_matrix_apply_transform (&gstate->source.transform, u0, v0);
- ctx_matrix_apply_transform (&gstate->source.transform, &u1, &v1);
+ ctx_matrix_apply_transform (&gstate->source_fill.transform, u0, v0);
+ ctx_matrix_apply_transform (&gstate->source_fill.transform, &u1, &v1);
*ud = (u1-*u0) / (count);
*vd = (v1-*v0) / (count);
}
-#if 0
+#if 1
static void
ctx_u8_source_over_normal_opaque_color (int components, CTX_COMPOSITE_ARGUMENTS)
{
@@ -24491,7 +28121,7 @@ ctx_porter_duff_factors(mode, foo, bar)\
}\
}
-#if 0
+#if 1
static void
ctx_u8_source_over_normal_color (int components,
CtxRasterizer *rasterizer,
@@ -24542,7 +28172,7 @@ ctx_u8_source_over_normal_color (int components,
static void
ctx_RGBA8_source_over_normal_linear_gradient (CTX_COMPOSITE_ARGUMENTS)
{
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float u0 = 0; float v0 = 0;
float ud = 0; float vd = 0;
ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
@@ -24760,7 +28390,7 @@ ctx_RGBA8_source_over_normal_linear_gradient (CTX_COMPOSITE_ARGUMENTS)
static void
ctx_RGBA8_source_over_normal_radial_gradient (CTX_COMPOSITE_ARGUMENTS)
{
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float u0 = 0; float v0 = 0;
float ud = 0; float vd = 0;
ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
@@ -26102,6 +29732,7 @@ CTX_COMPOSITE_SUFFIX(ctx_RGBA8_nop) (CTX_COMPOSITE_ARGUMENTS)
{
}
+
static void
ctx_setup_RGBA8 (CtxRasterizer *rasterizer)
{
@@ -26109,6 +29740,8 @@ ctx_setup_RGBA8 (CtxRasterizer *rasterizer)
int components = 4;
rasterizer->fragment = ctx_rasterizer_get_fragment_RGBA8 (rasterizer);
rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_RGBA8_porter_duff_generic);
+
+
#if 1
if (gstate->compositing_mode == CTX_COMPOSITE_CLEAR)
{
@@ -26118,14 +29751,14 @@ ctx_setup_RGBA8 (CtxRasterizer *rasterizer)
#endif
#if CTX_INLINED_GRADIENTS
#if CTX_GRADIENTS
- if (gstate->source.type == CTX_SOURCE_LINEAR_GRADIENT &&
+ if (gstate->source_fill.type == CTX_SOURCE_LINEAR_GRADIENT &&
gstate->blend_mode == CTX_BLEND_NORMAL &&
gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
{
rasterizer->comp_op = ctx_RGBA8_source_over_normal_linear_gradient;
return;
}
- if (gstate->source.type == CTX_SOURCE_RADIAL_GRADIENT &&
+ if (gstate->source_fill.type == CTX_SOURCE_RADIAL_GRADIENT &&
gstate->blend_mode == CTX_BLEND_NORMAL &&
gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
{
@@ -26135,9 +29768,9 @@ ctx_setup_RGBA8 (CtxRasterizer *rasterizer)
#endif
#endif
- if (gstate->source.type == CTX_SOURCE_COLOR)
+ if (gstate->source_fill.type == CTX_SOURCE_COLOR)
{
- ctx_color_get_rgba8 (rasterizer->state, &gstate->source.color, rasterizer->color);
+ ctx_color_get_rgba8 (rasterizer->state, &gstate->source_fill.color, rasterizer->color);
if (gstate->global_alpha_u8 != 255)
rasterizer->color[components-1] = (rasterizer->color[components-1] * gstate->global_alpha_u8)/255;
if (rasterizer->swap_red_green)
@@ -26181,7 +29814,7 @@ ctx_setup_RGBA8 (CtxRasterizer *rasterizer)
#if CTX_INLINED_NORMAL
if (gstate->blend_mode == CTX_BLEND_NORMAL)
{
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
return; // exhaustively handled above;
@@ -26193,10 +29826,10 @@ ctx_setup_RGBA8 (CtxRasterizer *rasterizer)
rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_RGBA8_porter_duff_radial_gradient_normal);
break;
#endif
- case CTX_SOURCE_IMAGE:
+ case CTX_SOURCE_TEXTURE:
{
- CtxSource *g = &rasterizer->state->gstate.source;
- switch (g->image.buffer->format->bpp)
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
+ switch (g->texture.buffer->format->bpp)
{
case 32:
rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_RGBA8_porter_duff_image_rgba8_normal);
@@ -26811,11 +30444,11 @@ ctx_setup_RGBAF (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
int components = 4;
- if (gstate->source.type == CTX_SOURCE_COLOR)
+ if (gstate->source_fill.type == CTX_SOURCE_COLOR)
{
rasterizer->comp_op = ctx_RGBAF_porter_duff_color;
rasterizer->fragment = NULL;
- ctx_color_get_rgba (rasterizer->state, &gstate->source.color, (float*)rasterizer->color);
+ ctx_color_get_rgba (rasterizer->state, &gstate->source_fill.color, (float*)rasterizer->color);
if (gstate->global_alpha_u8 != 255)
for (int c = 0; c < components; c ++)
((float*)rasterizer->color)[c] *= gstate->global_alpha_f;
@@ -26843,7 +30476,7 @@ ctx_setup_RGBAF (CtxRasterizer *rasterizer)
rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_RGBA8_nop);
}
else
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
if (gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
@@ -26870,7 +30503,7 @@ ctx_setup_RGBAF (CtxRasterizer *rasterizer)
rasterizer->comp_op = ctx_RGBAF_porter_duff_radial_gradient_normal;
break;
#endif
- case CTX_SOURCE_IMAGE:
+ case CTX_SOURCE_TEXTURE:
rasterizer->comp_op = ctx_RGBAF_porter_duff_image_normal;
break;
default:
@@ -26879,7 +30512,7 @@ ctx_setup_RGBAF (CtxRasterizer *rasterizer)
}
break;
default:
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
rasterizer->comp_op = ctx_RGBAF_porter_duff_color;
@@ -26893,7 +30526,7 @@ ctx_setup_RGBAF (CtxRasterizer *rasterizer)
rasterizer->comp_op = ctx_RGBAF_porter_duff_radial_gradient;
break;
#endif
- case CTX_SOURCE_IMAGE:
+ case CTX_SOURCE_TEXTURE:
rasterizer->comp_op = ctx_RGBAF_porter_duff_image;
break;
default:
@@ -26913,7 +30546,7 @@ static void
ctx_fragment_linear_gradient_GRAYAF (CtxRasterizer *rasterizer, float x, float y, void *out)
{
float rgba[4];
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
g->linear_gradient.length) -
g->linear_gradient.start) * (g->linear_gradient.rdelta);
@@ -26926,7 +30559,7 @@ static void
ctx_fragment_radial_gradient_GRAYAF (CtxRasterizer *rasterizer, float x, float y, void *out)
{
float rgba[4];
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = 0.0f;
if ((g->radial_gradient.r1-g->radial_gradient.r0) > 0.0f)
{
@@ -26942,7 +30575,7 @@ ctx_fragment_radial_gradient_GRAYAF (CtxRasterizer *rasterizer, float x, float y
static void
ctx_fragment_color_GRAYAF (CtxRasterizer *rasterizer, float x, float y, void *out)
{
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
ctx_color_get_graya (rasterizer->state, &g->color, (float*)out);
}
@@ -26951,7 +30584,7 @@ static void ctx_fragment_image_GRAYAF (CtxRasterizer *rasterizer, float x, float
uint8_t rgba[4];
float rgbaf[4];
CtxGState *gstate = &rasterizer->state->gstate;
- CtxBuffer *buffer = gstate->source.image.buffer;
+ CtxBuffer *buffer = gstate->source_fill.texture.buffer;
switch (buffer->format->bpp)
{
case 1: ctx_fragment_image_gray1_RGBA8 (rasterizer, x, y, rgba); break;
@@ -26967,9 +30600,9 @@ static void ctx_fragment_image_GRAYAF (CtxRasterizer *rasterizer, float x, float
static CtxFragment ctx_rasterizer_get_fragment_GRAYAF (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
- case CTX_SOURCE_IMAGE: return ctx_fragment_image_GRAYAF;
+ case CTX_SOURCE_TEXTURE: return ctx_fragment_image_GRAYAF;
case CTX_SOURCE_COLOR: return ctx_fragment_color_GRAYAF;
#if CTX_GRADIENTS
case CTX_SOURCE_LINEAR_GRADIENT: return ctx_fragment_linear_gradient_GRAYAF;
@@ -27011,11 +30644,11 @@ ctx_setup_GRAYAF (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
int components = 2;
- if (gstate->source.type == CTX_SOURCE_COLOR)
+ if (gstate->source_fill.type == CTX_SOURCE_COLOR)
{
rasterizer->comp_op = ctx_GRAYAF_porter_duff_color;
rasterizer->fragment = NULL;
- ctx_color_get_rgba (rasterizer->state, &gstate->source.color, (float*)rasterizer->color);
+ ctx_color_get_rgba (rasterizer->state, &gstate->source_fill.color, (float*)rasterizer->color);
if (gstate->global_alpha_u8 != 255)
for (int c = 0; c < components; c ++)
((float*)rasterizer->color)[c] *= gstate->global_alpha_f;
@@ -27040,7 +30673,7 @@ ctx_setup_GRAYAF (CtxRasterizer *rasterizer)
else if (gstate->global_alpha_u8 == 0)
rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_RGBA8_nop);
else
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
if (gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
@@ -27065,7 +30698,7 @@ ctx_setup_GRAYAF (CtxRasterizer *rasterizer)
}
break;
default:
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
rasterizer->comp_op = ctx_GRAYAF_porter_duff_color;
@@ -27158,9 +30791,9 @@ ctx_fragment_other_CMYKAF (CtxRasterizer *rasterizer, float x, float y, void *ou
float *cmyka = (float*)out;
float rgba[4];
CtxGState *gstate = &rasterizer->state->gstate;
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
- case CTX_SOURCE_IMAGE:
+ case CTX_SOURCE_TEXTURE:
ctx_fragment_image_RGBAF (rasterizer, x, y, rgba);
break;
case CTX_SOURCE_COLOR:
@@ -27187,7 +30820,7 @@ ctx_fragment_color_CMYKAF (CtxRasterizer *rasterizer, float x, float y, void *ou
{
CtxGState *gstate = &rasterizer->state->gstate;
float *cmyka = (float*)out;
- ctx_color_get_cmyka (rasterizer->state, &gstate->source.color, cmyka);
+ ctx_color_get_cmyka (rasterizer->state, &gstate->source_fill.color, cmyka);
// RGBW instead of CMYK
for (int i = 0; i < 4; i ++)
{
@@ -27198,7 +30831,7 @@ ctx_fragment_color_CMYKAF (CtxRasterizer *rasterizer, float x, float y, void *ou
static CtxFragment ctx_rasterizer_get_fragment_CMYKAF (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
return ctx_fragment_color_CMYKAF;
@@ -27238,11 +30871,11 @@ ctx_setup_CMYKAF (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
int components = 5;
- if (gstate->source.type == CTX_SOURCE_COLOR)
+ if (gstate->source_fill.type == CTX_SOURCE_COLOR)
{
rasterizer->comp_op = ctx_CMYKAF_porter_duff_color;
rasterizer->fragment = NULL;
- ctx_color_get_cmyka (rasterizer->state, &gstate->source.color, (float*)rasterizer->color);
+ ctx_color_get_cmyka (rasterizer->state, &gstate->source_fill.color, (float*)rasterizer->color);
if (gstate->global_alpha_u8 != 255)
((float*)rasterizer->color)[components-1] *= gstate->global_alpha_f;
}
@@ -27267,7 +30900,7 @@ ctx_setup_CMYKAF (CtxRasterizer *rasterizer)
else if (gstate->global_alpha_u8 == 0)
rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_RGBA8_nop);
else
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
if (gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
@@ -27292,7 +30925,7 @@ ctx_setup_CMYKAF (CtxRasterizer *rasterizer)
}
break;
default:
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
rasterizer->comp_op = ctx_CMYKAF_porter_duff_color;
@@ -27750,12 +31383,9 @@ inline static void
ctx_RGBA8_to_GRAY8 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
{
uint8_t *pixel = (uint8_t *) buf;
- while (count--)
+ for (int i = 0; i < count; i ++)
{
- pixel[0] = ctx_u8_color_rgb_to_gray (rasterizer->state, rgba);
- // for internal uses... using only green would work
- pixel+=1;
- rgba +=4;
+ pixel[i] = ctx_u8_color_rgb_to_gray (rasterizer->state, rgba + i * 4);
}
}
#endif
@@ -27802,7 +31432,7 @@ CTX_INLINE static void ctx_rgba_to_graya_u8 (CtxState *state, uint8_t *in, uint8
static void
ctx_fragment_linear_gradient_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
g->linear_gradient.length) -
g->linear_gradient.start) * (g->linear_gradient.rdelta);
@@ -27818,7 +31448,7 @@ static void
ctx_fragment_radial_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
uint8_t *rgba = (uint8_t *) out;
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = (ctx_hypotf (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y) -
g->radial_gradient.r0) * (g->radial_gradient.rdelta);
ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 0.0, rgba);
@@ -27833,7 +31463,7 @@ ctx_fragment_radial_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y,
static void
ctx_fragment_radial_gradient_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
float v = (ctx_hypotf (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y) -
g->radial_gradient.r0) * (g->radial_gradient.rdelta);
ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 0.0, (uint8_t*)out);
@@ -27847,7 +31477,7 @@ ctx_fragment_radial_gradient_GRAYA8 (CtxRasterizer *rasterizer, float x, float y
static void
ctx_fragment_color_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
{
- CtxSource *g = &rasterizer->state->gstate.source;
+ CtxSource *g = &rasterizer->state->gstate.source_fill;
ctx_color_get_graya_u8 (rasterizer->state, &g->color, out);
}
@@ -27855,7 +31485,7 @@ static void ctx_fragment_image_GRAYA8 (CtxRasterizer *rasterizer, float x, float
{
uint8_t rgba[4];
CtxGState *gstate = &rasterizer->state->gstate;
- CtxBuffer *buffer = gstate->source.image.buffer;
+ CtxBuffer *buffer = gstate->source_fill.texture.buffer;
switch (buffer->format->bpp)
{
case 1: ctx_fragment_image_gray1_RGBA8 (rasterizer, x, y, rgba); break;
@@ -27869,9 +31499,9 @@ static void ctx_fragment_image_GRAYA8 (CtxRasterizer *rasterizer, float x, float
static CtxFragment ctx_rasterizer_get_fragment_GRAYA8 (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
- case CTX_SOURCE_IMAGE: return ctx_fragment_image_GRAYA8;
+ case CTX_SOURCE_TEXTURE: return ctx_fragment_image_GRAYA8;
#if CTX_GRADIENTS
case CTX_SOURCE_COLOR: return ctx_fragment_color_GRAYA8;
case CTX_SOURCE_LINEAR_GRADIENT: return ctx_fragment_linear_gradient_GRAYA8;
@@ -27902,13 +31532,13 @@ ctx_GRAYA8_clear_normal (CTX_COMPOSITE_ARGUMENTS)
}
static void
-ctx_GRAYA8_source_over_normal_color (CTX_COMPOSITE_ARGUMENTS)
+CTX_COMPOSITE_SUFFIX (ctx_GRAYA8_source_over_normal_color) (CTX_COMPOSITE_ARGUMENTS)
{
ctx_u8_source_over_normal_color (2, rasterizer, dst, rasterizer->color, x0, coverage, count);
}
static void
-ctx_GRAYA8_source_over_normal_opaque_color (CTX_COMPOSITE_ARGUMENTS)
+CTX_COMPOSITE_SUFFIX (ctx_GRAYA8_source_over_normal_opaque_color) (CTX_COMPOSITE_ARGUMENTS)
{
ctx_u8_source_over_normal_opaque_color (2, rasterizer, dst, rasterizer->color, x0, coverage, count);
}
@@ -27920,10 +31550,10 @@ ctx_is_opaque_color (CtxRasterizer *rasterizer)
CtxGState *gstate = &rasterizer->state->gstate;
if (gstate->global_alpha_u8 != 255)
return 0;
- if (gstate->source.type == CTX_SOURCE_COLOR)
+ if (gstate->source_fill.type == CTX_SOURCE_COLOR)
{
uint8_t ga[2];
- ctx_color_get_graya_u8 (rasterizer->state, &gstate->source.color, ga);
+ ctx_color_get_graya_u8 (rasterizer->state, &gstate->source_fill.color, ga);
return ga[1] == 255;
}
return 0;
@@ -27934,11 +31564,11 @@ ctx_setup_GRAYA8 (CtxRasterizer *rasterizer)
{
CtxGState *gstate = &rasterizer->state->gstate;
int components = 2;
- if (gstate->source.type == CTX_SOURCE_COLOR)
+ if (gstate->source_fill.type == CTX_SOURCE_COLOR)
{
- rasterizer->comp_op = ctx_GRAYA8_porter_duff_color;
+ rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_GRAYA8_porter_duff_color);
rasterizer->fragment = NULL;
- ctx_color_get_rgba8 (rasterizer->state, &gstate->source.color, rasterizer->color);
+ ctx_color_get_rgba8 (rasterizer->state, &gstate->source_fill.color, rasterizer->color);
if (gstate->global_alpha_u8 != 255)
for (int c = 0; c < components; c ++)
rasterizer->color[c] = (rasterizer->color[c] * gstate->global_alpha_u8)/255;
@@ -27948,7 +31578,7 @@ ctx_setup_GRAYA8 (CtxRasterizer *rasterizer)
else
{
rasterizer->fragment = ctx_rasterizer_get_fragment_GRAYA8 (rasterizer);
- rasterizer->comp_op = ctx_GRAYA8_porter_duff_generic;
+ rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_GRAYA8_porter_duff_generic);
}
#if CTX_INLINED_NORMAL
@@ -27965,7 +31595,7 @@ ctx_setup_GRAYA8 (CtxRasterizer *rasterizer)
else if (gstate->global_alpha_u8 == 0)
rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_RGBA8_nop);
else
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
if (gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
@@ -27973,31 +31603,31 @@ ctx_setup_GRAYA8 (CtxRasterizer *rasterizer)
if (rasterizer->color[components-1] == 0)
rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_RGBA8_nop);
else if (rasterizer->color[components-1] == 255)
- rasterizer->comp_op = ctx_GRAYA8_source_over_normal_opaque_color;
+ rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_GRAYA8_source_over_normal_opaque_color);
else
- rasterizer->comp_op = ctx_GRAYA8_source_over_normal_color;
+ rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_GRAYA8_source_over_normal_color);
rasterizer->fragment = NULL;
}
else
{
- rasterizer->comp_op = ctx_GRAYA8_porter_duff_color_normal;
+ rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_GRAYA8_porter_duff_color_normal);
rasterizer->fragment = NULL;
}
break;
default:
- rasterizer->comp_op = ctx_GRAYA8_porter_duff_generic_normal;
+ rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_GRAYA8_porter_duff_generic_normal);
break;
}
break;
default:
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_COLOR:
- rasterizer->comp_op = ctx_GRAYA8_porter_duff_color;
+ rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_GRAYA8_porter_duff_color);
rasterizer->fragment = NULL;
break;
default:
- rasterizer->comp_op = ctx_GRAYA8_porter_duff_generic;
+ rasterizer->comp_op = CTX_COMPOSITE_SUFFIX(ctx_GRAYA8_porter_duff_generic);
break;
}
break;
@@ -28314,6 +31944,13 @@ CtxPixelFormatInfo CTX_COMPOSITE_SUFFIX(ctx_pixel_formats)[]=
void
CTX_COMPOSITE_SUFFIX(ctx_compositor_setup) (CtxRasterizer *rasterizer)
{
+ if (rasterizer->state->gstate.source_fill.type == CTX_SOURCE_TEXTURE)
+ {
+ if (!rasterizer->state->gstate.source_fill.texture.buffer->color_managed)
+ _ctx_texture_prepare_color_management (rasterizer,
+ rasterizer->state->gstate.source_fill.texture.buffer);
+ }
+
if (rasterizer->format->setup)
{
// event if _default is used we get to work
@@ -28322,7 +31959,7 @@ CTX_COMPOSITE_SUFFIX(ctx_compositor_setup) (CtxRasterizer *rasterizer)
#if CTX_GRADIENTS
#if CTX_GRADIENT_CACHE
CtxGState *gstate = &rasterizer->state->gstate;
- switch (gstate->source.type)
+ switch (gstate->source_fill.type)
{
case CTX_SOURCE_LINEAR_GRADIENT:
case CTX_SOURCE_RADIAL_GRADIENT:
diff --git a/gegl/ctx/meson.build b/gegl/ctx/meson.build
index f2e9a6d86..bd9175039 100644
--- a/gegl/ctx/meson.build
+++ b/gegl/ctx/meson.build
@@ -3,3 +3,6 @@ gegl_sources += files(
)
gegl_headers += files('ctx.h')
+
+gegl_cflags += '-DNO_LIBCURL'
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]