1 /* ctx git commit: 6bfbdd4 */
2 /*
3  * ctx.h is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 3 of the License, or (at your option) any later version.
7  *
8  * ctx.h is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with ctx; if not, see <https://www.gnu.org/licenses/>.
15  *
16  * 2012, 2015, 2019, 2020 Øyvind Kolås <pippin@gimp.org>
17  *
18  * ctx is a single header 2d vector graphics processing framework.
19  *
20  * To use ctx in a project, do the following:
21  *
22  * #define CTX_IMPLEMENTATION
23  * #include "ctx.h"
24  *
25  * Ctx contains a minimal default fallback font with only ascii, so
26  * you probably want to also include a font, and perhaps enable
27  * the cairo or SDL2 optional renderers, a more complete example
28  * could be:
29  *
30  * #include <cairo.h>
31  * #include <SDL.h>
32  * #include "ctx-font-regular.h"
33  * #define CTX_IMPLEMENTATION
34  * #include "ctx.h"
35  *
36  * The behavior of ctx can be tweaked, and features can be configured, enabled
37  * or disabled with other #defines, see further down in the start of this file
38  * for details.
39  */
40 
41 #ifndef CTX_H
42 #define CTX_H
43 
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47 
48 #if !__COSMOPOLITAN__
49 #include <stdint.h>
50 #include <string.h>
51 #include <stdio.h>
52 #if CTX_EVENTS
53 #include <sys/select.h> // XXX if events?
54 #endif
55 #endif
56 
57 typedef struct _Ctx            Ctx;
58 
59 /* The pixel formats supported as render targets
60  */
61 enum _CtxPixelFormat
62 {
63   CTX_FORMAT_NONE=0,
64   CTX_FORMAT_GRAY8,  // 1  - these enum values are not coincidence
65   CTX_FORMAT_GRAYA8, // 2  -
66   CTX_FORMAT_RGB8,   // 3  -
67   CTX_FORMAT_RGBA8,  // 4  -
68   CTX_FORMAT_BGRA8,  // 5
69   CTX_FORMAT_RGB565, // 6
70   CTX_FORMAT_RGB565_BYTESWAPPED, // 7
71   CTX_FORMAT_RGB332, // 8
72   CTX_FORMAT_RGBAF,  // 9
73   CTX_FORMAT_GRAYF,  // 10
74   CTX_FORMAT_GRAYAF, // 11
75   CTX_FORMAT_GRAY1,  //12 MONO
76   CTX_FORMAT_GRAY2,  //13 DUO
77   CTX_FORMAT_GRAY4,  //14
78   CTX_FORMAT_CMYK8,  //15
79   CTX_FORMAT_CMYKA8, //16
80   CTX_FORMAT_CMYKAF, //17
81   CTX_FORMAT_YUV420, //18
82   CTX_FORMAT_RGBA8_SEPARATE_ALPHA, // 19
83 };
84 typedef enum   _CtxPixelFormat CtxPixelFormat;
85 
86 typedef struct _CtxGlyph       CtxGlyph;
87 
88 /**
89  * ctx_new:
90  *
91  * Create a new drawing context, this context has no pixels but
92  * accumulates commands and can be played back on other ctx
93  * render contexts.
94  */
95 Ctx *ctx_new (void);
96 
97 /**
98  * ctx_new_for_framebuffer:
99  *
100  * Create a new drawing context for a framebuffer, rendering happens
101  * immediately.
102  */
103 Ctx *ctx_new_for_framebuffer (void *data,
104                               int   width,
105                               int   height,
106                               int   stride,
107                               CtxPixelFormat pixel_format);
108 /**
109  * ctx_new_ui:
110  *
111  * Create a new interactive ctx context, might depend on additional
112  * integration.
113  */
114 Ctx *ctx_new_ui (int width, int height);
115 
116 /**
117  * ctx_new_for_drawlist:
118  *
119  * Create a new drawing context for a pre-existing drawlist.
120  */
121 Ctx *ctx_new_for_drawlist (void *data, size_t length);
122 
123 
124 /**
125  * ctx_dirty_rect:
126  *
127  * Query the dirtied bounding box of drawing commands thus far.
128  */
129 void  ctx_dirty_rect      (Ctx *ctx, int *x, int *y, int *width, int *height);
130 
131 /**
132  * ctx_free:
133  * @ctx: a ctx context
134  */
135 void ctx_free (Ctx *ctx);
136 
137 /* clears and resets a context */
138 void ctx_reset          (Ctx *ctx);
139 void ctx_begin_path     (Ctx *ctx);
140 void ctx_save           (Ctx *ctx);
141 void ctx_restore        (Ctx *ctx);
142 void ctx_start_group    (Ctx *ctx);
143 void ctx_end_group      (Ctx *ctx);
144 void ctx_clip           (Ctx *ctx);
145 void ctx_identity       (Ctx *ctx);
146 void ctx_rotate         (Ctx *ctx, float x);
147 
148 void ctx_image_smoothing     (Ctx *ctx, int enabled);
149 int  ctx_get_image_smoothing (Ctx *ctx);
150 
151 #define CTX_LINE_WIDTH_HAIRLINE -1000.0
152 #define CTX_LINE_WIDTH_ALIASED  -1.0
153 #define CTX_LINE_WIDTH_FAST     -1.0  /* aliased 1px wide line */
154 void ctx_miter_limit (Ctx *ctx, float limit);
155 float ctx_get_miter_limit (Ctx *ctx);
156 void ctx_line_width       (Ctx *ctx, float x);
157 void ctx_line_dash_offset (Ctx *ctx, float line_dash);
158 float ctx_get_line_dash_offset (Ctx *ctx);
159 void ctx_apply_transform  (Ctx *ctx, float a,  float b,  // hscale, hskew
160                                      float c,  float d,  // vskew,  vscale
161                                      float e,  float f); // htran,  vtran
162 void ctx_set_transform    (Ctx *ctx, float a, float b, float c, float d, float e, float f);
163 void  ctx_line_dash       (Ctx *ctx, float *dashes, int count);
164 void  ctx_font_size       (Ctx *ctx, float x);
165 void  ctx_font            (Ctx *ctx, const char *font);
166 void  ctx_font_family     (Ctx *ctx, const char *font_family);
167 void  ctx_scale           (Ctx *ctx, float x, float y);
168 void  ctx_translate       (Ctx *ctx, float x, float y);
169 void  ctx_line_to         (Ctx *ctx, float x, float y);
170 void  ctx_move_to         (Ctx *ctx, float x, float y);
171 void  ctx_curve_to        (Ctx *ctx, float cx0, float cy0,
172                            float cx1, float cy1,
173                            float x, float y);
174 void  ctx_quad_to         (Ctx *ctx, float cx, float cy,
175                            float x, float y);
176 void  ctx_arc             (Ctx  *ctx,
177                            float x, float y,
178                            float radius,
179                            float angle1, float angle2,
180                            int   direction);
181 void  ctx_arc_to          (Ctx *ctx, float x1, float y1,
182                            float x2, float y2, float radius);
183 void  ctx_rel_arc_to      (Ctx *ctx, float x1, float y1,
184                            float x2, float y2, float radius);
185 void  ctx_rectangle       (Ctx *ctx,
186                            float x0, float y0,
187                            float w, float h);
188 void  ctx_round_rectangle (Ctx *ctx,
189                            float x0, float y0,
190                            float w, float h,
191                            float radius);
192 void  ctx_rel_line_to     (Ctx *ctx,
193                            float x, float y);
194 void  ctx_rel_move_to     (Ctx *ctx,
195                            float x, float y);
196 void  ctx_rel_curve_to    (Ctx *ctx,
197                            float x0, float y0,
198                            float x1, float y1,
199                            float x2, float y2);
200 void  ctx_rel_quad_to     (Ctx *ctx,
201                            float cx, float cy,
202                            float x, float y);
203 void  ctx_close_path      (Ctx *ctx);
204 float ctx_get_font_size   (Ctx *ctx);
205 const char *ctx_get_font  (Ctx *ctx);
206 float ctx_get_line_width  (Ctx *ctx);
207 int   ctx_width           (Ctx *ctx);
208 int   ctx_height          (Ctx *ctx);
209 int   ctx_rev             (Ctx *ctx);
210 float ctx_x               (Ctx *ctx);
211 float ctx_y               (Ctx *ctx);
212 void  ctx_current_point   (Ctx *ctx, float *x, float *y);
213 void  ctx_get_transform   (Ctx *ctx, float *a, float *b,
214                            float *c, float *d,
215                            float *e, float *f);
216 
217 CtxGlyph *ctx_glyph_allocate (int n_glyphs);
218 
219 void gtx_glyph_free       (CtxGlyph *glyphs);
220 
221 int  ctx_glyph            (Ctx *ctx, uint32_t unichar, int stroke);
222 
223 void ctx_preserve         (Ctx *ctx);
224 void ctx_fill             (Ctx *ctx);
225 void ctx_stroke           (Ctx *ctx);
226 
227 void ctx_parse            (Ctx *ctx, const char *string);
228 
229 void ctx_shadow_rgba      (Ctx *ctx, float r, float g, float b, float a);
230 void ctx_shadow_blur      (Ctx *ctx, float x);
231 void ctx_shadow_offset_x  (Ctx *ctx, float x);
232 void ctx_shadow_offset_y  (Ctx *ctx, float y);
233 void ctx_view_box         (Ctx *ctx,
234                            float x0, float y0,
235                            float w, float h);
236 void
237 ctx_set_pixel_u8          (Ctx *ctx, uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
238 
239 void  ctx_global_alpha     (Ctx *ctx, float global_alpha);
240 float ctx_get_global_alpha (Ctx *ctx);
241 
242 void ctx_named_source (Ctx *ctx, const char *name);
243 // followed by a color, gradient or pattern definition
244 
245 void ctx_stroke_source  (Ctx *ctx); // next source definition is for stroking
246 
247 void ctx_rgba_stroke   (Ctx *ctx, float r, float g, float b, float a);
248 void ctx_rgb_stroke    (Ctx *ctx, float r, float g, float b);
249 void ctx_rgba8_stroke  (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
250 
251 void ctx_gray_stroke   (Ctx *ctx, float gray);
252 void ctx_drgba_stroke  (Ctx *ctx, float r, float g, float b, float a);
253 void ctx_cmyka_stroke  (Ctx *ctx, float c, float m, float y, float k, float a);
254 void ctx_cmyk_stroke   (Ctx *ctx, float c, float m, float y, float k);
255 void ctx_dcmyka_stroke (Ctx *ctx, float c, float m, float y, float k, float a);
256 void ctx_dcmyk_stroke  (Ctx *ctx, float c, float m, float y, float k);
257 
258 
259 
260 void ctx_rgba   (Ctx *ctx, float r, float g, float b, float a);
261 void ctx_rgb    (Ctx *ctx, float r, float g, float b);
262 void ctx_rgba8  (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
263 
264 void ctx_gray   (Ctx *ctx, float gray);
265 void ctx_drgba  (Ctx *ctx, float r, float g, float b, float a);
266 void ctx_cmyka  (Ctx *ctx, float c, float m, float y, float k, float a);
267 void ctx_cmyk   (Ctx *ctx, float c, float m, float y, float k);
268 void ctx_dcmyka (Ctx *ctx, float c, float m, float y, float k, float a);
269 void ctx_dcmyk  (Ctx *ctx, float c, float m, float y, float k);
270 
271 /* there is also getters for colors, by first setting a color in one format and getting
272  * it with another color conversions can be done
273  */
274 
275 void ctx_get_rgba   (Ctx *ctx, float *rgba);
276 void ctx_get_graya  (Ctx *ctx, float *ya);
277 void ctx_get_drgba  (Ctx *ctx, float *drgba);
278 void ctx_get_cmyka  (Ctx *ctx, float *cmyka);
279 void ctx_get_dcmyka (Ctx *ctx, float *dcmyka);
280 int  ctx_in_fill    (Ctx *ctx, float x, float y);
281 int  ctx_in_stroke  (Ctx *ctx, float x, float y);
282 
283 void ctx_linear_gradient (Ctx *ctx, float x0, float y0, float x1, float y1);
284 void ctx_radial_gradient (Ctx *ctx, float x0, float y0, float r0,
285                           float x1, float y1, float r1);
286 /* XXX should be ctx_gradient_add_stop_rgba */
287 void ctx_gradient_add_stop (Ctx *ctx, float pos, float r, float g, float b, float a);
288 
289 void ctx_gradient_add_stop_u8 (Ctx *ctx, float pos, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
290 
291 
292 /*
293  *
294  */
295 void ctx_define_texture (Ctx *ctx,
296                          const char *eid,
297                          int         width,
298                          int         height,
299                          int         stride,
300                          int         format,
301                          void       *data,
302                          char       *ret_eid);
303 
304 void
305 ctx_source_transform (Ctx *ctx, float a, float b,  // hscale, hskew
306                       float c, float d,  // vskew,  vscale
307                       float e, float f);  // htran,  vtran
308 typedef struct _CtxMatrix     CtxMatrix;
309 void
310 ctx_source_transform_matrix (Ctx *ctx, CtxMatrix *matrix);
311 
312 void
313 ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh,
314                     CtxPixelFormat format, int dst_stride,
315                     uint8_t *dst_data);
316 
317 void
318 ctx_put_image_data (Ctx *ctx, int w, int h, int stride, int format,
319                     uint8_t *data,
320                     int ox, int oy,
321                     int dirtyX, int dirtyY,
322                     int dirtyWidth, int dirtyHeight);
323 
324 
325 /* loads an image file from disk into texture, returning pixel width, height
326  * and eid, the eid is based on the path; not the contents - avoiding doing
327  * sha1 checksum of contents. The width and height of the image is returned
328  * along with the used eid, width height or eid can be NULL if we
329  * do not care about their values.
330  */
331 void ctx_texture_load (Ctx        *ctx,
332                        const char *path,
333                        int        *width,
334                        int        *height,
335                        char       *eid);
336 
337 /* sets the paint source to be a texture by eid
338  */
339 void ctx_texture              (Ctx *ctx, const char *eid, float x, float y);
340 
341 void ctx_draw_texture         (Ctx *ctx, const char *eid, float x, float y, float w, float h);
342 
343 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);
344 
345 void ctx_draw_image           (Ctx *ctx, const char *path, float x, float y, float w, float h);
346 
347 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);
348 
349 /* used by the render threads of fb and sdl backends.
350  */
351 void ctx_set_texture_source (Ctx *ctx, Ctx *texture_source);
352 /* used when sharing cache state of eids between clients
353  */
354 void ctx_set_texture_cache (Ctx *ctx, Ctx *texture_cache);
355 
356 typedef struct _CtxDrawlist CtxDrawlist;
357 typedef void (*CtxFullCb) (CtxDrawlist *drawlist, void *data);
358 
359 int ctx_pixel_format_bits_per_pixel (CtxPixelFormat format); // bits per pixel
360 int ctx_pixel_format_get_stride (CtxPixelFormat format, int width);
361 int ctx_pixel_format_components (CtxPixelFormat format);
362 
363 void _ctx_set_store_clear (Ctx *ctx);
364 void _ctx_set_transformation (Ctx *ctx, int transformation);
365 
366 Ctx *ctx_hasher_new (int width, int height, int cols, int rows);
367 uint8_t *ctx_hasher_get_hash (Ctx *ctx, int col, int row);
368 
369 int ctx_utf8_strlen (const char *s);
370 
371 #ifdef _BABL_H
372 #define CTX_BABL 1
373 #else
374 #define CTX_BABL 0
375 #endif
376 
377 /* If cairo.h is included before ctx.h add cairo integration code
378  */
379 #ifdef CAIRO_H
380 #ifndef CTX_CAIRO
381 #define CTX_CAIRO 1
382 #endif
383 #endif
384 
385 #ifndef CTX_SDL
386 #ifdef SDL_h_
387 #define CTX_SDL 1
388 #else
389 #define CTX_SDL 0
390 #endif
391 #endif
392 
393 #ifndef CTX_FB
394 #define CTX_FB 0
395 #endif
396 
397 #ifndef CTX_KMS
398 #define CTX_KMS 0
399 #endif
400 
401 #if CTX_SDL
402 #define ctx_mutex_t            SDL_mutex
403 #define ctx_create_mutex()     SDL_CreateMutex()
404 #define ctx_lock_mutex(a)      SDL_LockMutex(a)
405 #define ctx_unlock_mutex(a)    SDL_UnlockMutex(a)
406 #else
407 #define ctx_mutex_t           int
408 #define ctx_create_mutex()    NULL
409 #define ctx_lock_mutex(a)
410 #define ctx_unlock_mutex(a)
411 #endif
412 
413 #if CTX_CAIRO
414 #ifndef CAIRO_H
415 typedef struct _cairo_t cairo_t;
416 #endif
417 
418 /* render the deferred commands of a ctx context to a cairo
419  * context
420  */
421 void  ctx_render_cairo  (Ctx *ctx, cairo_t *cr);
422 
423 /* create a ctx context that directly renders to the specified
424  * cairo context
425  */
426 Ctx * ctx_new_for_cairo (cairo_t *cr);
427 #endif
428 
429 /* free with free() */
430 char *ctx_render_string (Ctx *ctx, int longform, int *retlen);
431 
432 void ctx_render_stream  (Ctx *ctx, FILE *stream, int formatter);
433 
434 void ctx_render_ctx     (Ctx *ctx, Ctx *d_ctx);
435 void ctx_render_ctx_textures (Ctx *ctx, Ctx *d_ctx); /* cycles through all
436                                                         used texture eids
437                                                       */
438 
439 void ctx_start_move     (Ctx *ctx);
440 
441 
442 int ctx_add_single      (Ctx *ctx, void *entry);
443 
444 uint32_t ctx_utf8_to_unichar (const char *input);
445 int      ctx_unichar_to_utf8 (uint32_t  ch, uint8_t  *dest);
446 
447 
448 typedef enum
449 {
450   CTX_FILL_RULE_WINDING = 0,
451   CTX_FILL_RULE_EVEN_ODD
452 } CtxFillRule;
453 
454 typedef enum
455 {
456 #if 0
457   CTX_COMPOSITE_SOURCE_OVER      = 0,
458   CTX_COMPOSITE_COPY             = 32,
459   CTX_COMPOSITE_SOURCE_IN        = 64,
460   CTX_COMPOSITE_SOURCE_OUT       = 96,
461   CTX_COMPOSITE_SOURCE_ATOP      = 128,
462   CTX_COMPOSITE_CLEAR            = 160,
463 
464   CTX_COMPOSITE_DESTINATION_OVER = 192,
465   CTX_COMPOSITE_DESTINATION      = 224,
466   CTX_COMPOSITE_DESTINATION_IN   = 256,
467   CTX_COMPOSITE_DESTINATION_OUT  = 288,
468   CTX_COMPOSITE_DESTINATION_ATOP = 320,
469   CTX_COMPOSITE_XOR              = 352,
470 
471   CTX_COMPOSITE_ALL              = (32+64+128+256)
472 #else
473   CTX_COMPOSITE_SOURCE_OVER      =0,
474   CTX_COMPOSITE_COPY             ,
475   CTX_COMPOSITE_SOURCE_IN        ,
476   CTX_COMPOSITE_SOURCE_OUT       ,
477   CTX_COMPOSITE_SOURCE_ATOP      ,
478   CTX_COMPOSITE_CLEAR            ,
479 
480   CTX_COMPOSITE_DESTINATION_OVER ,
481   CTX_COMPOSITE_DESTINATION      ,
482   CTX_COMPOSITE_DESTINATION_IN   ,
483   CTX_COMPOSITE_DESTINATION_OUT  ,
484   CTX_COMPOSITE_DESTINATION_ATOP ,
485   CTX_COMPOSITE_XOR              ,
486 #endif
487 } CtxCompositingMode;
488 
489 typedef enum
490 {
491   CTX_BLEND_NORMAL,
492   CTX_BLEND_MULTIPLY,
493   CTX_BLEND_SCREEN,
494   CTX_BLEND_OVERLAY,
495   CTX_BLEND_DARKEN,
496   CTX_BLEND_LIGHTEN,
497   CTX_BLEND_COLOR_DODGE,
498   CTX_BLEND_COLOR_BURN,
499   CTX_BLEND_HARD_LIGHT,
500   CTX_BLEND_SOFT_LIGHT,
501   CTX_BLEND_DIFFERENCE,
502   CTX_BLEND_EXCLUSION,
503   CTX_BLEND_HUE,
504   CTX_BLEND_SATURATION,
505   CTX_BLEND_COLOR,
506   CTX_BLEND_LUMINOSITY,  // 15
507   CTX_BLEND_DIVIDE,
508   CTX_BLEND_ADDITION,
509   CTX_BLEND_SUBTRACT,    // 18
510 } CtxBlend;
511 
512 void ctx_blend_mode (Ctx *ctx, CtxBlend mode);
513 
514 typedef enum
515 {
516   CTX_JOIN_BEVEL = 0,
517   CTX_JOIN_ROUND = 1,
518   CTX_JOIN_MITER = 2
519 } CtxLineJoin;
520 
521 typedef enum
522 {
523   CTX_CAP_NONE   = 0,
524   CTX_CAP_ROUND  = 1,
525   CTX_CAP_SQUARE = 2
526 } CtxLineCap;
527 
528 typedef enum
529 {
530   CTX_TEXT_BASELINE_ALPHABETIC = 0,
531   CTX_TEXT_BASELINE_TOP,
532   CTX_TEXT_BASELINE_HANGING,
533   CTX_TEXT_BASELINE_MIDDLE,
534   CTX_TEXT_BASELINE_IDEOGRAPHIC,
535   CTX_TEXT_BASELINE_BOTTOM
536 } CtxTextBaseline;
537 
538 typedef enum
539 {
540   CTX_TEXT_ALIGN_START = 0,  // in mrg these didnt exist
541   CTX_TEXT_ALIGN_END,        // but left/right did
542   CTX_TEXT_ALIGN_JUSTIFY, // not handled in ctx
543   CTX_TEXT_ALIGN_CENTER,
544   CTX_TEXT_ALIGN_LEFT,
545   CTX_TEXT_ALIGN_RIGHT
546 } CtxTextAlign;
547 
548 typedef enum
549 {
550   CTX_TEXT_DIRECTION_INHERIT = 0,
551   CTX_TEXT_DIRECTION_LTR,
552   CTX_TEXT_DIRECTION_RTL
553 } CtxTextDirection;
554 
555 struct
556 _CtxGlyph
557 {
558   uint32_t index;
559   float    x;
560   float    y;
561 };
562 
563 CtxTextAlign       ctx_get_text_align (Ctx *ctx);
564 CtxTextBaseline    ctx_get_text_baseline (Ctx *ctx);
565 CtxTextDirection   ctx_get_text_direction (Ctx *ctx);
566 CtxFillRule        ctx_get_fill_rule (Ctx *ctx);
567 CtxLineCap         ctx_get_line_cap (Ctx *ctx);
568 CtxLineJoin        ctx_get_line_join (Ctx *ctx);
569 CtxCompositingMode ctx_get_compositing_mode (Ctx *ctx);
570 CtxBlend           ctx_get_blend_mode (Ctx *ctx);
571 
572 void ctx_gradient_add_stop_string (Ctx *ctx, float pos, const char *color);
573 
574 void ctx_text_align           (Ctx *ctx, CtxTextAlign      align);
575 void ctx_text_baseline        (Ctx *ctx, CtxTextBaseline   baseline);
576 void ctx_text_direction       (Ctx *ctx, CtxTextDirection  direction);
577 void ctx_fill_rule            (Ctx *ctx, CtxFillRule       fill_rule);
578 void ctx_line_cap             (Ctx *ctx, CtxLineCap        cap);
579 void ctx_line_join            (Ctx *ctx, CtxLineJoin       join);
580 void ctx_compositing_mode     (Ctx *ctx, CtxCompositingMode mode);
581 int  ctx_set_drawlist     (Ctx *ctx, void *data, int length);
582 typedef struct _CtxEntry CtxEntry;
583 /* we only care about the tight packing for this specific
584  * struct as we do indexing across members in arrays of it,
585  * to make sure its size becomes 9bytes -
586  * the pack pragma is also sufficient on recent gcc versions
587  */
588 #pragma pack(push,1)
589 struct
590   _CtxEntry
591 {
592   uint8_t code;
593   union
594   {
595     float    f[2];
596     uint8_t  u8[8];
597     int8_t   s8[8];
598     uint16_t u16[4];
599     int16_t  s16[4];
600     uint32_t u32[2];
601     int32_t  s32[2];
602     uint64_t u64[1]; // unused
603   } data; // 9bytes long, we're favoring compactness and correctness
604   // over performance. By sacrificing float precision, zeroing
605   // first 8bit of f[0] would permit 8bytes long and better
606   // aglinment and cacheline behavior.
607 };
608 #pragma pack(pop)
609 const CtxEntry *ctx_get_drawlist (Ctx *ctx);
610 int  ctx_append_drawlist  (Ctx *ctx, void *data, int length);
611 
612 /* these are only needed for clients rendering text, as all text gets
613  * converted to paths.
614  */
615 void  ctx_glyphs        (Ctx        *ctx,
616                          CtxGlyph   *glyphs,
617                          int         n_glyphs);
618 
619 void  ctx_glyphs_stroke (Ctx       *ctx,
620                          CtxGlyph   *glyphs,
621                          int         n_glyphs);
622 
623 void  ctx_text          (Ctx        *ctx,
624                          const char *string);
625 void  ctx_text_stroke   (Ctx        *ctx,
626                          const char *string);
627 
628 void  ctx_fill_text     (Ctx        *ctx,
629                          const char *string,
630                          float       x,
631                          float       y);
632 
633 void  ctx_stroke_text   (Ctx        *ctx,
634                          const char *string,
635                          float       x,
636                          float       y);
637 
638 /* returns the total horizontal advance if string had been rendered */
639 float ctx_text_width    (Ctx        *ctx,
640                          const char *string);
641 
642 float ctx_glyph_width   (Ctx *ctx, int unichar);
643 
644 int   ctx_load_font_ttf (const char *name, const void *ttf_contents, int length);
645 
646 
647 
648 enum _CtxModifierState
649 {
650   CTX_MODIFIER_STATE_SHIFT   = (1<<0),
651   CTX_MODIFIER_STATE_CONTROL = (1<<1),
652   CTX_MODIFIER_STATE_ALT     = (1<<2),
653   CTX_MODIFIER_STATE_BUTTON1 = (1<<3),
654   CTX_MODIFIER_STATE_BUTTON2 = (1<<4),
655   CTX_MODIFIER_STATE_BUTTON3 = (1<<5),
656   CTX_MODIFIER_STATE_DRAG    = (1<<6), // pointer button is down (0 or any)
657 };
658 typedef enum _CtxModifierState CtxModifierState;
659 
660 enum _CtxScrollDirection
661 {
662   CTX_SCROLL_DIRECTION_UP,
663   CTX_SCROLL_DIRECTION_DOWN,
664   CTX_SCROLL_DIRECTION_LEFT,
665   CTX_SCROLL_DIRECTION_RIGHT
666 };
667 typedef enum _CtxScrollDirection CtxScrollDirection;
668 
669 typedef struct _CtxEvent CtxEvent;
670 
671 void ctx_set_renderer (Ctx *ctx,
672                        void *renderer);
673 void *ctx_get_renderer (Ctx *ctx);
674 
675 int ctx_renderer_is_sdl (Ctx *ctx);
676 int ctx_renderer_is_fb (Ctx *ctx);
677 int ctx_renderer_is_kms (Ctx *ctx);
678 int ctx_renderer_is_tiled (Ctx *ctx);
679 int ctx_renderer_is_ctx (Ctx *ctx);
680 int ctx_renderer_is_term (Ctx *ctx);
681 
682 /* the following API is only available when CTX_EVENTS is defined to 1
683  *
684  * it provides the ability to register callbacks with the current path
685  * that get delivered with transformed coordinates.
686  */
687 int ctx_is_dirty (Ctx *ctx);
688 void ctx_set_dirty (Ctx *ctx, int dirty);
689 float ctx_get_float (Ctx *ctx, uint32_t hash);
690 void ctx_set_float (Ctx *ctx, uint32_t hash, float value);
691 
692 unsigned long ctx_ticks (void);
693 void ctx_flush (Ctx *ctx);
694 
695 void ctx_set_clipboard (Ctx *ctx, const char *text);
696 char *ctx_get_clipboard (Ctx *ctx);
697 
698 void _ctx_events_init     (Ctx *ctx);
699 typedef struct _CtxIntRectangle CtxIntRectangle;
700 struct _CtxIntRectangle {
701   int x;
702   int y;
703   int width;
704   int height;
705 };
706 
707 void ctx_quit (Ctx *ctx);
708 int  ctx_has_quit (Ctx *ctx);
709 
710 typedef void (*CtxCb) (CtxEvent *event,
711                        void     *data,
712                        void     *data2);
713 typedef void (*CtxDestroyNotify) (void *data);
714 
715 enum _CtxEventType {
716   CTX_PRESS        = 1 << 0,
717   CTX_MOTION       = 1 << 1,
718   CTX_RELEASE      = 1 << 2,
719   CTX_ENTER        = 1 << 3,
720   CTX_LEAVE        = 1 << 4,
721   CTX_TAP          = 1 << 5,
722   CTX_TAP_AND_HOLD = 1 << 6,
723 
724   /* NYI: SWIPE, ZOOM ROT_ZOOM, */
725 
726   CTX_DRAG_PRESS   = 1 << 7,
727   CTX_DRAG_MOTION  = 1 << 8,
728   CTX_DRAG_RELEASE = 1 << 9,
729   CTX_KEY_PRESS    = 1 << 10,
730   CTX_KEY_DOWN     = 1 << 11,
731   CTX_KEY_UP       = 1 << 12,
732   CTX_SCROLL       = 1 << 13,
733   CTX_MESSAGE      = 1 << 14,
734   CTX_DROP         = 1 << 15,
735 
736   CTX_SET_CURSOR   = 1 << 16, // used internally
737 
738   /* client should store state - preparing
739                                  * for restart
740                                  */
741   CTX_POINTER  = (CTX_PRESS | CTX_MOTION | CTX_RELEASE | CTX_DROP),
742   CTX_TAPS     = (CTX_TAP | CTX_TAP_AND_HOLD),
743   CTX_CROSSING = (CTX_ENTER | CTX_LEAVE),
744   CTX_DRAG     = (CTX_DRAG_PRESS | CTX_DRAG_MOTION | CTX_DRAG_RELEASE),
745   CTX_KEY      = (CTX_KEY_DOWN | CTX_KEY_UP | CTX_KEY_PRESS),
746   CTX_MISC     = (CTX_MESSAGE),
747   CTX_ANY      = (CTX_POINTER | CTX_DRAG | CTX_CROSSING | CTX_KEY | CTX_MISC | CTX_TAPS),
748 };
749 typedef enum _CtxEventType CtxEventType;
750 
751 #define CTX_CLICK   CTX_PRESS   // SHOULD HAVE MORE LOGIC
752 
753 struct _CtxEvent {
754   CtxEventType  type;
755   uint32_t time;
756   Ctx     *ctx;
757   int stop_propagate; /* when set - propagation is stopped */
758 
759   CtxModifierState state;
760 
761   int     device_no; /* 0 = left mouse button / virtual focus */
762                      /* 1 = middle mouse button */
763                      /* 2 = right mouse button */
764                      /* 3 = first multi-touch .. (NYI) */
765 
766   float   device_x; /* untransformed (device) coordinates  */
767   float   device_y;
768 
769   /* coordinates; and deltas for motion/drag events in user-coordinates: */
770   float   x;
771   float   y;
772   float   start_x; /* start-coordinates (press) event for drag, */
773   float   start_y; /*    untransformed coordinates */
774   float   prev_x;  /* previous events coordinates */
775   float   prev_y;
776   float   delta_x; /* x - prev_x, redundant - but often useful */
777   float   delta_y; /* y - prev_y, redundant - ..  */
778 
779 
780   unsigned int unicode; /* only valid for key-events, re-use as keycode? */
781   const char *string;   /* as key can be "up" "down" "space" "backspace" "a" "b" "ø" etc .. */
782                         /* this is also where the message is delivered for
783                          * MESSAGE events
784                          *
785                          * and the data for drop events are delivered
786                          */
787   CtxScrollDirection scroll_direction;
788 
789 
790   // would be nice to add the bounding box of the hit-area causing
791   // the event, making for instance scissored enter/leave repaint easier.
792 };
793 
794 // layer-event "layer"  motion x y device_no
795 
796 void ctx_add_key_binding_full (Ctx *ctx,
797                                const char *key,
798                                const char *action,
799                                const char *label,
800                                CtxCb       cb,
801                                void       *cb_data,
802                                CtxDestroyNotify destroy_notify,
803                                void       *destroy_data);
804 void ctx_add_key_binding (Ctx *ctx,
805                           const char *key,
806                           const char *action,
807                           const char *label,
808                           CtxCb cb,
809                           void  *cb_data);
810 typedef struct CtxBinding {
811   char *nick;
812   char *command;
813   char *label;
814   CtxCb cb;
815   void *cb_data;
816   CtxDestroyNotify destroy_notify;
817   void  *destroy_data;
818 } CtxBinding;
819 CtxBinding *ctx_get_bindings (Ctx *ctx);
820 void  ctx_clear_bindings     (Ctx *ctx);
821 void  ctx_remove_idle        (Ctx *ctx, int handle);
822 int   ctx_add_timeout_full   (Ctx *ctx, int ms, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data,
823                               void (*destroy_notify)(void *destroy_data), void *destroy_data);
824 int   ctx_add_timeout        (Ctx *ctx, int ms, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data);
825 int   ctx_add_idle_full      (Ctx *ctx, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data,
826                               void (*destroy_notify)(void *destroy_data), void *destroy_data);
827 int   ctx_add_idle           (Ctx *ctx, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data);
828 
829 
830 void ctx_add_hit_region (Ctx *ctx, const char *id);
831 
832 void ctx_set_title (Ctx *ctx, const char *title);
833 
834 void ctx_listen_full (Ctx     *ctx,
835                       float    x,
836                       float    y,
837                       float    width,
838                       float    height,
839                       CtxEventType  types,
840                       CtxCb    cb,
841                       void    *data1,
842                       void    *data2,
843                       void   (*finalize)(void *listen_data, void *listen_data2,
844                                          void *finalize_data),
845                       void    *finalize_data);
846 void  ctx_event_stop_propagate (CtxEvent *event);
847 void  ctx_listen               (Ctx          *ctx,
848                                 CtxEventType  types,
849                                 CtxCb         cb,
850                                 void*         data1,
851                                 void*         data2);
852 void  ctx_listen_with_finalize (Ctx          *ctx,
853                                 CtxEventType  types,
854                                 CtxCb         cb,
855                                 void*         data1,
856                                 void*         data2,
857                       void   (*finalize)(void *listen_data, void *listen_data2,
858                                          void *finalize_data),
859                       void    *finalize_data);
860 
861 void ctx_init (int *argc, char ***argv); // is a no-op but could launch
862                                          // terminal
863 CtxEvent *ctx_get_event (Ctx *ctx);
864 int       ctx_has_event (Ctx *ctx, int timeout);
865 void      ctx_get_event_fds (Ctx *ctx, int *fd, int *count);
866 
867 int   ctx_pointer_is_down (Ctx *ctx, int no);
868 float ctx_pointer_x (Ctx *ctx);
869 float ctx_pointer_y (Ctx *ctx);
870 void  ctx_freeze (Ctx *ctx);
871 void  ctx_thaw   (Ctx *ctx);
872 int   ctx_events_frozen (Ctx *ctx);
873 void  ctx_events_clear_items (Ctx *ctx);
874 int   ctx_events_width (Ctx *ctx);
875 int   ctx_events_height (Ctx *ctx);
876 
877 /* The following functions drive the event delivery, registered callbacks
878  * are called in response to these being called.
879  */
880 
881 int ctx_key_down  (Ctx *ctx, unsigned int keyval,
882                    const char *string, uint32_t time);
883 int ctx_key_up    (Ctx *ctx, unsigned int keyval,
884                    const char *string, uint32_t time);
885 int ctx_key_press (Ctx *ctx, unsigned int keyval,
886                    const char *string, uint32_t time);
887 
888 
889 int ctx_scrolled  (Ctx *ctx, float x, float y, CtxScrollDirection scroll_direction, uint32_t time);
890 void ctx_incoming_message (Ctx *ctx, const char *message, long time);
891 int ctx_pointer_motion    (Ctx *ctx, float x, float y, int device_no, uint32_t time);
892 int ctx_pointer_release   (Ctx *ctx, float x, float y, int device_no, uint32_t time);
893 int ctx_pointer_press     (Ctx *ctx, float x, float y, int device_no, uint32_t time);
894 int ctx_pointer_drop      (Ctx *ctx, float x, float y, int device_no, uint32_t time,
895                            char *string);
896 
897 typedef enum
898 {
899   CTX_CONT             = '\0', // - contains args from preceding entry
900   CTX_NOP              = ' ', //
901   CTX_DATA             = '(', // size size-in-entries - u32
902   CTX_DATA_REV         = ')', // reverse traversal data marker
903   CTX_SET_RGBA_U8      = '*', // r g b a - u8
904   CTX_NEW_EDGE         = '+', // x0 y0 x1 y1 - s16
905   // set pixel might want a shorter ascii form? or keep it an embedded
906   // only option?
907   CTX_SET_PIXEL        = '-', // 8bit "fast-path" r g b a x y - u8 for rgba, and u16 for x,y
908   /* optimizations that reduce the number of entries used,
909    * not visible outside the drawlist compression, thus
910    * using entries that cannot be used directly as commands
911    * since they would be interpreted as numbers - if values>127
912    * then the embedded font data is harder to escape.
913    */
914   CTX_REL_LINE_TO_X4            = '0', // x1 y1 x2 y2 x3 y3 x4 y4   -- s8
915   CTX_REL_LINE_TO_REL_CURVE_TO  = '1', // x1 y1 cx1 cy1 cx2 cy2 x y -- s8
916   CTX_REL_CURVE_TO_REL_LINE_TO  = '2', // cx1 cy1 cx2 cy2 x y x1 y1 -- s8
917   CTX_REL_CURVE_TO_REL_MOVE_TO  = '3', // cx1 cy1 cx2 cy2 x y x1 y1 -- s8
918   CTX_REL_LINE_TO_X2            = '4', // x1 y1 x2 y2 -- s16
919   CTX_MOVE_TO_REL_LINE_TO       = '5', // x1 y1 x2 y2 -- s16
920   CTX_REL_LINE_TO_REL_MOVE_TO   = '6', // x1 y1 x2 y2 -- s16
921   CTX_FILL_MOVE_TO              = '7', // x y
922   CTX_REL_QUAD_TO_REL_QUAD_TO   = '8', // cx1 x1 cy1 y1 cx1 x2 cy1 y1 -- s8
923   CTX_REL_QUAD_TO_S16           = '9', // cx1 cy1 x y                 - s16
924   // expand with: . :
925   CTX_FLUSH            = ';',
926 
927   CTX_DEFINE_GLYPH     = '@', // unichar width - u32
928   CTX_ARC_TO           = 'A', // x1 y1 x2 y2 radius
929   CTX_ARC              = 'B', // x y radius angle1 angle2 direction
930   CTX_CURVE_TO         = 'C', // cx1 cy1 cx2 cy2 x y
931   CTX_STROKE           = 'E', //
932   CTX_FILL             = 'F', //
933   CTX_RESTORE          = 'G', //
934   CTX_HOR_LINE_TO      = 'H', // x
935   CTX_DEFINE_TEXTURE   = 'I', // "eid" width height format "data"
936   CTX_ROTATE           = 'J', // radians
937   CTX_COLOR            = 'K', // model, c1 c2 c3 ca - has a variable set of
938   // arguments.
939   CTX_LINE_TO          = 'L', // x y
940   CTX_MOVE_TO          = 'M', // x y
941   CTX_BEGIN_PATH       = 'N', //
942   CTX_SCALE            = 'O', // xscale yscale
943   CTX_NEW_PAGE         = 'P', // - NYI - optional page-size
944   CTX_QUAD_TO          = 'Q', // cx cy x y
945   CTX_VIEW_BOX         = 'R', // x y width height
946   CTX_SMOOTH_TO        = 'S', // cx cy x y
947   CTX_SMOOTHQ_TO       = 'T', // x y
948   CTX_RESET            = 'U', //
949   CTX_VER_LINE_TO      = 'V', // y
950   CTX_APPLY_TRANSFORM  = 'W', // a b c d e f - for set_transform combine with identity
951   CTX_EXIT             = 'X', //
952   CTX_ROUND_RECTANGLE  = 'Y', // x y width height radius
953 
954   CTX_CLOSE_PATH2      = 'Z', //
955   CTX_STROKE_SOURCE    = '_', // next source definition applies to strokes
956   CTX_KERNING_PAIR     = '[', // glA glB kerning, glA and glB in u16 kerning in s32
957   CTX_COLOR_SPACE      = ']', // IccSlot  data  data_len,
958                          //    data can be a string with a name,
959                          //    icc data or perhaps our own serialization
960                          //    of profile data
961   CTX_REL_ARC_TO       = 'a', // x1 y1 x2 y2 radius
962   CTX_CLIP             = 'b',
963   CTX_REL_CURVE_TO     = 'c', // cx1 cy1 cx2 cy2 x y
964   CTX_LINE_DASH        = 'd', // dashlen0 [dashlen1 ...]
965   CTX_TRANSLATE        = 'e', // x y
966   CTX_LINEAR_GRADIENT  = 'f', // x1 y1 x2 y2
967   CTX_SAVE             = 'g',
968   CTX_REL_HOR_LINE_TO  = 'h', // x
969   CTX_TEXTURE          = 'i',
970   CTX_PRESERVE         = 'j', //
971   CTX_SET_KEY          = 'k', // - used together with another char to identify
972                               //   a key to set
973   CTX_REL_LINE_TO      = 'l', // x y
974   CTX_REL_MOVE_TO      = 'm', // x y
975   CTX_FONT             = 'n', // as used by text parser
976   CTX_RADIAL_GRADIENT  = 'o', // x1 y1 radius1 x2 y2 radius2
977   CTX_GRADIENT_STOP    = 'p', // argument count depends on current color model
978   CTX_REL_QUAD_TO      = 'q', // cx cy x y
979   CTX_RECTANGLE        = 'r', // x y width height
980   CTX_REL_SMOOTH_TO    = 's', // cx cy x y
981   CTX_REL_SMOOTHQ_TO   = 't', // x y
982   CTX_STROKE_TEXT      = 'u', // string - utf8 string
983   CTX_REL_VER_LINE_TO  = 'v', // y
984   CTX_GLYPH            = 'w', // unichar fontsize
985   CTX_TEXT             = 'x', // string | kern - utf8 data to shape or horizontal kerning amount
986   CTX_IDENTITY         = 'y', //
987   CTX_CLOSE_PATH       = 'z', //
988   CTX_START_GROUP      = '{',
989   CTX_END_GROUP        = '}',
990   CTX_SOURCE_TRANSFORM = '`',
991 
992   CTX_EDGE             = '&',                        // will not occur in commandstream
993   CTX_EDGE_FLIPPED     = '^', // x0 y0 x1 y1 - s16   // thus these use reserved entries as code
994 
995   /* though expressed as two chars in serialization we have
996    * dedicated byte commands for the setters to keep the dispatch
997    * simpler. There is no need for these to be human readable thus we go >128
998    *
999    * unused:        !&<=>?:.=/\`,
1000    * reserved:      '"&   #  %^@
1001    */
1002 
1003 
1004   CTX_FILL_RULE        = 128, // kr rule - u8, default = CTX_FILLE_RULE_EVEN_ODD
1005   CTX_BLEND_MODE       = 129, // kB mode - u8 , default=0
1006 
1007   CTX_MITER_LIMIT      = 130, // km limit - float, default = 0.0
1008 
1009   CTX_LINE_JOIN        = 131, // kj join - u8 , default=0
1010   CTX_LINE_CAP         = 132, // kc cap - u8, default = 0
1011   CTX_LINE_WIDTH       = 133, // kw width, default = 2.0
1012   CTX_GLOBAL_ALPHA     = 134, // ka alpha - default=1.0
1013   CTX_COMPOSITING_MODE = 135, // kc mode - u8 , default=0
1014 
1015   CTX_FONT_SIZE        = 136, // kf size - float, default=?
1016   CTX_TEXT_ALIGN       = 137, // kt align - u8, default = CTX_TEXT_ALIGN_START
1017   CTX_TEXT_BASELINE    = 138, // kb baseline - u8, default = CTX_TEXT_ALIGN_ALPHABETIC
1018   CTX_TEXT_DIRECTION   = 139, // kd
1019 
1020   CTX_SHADOW_BLUR      = 140, // ks
1021   CTX_SHADOW_COLOR     = 141, // kC
1022   CTX_SHADOW_OFFSET_X  = 142, // kx
1023   CTX_SHADOW_OFFSET_Y  = 143, // ky
1024   CTX_IMAGE_SMOOTHING  = 144, // kS
1025   CTX_LINE_DASH_OFFSET = 145, // kD lineDashOffset
1026 
1027   // items marked with % are currently only for the parser
1028   // for instance for svg compatibility or simulated/converted color spaces
1029   // not the serialization/internal render stream
1030   //
1031   CTX_STROKE_RECT      = 200, // strokeRect - only exist in long form
1032   CTX_FILL_RECT        = 201, // fillRect   - only exist in long form
1033 } CtxCode;
1034 
1035 
1036 #pragma pack(push,1)
1037 
1038 typedef struct _CtxCommand CtxCommand;
1039 typedef struct _CtxIterator CtxIterator;
1040 
1041 CtxIterator *
1042 ctx_current_path (Ctx *ctx);
1043 void
1044 ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2);
1045 
1046 #define CTX_ASSERT               0
1047 
1048 #if CTX_ASSERT==1
1049 #define ctx_assert(a)  if(!(a)){fprintf(stderr,"%s:%i assertion failed\n", __FUNCTION__, __LINE__);  }
1050 #else
1051 #define ctx_assert(a)
1052 #endif
1053 
1054 int ctx_get_drawlist_count (Ctx *ctx);
1055 
1056 struct
1057   _CtxCommand
1058 {
1059   union
1060   {
1061     uint8_t  code;
1062     CtxEntry entry;
1063     struct
1064     {
1065       uint8_t code;
1066       float scalex;
1067       float scaley;
1068     } scale;
1069     struct
1070     {
1071       uint8_t code;
1072       uint32_t stringlen;
1073       uint32_t blocklen;
1074       uint8_t cont;
1075       uint8_t data[8]; /* ... and continues */
1076     } data;
1077     struct
1078     {
1079       uint8_t code;
1080       uint32_t stringlen;
1081       uint32_t blocklen;
1082     } data_rev;
1083     struct
1084     {
1085       uint8_t code;
1086       float pad;
1087       float pad2;
1088       uint8_t code_data;
1089       uint32_t stringlen;
1090       uint32_t blocklen;
1091       uint8_t code_cont;
1092       uint8_t utf8[8]; /* .. and continues */
1093     } text;
1094     struct
1095     {
1096       uint8_t  code;
1097       uint32_t key_hash;
1098       float    pad;
1099       uint8_t  code_data;
1100       uint32_t stringlen;
1101       uint32_t blocklen;
1102       uint8_t  code_cont;
1103       uint8_t  utf8[8]; /* .. and continues */
1104     } set;
1105     struct
1106     {
1107       uint8_t  code;
1108       uint32_t pad0;
1109       float    pad1;
1110       uint8_t  code_data;
1111       uint32_t stringlen;
1112       uint32_t blocklen;
1113       uint8_t  code_cont;
1114       uint8_t  utf8[8]; /* .. and continues */
1115     } get;
1116     struct {
1117       uint8_t  code;
1118       uint32_t count; /* better than byte_len in code, but needs to then be set   */
1119       float    pad1;
1120       uint8_t  code_data;
1121       uint32_t byte_len;
1122       uint32_t blocklen;
1123       uint8_t  code_cont;
1124       float    data[2]; /* .. and - possibly continues */
1125     } line_dash;
1126     struct {
1127       uint8_t  code;
1128       uint32_t space_slot;
1129       float    pad1;
1130       uint8_t  code_data;
1131       uint32_t data_len;
1132       uint32_t blocklen;
1133       uint8_t  code_cont;
1134       uint8_t  data[8]; /* .. and continues */
1135     } colorspace;
1136     struct
1137     {
1138       uint8_t  code;
1139       float    x;
1140       float    y;
1141       uint8_t  code_data;
1142       uint32_t stringlen;
1143       uint32_t blocklen;
1144       uint8_t  code_cont;
1145       char     eid[8]; /* .. and continues */
1146     } texture;
1147     struct
1148     {
1149       uint8_t  code;
1150       uint32_t width;
1151       uint32_t height;
1152       uint8_t  code_cont0;
1153       uint16_t format;
1154       uint16_t pad0;
1155       uint32_t pad1;
1156       uint8_t  code_data;
1157       uint32_t stringlen;
1158       uint32_t blocklen;
1159       uint8_t  code_cont1;
1160       char     eid[8]; /* .. and continues */
1161       // followed by - in variable offset code_Data, data_len, datablock_len, cont, pixeldata
1162     } define_texture;
1163     struct
1164     {
1165       uint8_t  code;
1166       float    pad;
1167       float    pad2;
1168       uint8_t  code_data;
1169       uint32_t stringlen;
1170       uint32_t blocklen;
1171       uint8_t  code_cont;
1172       uint8_t  utf8[8]; /* .. and continues */
1173     } text_stroke;
1174     struct
1175     {
1176       uint8_t  code;
1177       float    pad;
1178       float    pad2;
1179       uint8_t  code_data;
1180       uint32_t stringlen;
1181       uint32_t blocklen;
1182       uint8_t  code_cont;
1183       uint8_t  utf8[8]; /* .. and continues */
1184     } set_font;
1185     struct
1186     {
1187       uint8_t code;
1188       float model;
1189       float r;
1190       uint8_t pad1;
1191       float g;
1192       float b;
1193       uint8_t pad2;
1194       float a;
1195     } rgba;
1196     struct
1197     {
1198       uint8_t code;
1199       float model;
1200       float c;
1201       uint8_t pad1;
1202       float m;
1203       float y;
1204       uint8_t pad2;
1205       float k;
1206       float a;
1207     } cmyka;
1208     struct
1209     {
1210       uint8_t code;
1211       float model;
1212       float g;
1213       uint8_t pad1;
1214       float a;
1215     } graya;
1216 
1217     struct
1218     {
1219       uint8_t code;
1220       float model;
1221       float c0;
1222       uint8_t pad1;
1223       float c1;
1224       float c2;
1225       uint8_t pad2;
1226       float c3;
1227       float c4;
1228       uint8_t pad3;
1229       float c5;
1230       float c6;
1231       uint8_t pad4;
1232       float c7;
1233       float c8;
1234       uint8_t pad5;
1235       float c9;
1236       float c10;
1237     } set_color;
1238     struct
1239     {
1240       uint8_t code;
1241       float x;
1242       float y;
1243     } rel_move_to;
1244     struct
1245     {
1246       uint8_t code;
1247       float x;
1248       float y;
1249     } rel_line_to;
1250     struct
1251     {
1252       uint8_t code;
1253       float x;
1254       float y;
1255     } line_to;
1256     struct
1257     {
1258       uint8_t code;
1259       float cx1;
1260       float cy1;
1261       uint8_t pad0;
1262       float cx2;
1263       float cy2;
1264       uint8_t pad1;
1265       float x;
1266       float y;
1267     } rel_curve_to;
1268     struct
1269     {
1270       uint8_t code;
1271       float x;
1272       float y;
1273     } move_to;
1274     struct
1275     {
1276       uint8_t code;
1277       float cx1;
1278       float cy1;
1279       uint8_t pad0;
1280       float cx2;
1281       float cy2;
1282       uint8_t pad1;
1283       float x;
1284       float y;
1285     } curve_to;
1286     struct
1287     {
1288       uint8_t code;
1289       float x1;
1290       float y1;
1291       uint8_t pad0;
1292       float r1;
1293       float x2;
1294       uint8_t pad1;
1295       float y2;
1296       float r2;
1297     } radial_gradient;
1298     struct
1299     {
1300       uint8_t code;
1301       float x1;
1302       float y1;
1303       uint8_t pad0;
1304       float x2;
1305       float y2;
1306     } linear_gradient;
1307     struct
1308     {
1309       uint8_t code;
1310       float x;
1311       float y;
1312       uint8_t pad0;
1313       float width;
1314       float height;
1315       uint8_t pad1;
1316       float radius;
1317     } rectangle;
1318     struct {
1319       uint8_t code;
1320       float x;
1321       float y;
1322       uint8_t pad0;
1323       float width;
1324       float height;
1325     } view_box;
1326 
1327     struct
1328     {
1329       uint8_t code;
1330       uint16_t glyph_before;
1331       uint16_t glyph_after;
1332        int32_t amount;
1333     } kern;
1334 
1335     struct
1336     {
1337       uint8_t code;
1338       uint32_t glyph;
1339       uint32_t advance; // * 256
1340     } define_glyph;
1341 
1342     struct
1343     {
1344       uint8_t code;
1345       uint8_t rgba[4];
1346       uint16_t x;
1347       uint16_t y;
1348     } set_pixel;
1349     struct
1350     {
1351       uint8_t code;
1352       float cx;
1353       float cy;
1354       uint8_t pad0;
1355       float x;
1356       float y;
1357     } quad_to;
1358     struct
1359     {
1360       uint8_t code;
1361       float cx;
1362       float cy;
1363       uint8_t pad0;
1364       float x;
1365       float y;
1366     } rel_quad_to;
1367     struct
1368     {
1369       uint8_t code;
1370       float x;
1371       float y;
1372       uint8_t pad0;
1373       float radius;
1374       float angle1;
1375       uint8_t pad1;
1376       float angle2;
1377       float direction;
1378     }
1379     arc;
1380     struct
1381     {
1382       uint8_t code;
1383       float x1;
1384       float y1;
1385       uint8_t pad0;
1386       float x2;
1387       float y2;
1388       uint8_t pad1;
1389       float radius;
1390     }
1391     arc_to;
1392     /* some format specific generic accesors:  */
1393     struct
1394     {
1395       uint8_t code;
1396       float   x0;
1397       float   y0;
1398       uint8_t pad0;
1399       float   x1;
1400       float   y1;
1401       uint8_t pad1;
1402       float   x2;
1403       float   y2;
1404       uint8_t pad2;
1405       float   x3;
1406       float   y3;
1407       uint8_t pad3;
1408       float   x4;
1409       float   y4;
1410     } c;
1411     struct
1412     {
1413       uint8_t code;
1414       float   a0;
1415       float   a1;
1416       uint8_t pad0;
1417       float   a2;
1418       float   a3;
1419       uint8_t pad1;
1420       float   a4;
1421       float   a5;
1422       uint8_t pad2;
1423       float   a6;
1424       float   a7;
1425       uint8_t pad3;
1426       float   a8;
1427       float   a9;
1428     } f;
1429     struct
1430     {
1431       uint8_t  code;
1432       uint32_t a0;
1433       uint32_t a1;
1434       uint8_t  pad0;
1435       uint32_t a2;
1436       uint32_t a3;
1437       uint8_t  pad1;
1438       uint32_t a4;
1439       uint32_t a5;
1440       uint8_t  pad2;
1441       uint32_t a6;
1442       uint32_t a7;
1443       uint8_t  pad3;
1444       uint32_t a8;
1445       uint32_t a9;
1446     } u32;
1447     struct
1448     {
1449       uint8_t  code;
1450       uint64_t a0;
1451       uint8_t  pad0;
1452       uint64_t a1;
1453       uint8_t  pad1;
1454       uint64_t a2;
1455       uint8_t  pad2;
1456       uint64_t a3;
1457       uint8_t  pad3;
1458       uint64_t a4;
1459     } u64;
1460     struct
1461     {
1462       uint8_t code;
1463       int32_t a0;
1464       int32_t a1;
1465       uint8_t pad0;
1466       int32_t a2;
1467       int32_t a3;
1468       uint8_t pad1;
1469       int32_t a4;
1470       int32_t a5;
1471       uint8_t pad2;
1472       int32_t a6;
1473       int32_t a7;
1474       uint8_t pad3;
1475       int32_t a8;
1476       int32_t a9;
1477     } s32;
1478     struct
1479     {
1480       uint8_t code;
1481       int16_t a0;
1482       int16_t a1;
1483       int16_t a2;
1484       int16_t a3;
1485       uint8_t pad0;
1486       int16_t a4;
1487       int16_t a5;
1488       int16_t a6;
1489       int16_t a7;
1490       uint8_t pad1;
1491       int16_t a8;
1492       int16_t a9;
1493       int16_t a10;
1494       int16_t a11;
1495       uint8_t pad2;
1496       int16_t a12;
1497       int16_t a13;
1498       int16_t a14;
1499       int16_t a15;
1500       uint8_t pad3;
1501       int16_t a16;
1502       int16_t a17;
1503       int16_t a18;
1504       int16_t a19;
1505     } s16;
1506     struct
1507     {
1508       uint8_t code;
1509       uint16_t a0;
1510       uint16_t a1;
1511       uint16_t a2;
1512       uint16_t a3;
1513       uint8_t pad0;
1514       uint16_t a4;
1515       uint16_t a5;
1516       uint16_t a6;
1517       uint16_t a7;
1518       uint8_t pad1;
1519       uint16_t a8;
1520       uint16_t a9;
1521       uint16_t a10;
1522       uint16_t a11;
1523       uint8_t pad2;
1524       uint16_t a12;
1525       uint16_t a13;
1526       uint16_t a14;
1527       uint16_t a15;
1528       uint8_t pad3;
1529       uint16_t a16;
1530       uint16_t a17;
1531       uint16_t a18;
1532       uint16_t a19;
1533     } u16;
1534     struct
1535     {
1536       uint8_t code;
1537       uint8_t a0;
1538       uint8_t a1;
1539       uint8_t a2;
1540       uint8_t a3;
1541       uint8_t a4;
1542       uint8_t a5;
1543       uint8_t a6;
1544       uint8_t a7;
1545       uint8_t pad0;
1546       uint8_t a8;
1547       uint8_t a9;
1548       uint8_t a10;
1549       uint8_t a11;
1550       uint8_t a12;
1551       uint8_t a13;
1552       uint8_t a14;
1553       uint8_t a15;
1554       uint8_t pad1;
1555       uint8_t a16;
1556       uint8_t a17;
1557       uint8_t a18;
1558       uint8_t a19;
1559       uint8_t a20;
1560       uint8_t a21;
1561       uint8_t a22;
1562       uint8_t a23;
1563     } u8;
1564     struct
1565     {
1566       uint8_t code;
1567       int8_t a0;
1568       int8_t a1;
1569       int8_t a2;
1570       int8_t a3;
1571       int8_t a4;
1572       int8_t a5;
1573       int8_t a6;
1574       int8_t a7;
1575       uint8_t pad0;
1576       int8_t a8;
1577       int8_t a9;
1578       int8_t a10;
1579       int8_t a11;
1580       int8_t a12;
1581       int8_t a13;
1582       int8_t a14;
1583       int8_t a15;
1584       uint8_t pad1;
1585       int8_t a16;
1586       int8_t a17;
1587       int8_t a18;
1588       int8_t a19;
1589       int8_t a20;
1590       int8_t a21;
1591       int8_t a22;
1592       int8_t a23;
1593     } s8;
1594   };
1595   CtxEntry next_entry; // also pads size of CtxCommand slightly.
1596 };
1597 
1598 typedef struct _CtxImplementation CtxImplementation;
1599 struct _CtxImplementation
1600 {
1601   void (*process)        (void *renderer, CtxCommand *entry);
1602   void (*reset)          (void *renderer);
1603   void (*flush)          (void *renderer);
1604   char *(*get_clipboard) (void *ctxctx);
1605   void (*set_clipboard)  (void *ctxctx, const char *text);
1606   void (*free)           (void *renderer);
1607 };
1608 
1609 CtxCommand *ctx_iterator_next (CtxIterator *iterator);
1610 
1611 #define ctx_arg_string()  ((char*)&entry[2].data.u8[0])
1612 
1613 
1614 /* The above should be public API
1615  */
1616 
1617 #pragma pack(pop)
1618 
1619 /* access macros for nth argument of a given type when packed into
1620  * an CtxEntry pointer in current code context
1621  */
1622 #define ctx_arg_float(no) entry[(no)>>1].data.f[(no)&1]
1623 #define ctx_arg_u64(no)   entry[(no)].data.u64[0]
1624 #define ctx_arg_u32(no)   entry[(no)>>1].data.u32[(no)&1]
1625 #define ctx_arg_s32(no)   entry[(no)>>1].data.s32[(no)&1]
1626 #define ctx_arg_u16(no)   entry[(no)>>2].data.u16[(no)&3]
1627 #define ctx_arg_s16(no)   entry[(no)>>2].data.s16[(no)&3]
1628 #define ctx_arg_u8(no)    entry[(no)>>3].data.u8[(no)&7]
1629 #define ctx_arg_s8(no)    entry[(no)>>3].data.s8[(no)&7]
1630 #define ctx_arg_string()  ((char*)&entry[2].data.u8[0])
1631 
1632 typedef enum
1633 {
1634   CTX_GRAY           = 1,
1635   CTX_RGB            = 3,
1636   CTX_DRGB           = 4,
1637   CTX_CMYK           = 5,
1638   CTX_DCMYK          = 6,
1639   CTX_LAB            = 7,
1640   CTX_LCH            = 8,
1641   CTX_GRAYA          = 101,
1642   CTX_RGBA           = 103,
1643   CTX_DRGBA          = 104,
1644   CTX_CMYKA          = 105,
1645   CTX_DCMYKA         = 106,
1646   CTX_LABA           = 107,
1647   CTX_LCHA           = 108,
1648   CTX_GRAYA_A        = 201,
1649   CTX_RGBA_A         = 203,
1650   CTX_RGBA_A_DEVICE  = 204,
1651   CTX_CMYKA_A        = 205,
1652   CTX_DCMYKA_A       = 206,
1653   // RGB  device and  RGB  ?
1654 } CtxColorModel;
1655 
1656 enum _CtxAntialias
1657 {
1658   CTX_ANTIALIAS_DEFAULT, //
1659   CTX_ANTIALIAS_NONE, // non-antialiased
1660   CTX_ANTIALIAS_FAST, // aa 3    // deprected or is default equal to this now?
1661   CTX_ANTIALIAS_GOOD, // aa 5    // this should perhaps still be 5?
1662 };
1663 typedef enum _CtxAntialias CtxAntialias;
1664 
1665 enum _CtxCursor
1666 {
1667   CTX_CURSOR_UNSET,
1668   CTX_CURSOR_NONE,
1669   CTX_CURSOR_ARROW,
1670   CTX_CURSOR_IBEAM,
1671   CTX_CURSOR_WAIT,
1672   CTX_CURSOR_HAND,
1673   CTX_CURSOR_CROSSHAIR,
1674   CTX_CURSOR_RESIZE_ALL,
1675   CTX_CURSOR_RESIZE_N,
1676   CTX_CURSOR_RESIZE_S,
1677   CTX_CURSOR_RESIZE_E,
1678   CTX_CURSOR_RESIZE_NE,
1679   CTX_CURSOR_RESIZE_SE,
1680   CTX_CURSOR_RESIZE_W,
1681   CTX_CURSOR_RESIZE_NW,
1682   CTX_CURSOR_RESIZE_SW,
1683   CTX_CURSOR_MOVE
1684 };
1685 typedef enum _CtxCursor CtxCursor;
1686 
1687 /* to be used immediately after a ctx_listen or ctx_listen_full causing the
1688  * cursor to change when hovering the listen area.
1689  */
1690 void ctx_listen_set_cursor (Ctx      *ctx,
1691                             CtxCursor cursor);
1692 
1693 /* lower level cursor setting that is independent of ctx event handling
1694  */
1695 void         ctx_set_cursor (Ctx *ctx, CtxCursor cursor);
1696 CtxCursor    ctx_get_cursor (Ctx *ctx);
1697 void         ctx_set_antialias (Ctx *ctx, CtxAntialias antialias);
1698 CtxAntialias ctx_get_antialias (Ctx *ctx);
1699 void         ctx_set_render_threads   (Ctx *ctx, int n_threads);
1700 int          ctx_get_render_threads   (Ctx *ctx);
1701 
1702 void         ctx_set_hash_cache (Ctx *ctx, int enable_hash_cache);
1703 int          ctx_get_hash_cache (Ctx *ctx);
1704 
1705 
1706 typedef struct _CtxParser CtxParser;
1707   CtxParser *ctx_parser_new (
1708   Ctx       *ctx,
1709   int        width,
1710   int        height,
1711   float      cell_width,
1712   float      cell_height,
1713   int        cursor_x,
1714   int        cursor_y,
1715   int   (*set_prop)(void *prop_data, uint32_t key, const char *data,  int len),
1716   int   (*get_prop)(void *prop_Data, const char *key, char **data, int *len),
1717   void  *prop_data,
1718   void (*exit) (void *exit_data),
1719   void *exit_data);
1720 
1721 
1722 enum _CtxColorSpace
1723 {
1724   CTX_COLOR_SPACE_DEVICE_RGB,
1725   CTX_COLOR_SPACE_DEVICE_CMYK,
1726   CTX_COLOR_SPACE_USER_RGB,
1727   CTX_COLOR_SPACE_USER_CMYK,
1728   CTX_COLOR_SPACE_TEXTURE
1729 };
1730 typedef enum _CtxColorSpace CtxColorSpace;
1731 
1732 /* sets the color space for a slot, the space is either a string of
1733  * "sRGB" "rec2020" .. etc or an icc profile.
1734  *
1735  * The slots device_rgb and device_cmyk is mostly to be handled outside drawing
1736  * code, and user_rgb and user_cmyk is to be used. With no user_cmyk set
1737  * user_cmyk == device_cmyk.
1738  *
1739  * The set profiles follows the graphics state.
1740  */
1741 void ctx_colorspace (Ctx           *ctx,
1742                      CtxColorSpace  space_slot,
1743                      unsigned char *data,
1744                      int            data_length);
1745 
1746 void
1747 ctx_parser_set_size (CtxParser *parser,
1748                      int        width,
1749                      int        height,
1750                      float      cell_width,
1751                      float      cell_height);
1752 
1753 void ctx_parser_feed_bytes (CtxParser *parser, const char *data, int count);
1754 
1755 int
1756 ctx_get_contents (const char     *path,
1757                    unsigned char **contents,
1758                    long           *length);
1759 int
1760 ctx_get_contents2 (const char     *path,
1761                    unsigned char **contents,
1762                    long           *length,
1763                    long            max_len);
1764 
1765 void ctx_parser_free (CtxParser *parser);
1766 typedef struct _CtxSHA1 CtxSHA1;
1767 
1768 void
1769 ctx_bin2base64 (const void *bin,
1770                 int         bin_length,
1771                 char       *ascii);
1772 int
1773 ctx_base642bin (const char    *ascii,
1774                 int           *length,
1775                 unsigned char *bin);
1776 
1777 
1778 struct
1779   _CtxMatrix
1780 {
1781   float m[3][2];
1782 };
1783 
1784 void ctx_apply_matrix (Ctx *ctx, CtxMatrix *matrix);
1785 void ctx_matrix_apply_transform (const CtxMatrix *m, float *x, float *y);
1786 void ctx_matrix_invert (CtxMatrix *m);
1787 void ctx_matrix_identity (CtxMatrix *matrix);
1788 void ctx_matrix_scale (CtxMatrix *matrix, float x, float y);
1789 void ctx_matrix_rotate (CtxMatrix *matrix, float angle);
1790 void ctx_matrix_multiply (CtxMatrix       *result,
1791                           const CtxMatrix *t,
1792                           const CtxMatrix *s);
1793 
1794 
1795 /* we already have the start of the file available which disambiguates some
1796  * of our important supported formats, give preference to magic, then extension
1797  * then text plain vs binary.
1798  */
1799 const char *ctx_guess_media_type (const char *path, const char *content, int len);
1800 
1801 /* get media-type, with preference towards using extension of path and
1802  * not reading the data at all.
1803  */
1804 const char *ctx_path_get_media_type (const char *path);
1805 
1806 typedef enum {
1807   CTX_MEDIA_TYPE_NONE=0,
1808   CTX_MEDIA_TYPE_TEXT,
1809   CTX_MEDIA_TYPE_IMAGE,
1810   CTX_MEDIA_TYPE_VIDEO,
1811   CTX_MEDIA_TYPE_AUDIO,
1812   CTX_MEDIA_TYPE_INODE,
1813   CTX_MEDIA_TYPE_APPLICATION,
1814 } CtxMediaTypeClass;
1815 
1816 CtxMediaTypeClass ctx_media_type_class (const char *media_type);
1817 
1818 
1819 float ctx_term_get_cell_width (Ctx *ctx);
1820 float ctx_term_get_cell_height (Ctx *ctx);
1821 
1822 
1823 
1824 
1825 
1826 #if 1 // CTX_VT
1827 
1828 typedef struct _VT VT;
1829 void vt_feed_keystring    (VT *vt, CtxEvent *event, const char *str);
1830 void vt_paste             (VT *vt, const char *str);
1831 char *vt_get_selection    (VT *vt);
1832 long vt_rev               (VT *vt);
1833 int  vt_has_blink         (VT *vt);
1834 int ctx_vt_had_alt_screen (VT *vt);
1835 
1836 int  ctx_clients_need_redraw   (Ctx *ctx);
1837 void ctx_clients_handle_events (Ctx *ctx);
1838 
1839 
1840 typedef struct _CtxBuffer CtxBuffer;
1841 CtxBuffer *ctx_buffer_new_for_data (void *data, int width, int height,
1842                                     int stride,
1843                                     CtxPixelFormat pixel_format,
1844                                     void (*freefunc) (void *pixels, void *user_data),
1845                                     void *user_data);
1846 
1847 
1848 
1849 
1850 
1851 
1852 
1853 #endif
1854 
1855 
1856 #ifndef CTX_CODEC_CHAR
1857 //#define CTX_CODEC_CHAR '\035'
1858 //#define CTX_CODEC_CHAR 'a'
1859 #define CTX_CODEC_CHAR '\020' // datalink escape
1860 //#define CTX_CODEC_CHAR '^'
1861 #endif
1862 
1863 #ifndef assert
1864 #define assert(a)
1865 #endif
1866 
1867 #ifdef __cplusplus
1868 }
1869 #endif
1870 #endif
1871 #ifndef __CTX_H__
1872 #define __CTX_H__
1873 #ifndef _DEFAULT_SOURCE
1874 #define _DEFAULT_SOURCE
1875 #endif
1876 #ifndef _XOPEN_SOURCE
1877 #define _XOPEN_SOURCE 600
1878 #endif
1879 
1880 #ifndef CTX_STRING_H
1881 #define CTX_STRING_H
1882 
1883 typedef struct _CtxString CtxString;
1884 struct _CtxString
1885 {
1886   char *str;
1887   int   length;
1888   int   utf8_length;
1889   int   allocated_length;
1890   int   is_line;
1891 };
1892 
1893 CtxString   *ctx_string_new_with_size  (const char *initial, int initial_size);
1894 CtxString   *ctx_string_new            (const char *initial);
1895 CtxString   *ctx_string_new_printf (const char *format, ...);
1896 char       *ctx_string_dissolve       (CtxString *string);
1897 void        ctx_string_free           (CtxString *string, int freealloc);
1898 const char *ctx_string_get            (CtxString *string);
1899 uint32_t    ctx_string_get_unichar    (CtxString *string, int pos);
1900 int         ctx_string_get_length     (CtxString *string);
1901 int         ctx_string_get_utf8length (CtxString *string);
1902 void        ctx_string_set            (CtxString *string, const char *new_string);
1903 void        ctx_string_clear          (CtxString *string);
1904 void        ctx_string_append_str     (CtxString *string, const char *str);
1905 void        ctx_string_append_byte    (CtxString *string, char  val);
1906 void        ctx_string_append_string  (CtxString *string, CtxString *string2);
1907 void        ctx_string_append_unichar (CtxString *string, unsigned int unichar);
1908 void        ctx_string_append_data    (CtxString *string, const char *data, int len);
1909 
1910 void        ctx_string_pre_alloc       (CtxString *string, int size);
1911 void        ctx_string_append_utf8char (CtxString *string, const char *str);
1912 void        ctx_string_append_printf  (CtxString *string, const char *format, ...);
1913 void        ctx_string_replace_utf8   (CtxString *string, int pos, const char *new_glyph);
1914 void        ctx_string_insert_utf8    (CtxString *string, int pos, const char *new_glyph);
1915 
1916 void        ctx_string_insert_unichar (CtxString *string, int pos, uint32_t unichar);
1917 void        ctx_string_replace_unichar (CtxString *string, int pos, uint32_t unichar);
1918 void        ctx_string_remove         (CtxString *string, int pos);
1919 char       *ctx_strdup_printf         (const char *format, ...);
1920 
1921 #ifndef TRUE
1922 #define TRUE 1
1923 #endif
1924 #ifndef FALSE
1925 #define FALSE 0
1926 #endif
1927 
1928 #endif
1929 #ifndef _CTX_INTERNAL_FONT_
1930 #define _CTX_INTERNAL_FONT_
1931 
1932 #ifndef CTX_FONT_ascii
1933 /* this is a ctx encoded font based on DejaVuSans.ttf */
1934 /* CTX_SUBDIV:8  CTX_BAKE_FONT_SIZE:160 */
1935 /* glyphs covered:
1936 
1937  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi
1938   jklmnopqrstuvwxyz{|}~  */
1939 static const struct __attribute__ ((packed)) {uint8_t code; uint32_t a; uint32_t b;}
1940 ctx_font_ascii[]={
1941 {'@', 0x00000020, 0x00002bb0},/*                 x-advance: 43.687500 */
1942 {'@', 0x00000021, 0x00003719},/*        !        x-advance: 55.097656 */
1943 {'M', 0x41a5e7f2, 0xc1886037},
1944 {'l', 0x4159fc90, 0x00000000},
1945 {'4', 0x00880000, 0x0000ff94},
1946 {'6', 0xff780000, 0xfd670000},
1947 {'l', 0x4159fc90, 0x00000000},
1948 {'l', 0x00000000, 0x422fd6c4},
1949 {'l', 0xbfabcfe0, 0x41bfad86},
1950 {'l', 0xc12df5b2, 0x00000000},
1951 {'l', 0xbfb46710, 0xc1bfad86},
1952 {'l', 0x00000000, 0xc22fd6c4},
1953 {'@', 0x00000022, 0x00003f38},/*        "        x-advance: 63.218750 */
1954 {'M', 0x41c50c07, 0xc2c86716},
1955 {'l', 0x00000000, 0x4214fe48},
1956 {'4', 0x0000ffa5, 0xfed70000},
1957 {'6', 0x0000005b, 0x000000ca},
1958 {'l', 0x00000000, 0x4214fe48},
1959 {'l', 0xc1368ce4, 0x00000000},
1960 {'l', 0x00000000, 0xc214fe48},
1961 {'l', 0x41368ce4, 0x00000000},
1962 {'@', 0x00000023, 0x0000732a},/*        #        x-advance: 115.164062 */
1963 {'M', 0x428c8973, 0xc271e113},
1964 {'l', 0xc19c3dda, 0x00000000},
1965 {'4', 0x00b3ffd3, 0x0000009d},
1966 {'6', 0xff4d002c, 0xfecfffb0},
1967 {'l', 0xc0df5b10, 0x41ded19c},
1968 {'l', 0x419cc74c, 0x00000000},
1969 {'l', 0x40e180e0, 0xc1ded19c},
1970 {'l', 0x412bcfe8, 0x00000000},
1971 {'l', 0xc0dd3540, 0x41ded19c},
1972 {'l', 0x41a78448, 0x00000000},
1973 {'l', 0x00000000, 0x41255e7c},
1974 {'l', 0xc1bc74d4, 0x00000000},
1975 {'l', 0xc0b01b80, 0x41b35430},
1976 {'l', 0x41aabd00, 0x00000000},
1977 {'l', 0x00000000, 0x41244b9a},
1978 {'l', 0xc1bfad88, 0x00000000},
1979 {'l', 0xc0df5b10, 0x41de4829},
1980 {'l', 0xc12bcfe4, 0x00000000},
1981 {'l', 0x40dd3540, 0xc1de4829},
1982 {'l', 0xc19d50c0, 0x00000000},
1983 {'l', 0xc0dd3540, 0x41de4829},
1984 {'l', 0xc12ce2ca, 0x00000000},
1985 {'l', 0x40df5b10, 0xc1de4829},
1986 {'l', 0xc1a920a5, 0x00000000},
1987 {'l', 0x00000000, 0xc1244b9a},
1988 {'l', 0x41bcfe48, 0x00000000},
1989 {'l', 0x40b46718, 0xc1b35430},
1990 {'l', 0xc1ace2cb, 0x00000000},
1991 {'l', 0x00000000, 0xc1255e7c},
1992 {'l', 0x41c1d353, 0x00000000},
1993 {'l', 0x40db0f78, 0xc1ded19c},
1994 {'l', 0x412df5b0, 0x00000000},
1995 {'@', 0x00000024, 0x00005773},/*        $        x-advance: 87.449219 */
1996 {'M', 0x4239c595, 0x41a19c59},
1997 {'4', 0x0000ffcb, 0xff5f0000},
1998 {'q', 0xc0e180d8, 0xbe09731d},
1999 {0, 0xc16180dc, 0xbfce2cac},
2000 {'9', 0xfff4ffc8, 0xffdcff8f},
2001 {'l', 0x00000000, 0xc14149e1},
2002 {'q', 0x40db0f76, 0x4089731e},
2003 {0, 0x415d3543, 0x40d05278},
2004 {'9', 0x00110038, 0x00110073},
2005 {'l', 0x00000000, 0xc1f4d50c},
2006 {'q', 0xc16d50c2, 0xc01aa180},
2007 {0, 0xc1ace2cb, 0xc10301b8},
2008 {'q', 0xc0d6c3de, 0xc0b8b2b0},
2009 {0, 0xc0d6c3de, 0xc17d6c3c},
2010 {'q', 0x00000000, 0xc12f0898},
2011 {0, 0x40ea180e, 0xc189fc90},
2012 {'9', 0xffce003a, 0xffc700a8},
2013 {'4', 0xff820000, 0x00000035},
2014 {'l', 0x00000000, 0x417920a8},
2015 {'8', 0x0a600231, 0x165b082e},
2016 {'l', 0x00000000, 0x413beb60},
2017 {'8', 0xdea5ead4, 0xf2a0f4d2},
2018 {'l', 0x00000000, 0x41e54302},
2019 {'q', 0x4173c228, 0x401655f0},
2020 {0, 0x41b35432, 0x41063a6c},
2021 {'q', 0x40e5cc70, 0x40c149e0},
2022 {0, 0x40e5cc70, 0x4184149e},
2023 {'q', 0x00000000, 0x413579fc},
2024 {0, 0xc0f4d510, 0x418f5b0f},
2025 {'9', 0x0034ffc4, 0x003cff51},
2026 {'6', 0x00a20000, 0xfdc1ffcb},
2027 {'l', 0x00000000, 0xc1dc2258},
2028 {'8', 0x23a106c2, 0x4be01ce0},
2029 {'8', 0x471e2e00, 0x2561191e},
2030 {'m', 0x40d6c3d8, 0x414e2cac},
2031 {'l', 0x00000000, 0x41e87bb4},
2032 {'8', 0xda66f744, 0xb322e322},
2033 {'8', 0xb5dfd100, 0xd898e5e0},
2034 {'@', 0x00000025, 0x0000829a},/*        %        x-advance: 130.601562 */
2035 {'M', 0x42c7dda3, 0xc2306037},
2036 {'8', 0x27b700d2, 0x6ee627e6},
2037 {'8', 0x6e1a4500, 0x2749271a},
2038 {'8', 0xd947002d, 0x921ad81a},
2039 {'8', 0x92e6ba00, 0xd8b9d8e6},
2040 {'m', 0x00000000, 0xc1086034},
2041 {'q', 0x4129aa18, 0x00000000},
2042 {0, 0x4186c3dc, 0x40ec3dd8},
2043 {'q', 0x40c7bb50, 0x40ec3dd8},
2044 {0, 0x40c7bb50, 0x419f768c},
2045 {'q', 0x00000000, 0x4148ce2d},
2046 {0, 0xc0c9e120, 0x419f768d},
2047 {'q', 0xc0c7bb40, 0x40ea180d},
2048 {0, 0xc1863a68, 0x40ea180d},
2049 {'q', 0xc12bcfe8, 0x34000000},
2050 {0, 0xc187d6c4, 0xc0ea180d},
2051 {'q', 0xc0c7bb40, 0xc0ec3dda},
2052 {0, 0xc0c7bb40, 0xc19f768d},
2053 {'q', 0x00000000, 0xc149e114},
2054 {0, 0x40c7bb40, 0xc19f768c},
2055 {'9', 0xffc50032, 0xffc50087},
2056 {'m', 0xc28a8603, 0xc2237d6c},
2057 {'8', 0x28b700d2, 0x6de627e6},
2058 {'8', 0x6e1a4600, 0x2749271a},
2059 {'8', 0xd949002e, 0x921ad91a},
2060 {'8', 0x93e6bb00, 0xd8b7d8e6},
2061 {'m', 0x42726a86, 0xc1086038},
2062 {'l', 0x412bcfe0, 0x00000000},
2063 {'4', 0x033ffe0b, 0x0000ffab},
2064 {'6', 0xfcc101f5, 0x0000fe1c},
2065 {'q', 0x4129aa14, 0x00000000},
2066 {0, 0x41874d50, 0x40ec3de0},
2067 {'q', 0x40c9e110, 0x40ea1800},
2068 {0, 0x40c9e110, 0x419eed18},
2069 {'q', 0x00000000, 0x414af3f8},
2070 {0, 0xc0c9e110, 0x41a00000},
2071 {'q', 0xc0c7bb48, 0x40ea1808},
2072 {0, 0xc1874d51, 0x40ea1808},
2073 {'q', 0xc12abcfe, 0x00000000},
2074 {0, 0xc1874d51, 0xc0ea1808},
2075 {'q', 0xc0c59579, 0xc0ec3dd8},
2076 {0, 0xc0c59579, 0xc1a00000},
2077 {'q', 0x00000000, 0xc147bb48},
2078 {0, 0x40c7bb47, 0xc19eed18},
2079 {'q', 0x40c7bb46, 0xc0ec3de0},
2080 {0, 0x4186c3de, 0xc0ec3de0},
2081 {'@', 0x00000026, 0x00006b2e},/*        &        x-advance: 107.179688 */
2082 {'M', 0x4205b0f7, 0xc257920a},
2083 {'8', 0x56b92bd0, 0x5aea2aea},
2084 {'q', 0x00000000, 0x411cc74e},
2085 {0, 0x40e3a6a8, 0x41827845},
2086 {'q', 0x40e3a6a8, 0x40d05278},
2087 {0, 0x418ed19c, 0x40d05278},
2088 {'8', 0xf05f0033, 0xcd53ef2c},
2089 {'6', 0xfeddfee4, 0xffc4004b},
2090 {'l', 0x42086037, 0x420b98e9},
2091 {'q', 0x407d6c40, 0xc0bf2410},
2092 {0, 0x40c59570, 0xc14c06e0},
2093 {'9', 0xffca0011, 0xff8d0014},
2094 {'l', 0x4147bb40, 0x00000000},
2095 {'q', 0xbf4e2c80, 0x410dbeb8},
2096 {0, 0xc0897310, 0x418c225c},
2097 {'9', 0x0045ffe5, 0x0088ffb3},
2098 {'4', 0x00990095, 0x0000ff79},
2099 {'l', 0xc1198e98, 0xc11dda33},
2100 {'q', 0xc0df5b10, 0x40bf2414},
2101 {0, 0xc16a1810, 0x410ed19c},
2102 {'q', 0xc0f4d510, 0x4038b2ae},
2103 {0, 0xc1838b2c, 0x4038b2ae},
2104 {'q', 0xc181655e, 0x34000000},
2105 {0, 0xc1d38b2a, 0xc1131d35},
2106 {'q', 0xc1244b99, 0xc114301c},
2107 {0, 0xc1244b99, 0xc1bd87bb},
2108 {'q', 0x00000000, 0xc109731e},
2109 {0, 0x408fe482, 0xc180dbeb},
2110 {'q', 0x408fe484, 0xc0f2af40},
2111 {0, 0x4157d6c4, 0xc163a6a8},
2112 {'8', 0xbdd9dfe7, 0xbef3dff3},
2113 {'q', 0x00000000, 0xc12df5b0},
2114 {0, 0x40ee63a4, 0xc18b98e8},
2115 {'q', 0x40ee63a8, 0xc0d49e10},
2116 {0, 0x419e63a6, 0xc0d49e10},
2117 {'8', 0x0958002c, 0x1c5a092c},
2118 {'l', 0x00000000, 0x41436fb0},
2119 {'8', 0xdaa7e7d2, 0xf3b2f3d6},
2120 {'8', 0x1ea500c8, 0x4cde1dde},
2121 {'8', 0x370f1b00, 0x4d401b10},
2122 {'@', 0x00000027, 0x000025c9},/*        '        x-advance: 37.785156 */
2123 {'M', 0x41c50c07, 0xc2c86716},
2124 {'l', 0x00000000, 0x4214fe48},
2125 {'l', 0xc1368ce3, 0x00000000},
2126 {'l', 0x00000000, 0xc214fe48},
2127 {'l', 0x41368ce3, 0x00000000},
2128 {'@', 0x00000028, 0x0000359f},/*        (        x-advance: 53.621094 */
2129 {'M', 0x422a7844, 0xc2d09732},
2130 {'q', 0xc10fe480, 0x4176fae0},
2131 {0, 0xc155b0f6, 0x41f44b9c},
2132 {'q', 0xc08b98e8, 0x41719c54},
2133 {0, 0xc08b98e8, 0x41f4d50a},
2134 {'q', 0x00000000, 0x41780dbe},
2135 {0, 0x408b98e8, 0x41f5e7f2},
2136 {'9', 0x00790023, 0x00f4006a},
2137 {'l', 0xc12bcfe2, 0x00000000},
2138 {'q', 0xc12112e6, 0xc17c5958},
2139 {0, 0xc1719c5a, 0xc1f80dbf},
2140 {'q', 0xc09eed18, 0xc173c224},
2141 {0, 0xc09eed18, 0xc1f225cc},
2142 {'q', 0x00000000, 0xc16f768c},
2143 {0, 0x409eed18, 0xc1f112e6},
2144 {'q', 0x409eed1c, 0xc172af40},
2145 {0, 0x41719c5a, 0xc1f80dc0},
2146 {'l', 0x412bcfe2, 0x00000000},
2147 {'@', 0x00000029, 0x0000359f},/*        )        x-advance: 53.621094 */
2148 {'M', 0x41301b7d, 0xc2d09732},
2149 {'l', 0x412bcfe5, 0x00000000},
2150 {'q', 0x412112e6, 0x417d6c40},
2151 {0, 0x41708972, 0x41f80dc0},
2152 {'q', 0x40a112e8, 0x4172af40},
2153 {0, 0x40a112e8, 0x41f112e6},
2154 {'q', 0x00000000, 0x41708974},
2155 {0, 0xc0a112e8, 0x41f225cc},
2156 {'9', 0x0079ffd9, 0x00f8ff88},
2157 {'l', 0xc12bcfe5, 0x00000000},
2158 {'q', 0x410ed19d, 0xc175e7f3},
2159 {0, 0x41549e11, 0xc1f44b99},
2160 {'q', 0x408dbeb4, 0xc173c226},
2161 {0, 0x408dbeb4, 0xc1f5e7f2},
2162 {'q', 0x00000000, 0xc1780dc0},
2163 {0, 0xc08dbeb4, 0xc1f4d50a},
2164 {'q', 0xc08b98e8, 0xc1719c58},
2165 {0, 0xc1549e11, 0xc1f44b9c},
2166 {'@', 0x0000002a, 0x000044b9},/*        *        x-advance: 68.722656 */
2167 {'M', 0x42814302, 0xc2a761ef},
2168 {'l', 0xc1c0c070, 0x41505278},
2169 {'l', 0x41c0c070, 0x41516560},
2170 {'l', 0xc07920b0, 0x40d27848},
2171 {'l', 0xc1b46716, 0xc159fc94},
2172 {'l', 0x00000000, 0x41ca6a88},
2173 {'l', 0xc0f4d50c, 0x00000000},
2174 {'l', 0x00000000, 0xc1ca6a88},
2175 {'l', 0xc1b46716, 0x4159fc94},
2176 {'l', 0xc07920a8, 0xc0d27848},
2177 {'l', 0x41c0c06e, 0xc1516560},
2178 {'l', 0xc1c0c06e, 0xc1505278},
2179 {'l', 0x407920a4, 0xc0d49e10},
2180 {'l', 0x41b46716, 0x4159fc90},
2181 {'l', 0x36000000, 0xc1ca6a84},
2182 {'l', 0x40f4d50c, 0x00000000},
2183 {'l', 0x00000000, 0x41ca6a84},
2184 {'l', 0x41b46716, 0xc159fc90},
2185 {'l', 0x407920b0, 0x40d49e10},
2186 {'@', 0x0000002b, 0x0000732a},/*        +        x-advance: 115.164062 */
2187 {'M', 0x427ce2ca, 0xc2ac5957},
2188 {'l', 0x00000000, 0x421587ba},
2189 {'l', 0x421587bc, 0x00000000},
2190 {'l', 0x00000000, 0x41368ce4},
2191 {'l', 0xc21587bc, 0x00000000},
2192 {'l', 0x00000000, 0x421587bb},
2193 {'l', 0xc1346714, 0x00000000},
2194 {'l', 0x00000000, 0xc21587bb},
2195 {'l', 0xc21587bb, 0x00000000},
2196 {'l', 0xb5800000, 0xc1368ce4},
2197 {'l', 0x421587bb, 0x00000000},
2198 {'l', 0x00000000, 0xc21587ba},
2199 {'l', 0x41346714, 0x00000000},
2200 {'@', 0x0000002c, 0x00002bb0},/*        ,        x-advance: 43.687500 */
2201 {'M', 0x4180dbeb, 0xc1886037},
2202 {'l', 0x416293c2, 0x00000000},
2203 {'l', 0x00000000, 0x4138b2b0},
2204 {'l', 0xc1301b7c, 0x41abcfe4},
2205 {'l', 0xc10a8604, 0x00000000},
2206 {'l', 0x40b01b7c, 0xc1abcfe4},
2207 {'l', 0x00000000, 0xc138b2b0},
2208 {'@', 0x0000002d, 0x00003198},/*        -        x-advance: 49.593750 */
2209 {'M', 0x40d6c3dd, 0xc22c9e11},
2210 {'l', 0x4210b2af, 0x00000000},
2211 {'l', 0x00000000, 0x41301b7c},
2212 {'l', 0xc210b2af, 0x00000000},
2213 {'l', 0xb5c00000, 0xc1301b7c},
2214 {'[', 0x0047002d, 0x00000508},
2215 {'[', 0x004a002d, 0x000007a6},
2216 {'[', 0x004f002d, 0x000003d3},
2217 {'[', 0x0051002d, 0x00000508},
2218 {'[', 0x006f002d, 0x0000028c},
2219 {'@', 0x0000002e, 0x00002bb0},/*        .        x-advance: 43.687500 */
2220 {'M', 0x416b2af4, 0xc1886037},
2221 {'l', 0x416293c2, 0x00000000},
2222 {'l', 0x00000000, 0x41886037},
2223 {'l', 0xc16293c2, 0x00000000},
2224 {'l', 0x00000000, 0xc1886037},
2225 {'@', 0x0000002f, 0x00002e4f},/*        /        x-advance: 46.308594 */
2226 {'M', 0x420b98e9, 0xc2c86716},
2227 {'l', 0x41368ce4, 0x00000000},
2228 {'l', 0xc20b98e9, 0x42e1e7f2},
2229 {'l', 0xc1368ce4, 0xb5800000},
2230 {'l', 0x420b98e9, 0xc2e1e7f2},
2231 {'@', 0x00000030, 0x00005773},/*        0        x-advance: 87.449219 */
2232 {'M', 0x422ec3dd, 0xc2b68ce3},
2233 {'q', 0xc1278448, 0x00000000},
2234 {0, 0xc17c5956, 0x41255e80},
2235 {'q', 0xc0a7844c, 0x41244b98},
2236 {0, 0xc0a7844c, 0x41f7844c},
2237 {'q', 0x00000000, 0x41a4d50c},
2238 {0, 0x40a7844c, 0x41f7844c},
2239 {'q', 0x40a9aa1c, 0x41244b98},
2240 {0, 0x417c5956, 0x41244b98},
2241 {'q', 0x41289734, 0x00000000},
2242 {0, 0x417c5958, 0xc1244b98},
2243 {'q', 0x40a9aa18, 0xc1255e80},
2244 {0, 0x40a9aa18, 0xc1f7844c},
2245 {'q', 0x00000000, 0xc1a55e80},
2246 {0, 0xc0a9aa18, 0xc1f7844c},
2247 {'9', 0xffaeffd7, 0xffaeff82},
2248 {'m', 0x00000000, 0xc12bcfe0},
2249 {'q', 0x4186c3de, 0x00000000},
2250 {0, 0x41cda33a, 0x4155b0f8},
2251 {'q', 0x410ed198, 0x41549e10},
2252 {0, 0x410ed198, 0x421aa180},
2253 {'q', 0x00000000, 0x41ca6a86},
2254 {0, 0xc10ed198, 0x421aa181},
2255 {'q', 0xc10dbeb8, 0x41549e11},
2256 {0, 0xc1cda33a, 0x41549e11},
2257 {'q', 0xc186c3dd, 0xb4c00000},
2258 {0, 0xc1ce2cab, 0xc1549e11},
2259 {'q', 0xc10dbeb5, 0xc155b0f8},
2260 {0, 0xc10dbeb5, 0xc21aa181},
2261 {'q', 0x00000000, 0xc1caf3f8},
2262 {0, 0x410dbeb5, 0xc21aa180},
2263 {'q', 0x410ed19c, 0xc155b0f8},
2264 {0, 0x41ce2cab, 0xc155b0f8},
2265 {'@', 0x00000031, 0x00005773},/*        1        x-advance: 87.449219 */
2266 {'M', 0x41886037, 0xc1368ce3},
2267 {'l', 0x41b12e63, 0x00000000},
2268 {'l', 0x00000000, 0xc298e2cb},
2269 {'l', 0xc1c0c06e, 0x409aa180},
2270 {'l', 0x35800000, 0xc1459578},
2271 {'l', 0x41bfad88, 0xc09aa180},
2272 {'l', 0x4158e9a8, 0x00000000},
2273 {'l', 0x00000000, 0x42b1957a},
2274 {'l', 0x41b12e64, 0xb6400000},
2275 {'l', 0x00000000, 0x41368ce3},
2276 {'l', 0xc266df5a, 0x00000000},
2277 {'l', 0xb6000000, 0xc1368ce3},
2278 {'@', 0x00000032, 0x00005773},/*        2        x-advance: 87.449219 */
2279 {'M', 0x41d301b8, 0xc1368ce3},
2280 {'l', 0x423d4302, 0x00000000},
2281 {'4', 0x005b0000, 0x0000fe04},
2282 {'l', 0xb6000000, 0xc1368ce3},
2283 {'q', 0x40f6fad8, 0xc0ff920a},
2284 {0, 0x41a80dbe, 0xc1ab4670},
2285 {'q', 0x4155b0f6, 0xc157d6c4},
2286 {0, 0x41863a6b, 0xc18b0f76},
2287 {'8', 0x9e48c634, 0xb114d814},
2288 {'q', 0x00000000, 0xc0ff9210},
2289 {0, 0xc0b46718, 0xc1505278},
2290 {'q', 0xc0b24148, 0xc0a112f0},
2291 {0, 0xc1690528, 0xc0a112f0},
2292 {'q', 0xc0cc06e0, 0x00000000},
2293 {0, 0xc157d6c2, 0x400dbec0},
2294 {'9', 0x0011ffc8, 0x0035ff88},
2295 {'l', 0x00000000, 0xc15b0f78},
2296 {'q', 0x410301b8, 0xc0527840},
2297 {0, 0x4174d50c, 0xc09eed20},
2298 {'q', 0x40e3a6a8, 0xbfd6c3c0},
2299 {0, 0x41505278, 0xbfd6c3c0},
2300 {'q', 0x417920a4, 0x00000000},
2301 {0, 0x41c6a860, 0x40f920a0},
2302 {'q', 0x41143018, 0x40f920b0},
2303 {0, 0x41143018, 0x41a67168},
2304 {'8', 0x5dee3100, 0x68bd2cee},
2305 {'q', 0xbfd6c3e0, 0x3ff920c0},
2306 {0, 0xc12abd00, 0x41346718},
2307 {'q', 0xc10fe480, 0x4114301c},
2308 {0, 0xc1caf3f8, 0x41cfc904},
2309 {'@', 0x00000033, 0x00005773},/*        3        x-advance: 87.449219 */
2310 {'M', 0x425f1656, 0xc2581b7d},
2311 {'q', 0x411bb468, 0x40052780},
2312 {0, 0x4172af40, 0x410a8604},
2313 {'q', 0x40b01b80, 0x40d27840},
2314 {0, 0x40b01b80, 0x4181eed1},
2315 {'q', 0x00000000, 0x416d50c0},
2316 {0, 0xc12338b8, 0x41b79fc8},
2317 {'q', 0xc12338b0, 0x4101eed3},
2318 {0, 0xc1e7f240, 0x4101eed3},
2319 {'8', 0xf79800ce, 0xe292f6cb},
2320 {'l', 0x00000000, 0xc151655e},
2321 {'q', 0x40b46716, 0x40527844},
2322 {0, 0x4145957b, 0x409eed18},
2323 {'q', 0x40d6c3dc, 0x3fd6c3e0},
2324 {0, 0x41606df6, 0x3fd6c3e0},
2325 {'q', 0x414c06dc, 0x00000000},
2326 {0, 0x419b2af2, 0xc0a112e6},
2327 {'q', 0x40d6c3e0, 0xc0a112e6},
2328 {0, 0x40d6c3e0, 0xc16a180d},
2329 {'q', 0x00000000, 0xc10dbeb6},
2330 {0, 0xc0c7bb48, 0xc15d3542},
2331 {'9', 0xffd8ffcf, 0xffd8ff77},
2332 {'4', 0x0000ffa3, 0xffa70000},
2333 {'l', 0x41436fae, 0x00000000},
2334 {'q', 0x41200000, 0x00000000},
2335 {0, 0x4174d50c, 0xc07d6c40},
2336 {'8', 0xa42ae02a, 0xa2d4c300},
2337 {'q', 0xc0adf5b0, 0xc0852790},
2338 {0, 0xc17a338c, 0xc0852790},
2339 {'q', 0xc0b24148, 0x00000000},
2340 {0, 0xc13f2414, 0x3f9aa180},
2341 {'9', 0x0009ffcd, 0x001eff90},
2342 {'l', 0x00000000, 0xc14149e0},
2343 {'q', 0x40f6fad8, 0xc0097320},
2344 {0, 0x4166df5a, 0xc04e2cc0},
2345 {'q', 0x40d8e9ac, 0xbf897300},
2346 {0, 0x414c06de, 0xbf897300},
2347 {'q', 0x4176fad8, 0x00000000},
2348 {0, 0x41c36fae, 0x40e180e0},
2349 {'q', 0x410fe480, 0x40df5b10},
2350 {0, 0x410fe480, 0x419768cc},
2351 {'q', 0x00000000, 0x41052788},
2352 {0, 0xc0987bb0, 0x416180dc},
2353 {'q', 0xc0987bb0, 0x40b68ce8},
2354 {0, 0xc158e9a8, 0x40fd6c40},
2355 {'@', 0x00000034, 0x00005773},/*        4        x-advance: 87.449219 */
2356 {'M', 0x424fc905, 0xc2b0c74d},
2357 {'4', 0x01abfeef, 0x00000111},
2358 {'6', 0xfe550000, 0xffa2ffe4},
2359 {'l', 0x41886038, 0x00000000},
2360 {'l', 0x00000000, 0x42829aa2},
2361 {'l', 0x4164b990, 0xb6800000},
2362 {'l', 0x00000000, 0x41346714},
2363 {'l', 0xc164b990, 0x00000000},
2364 {'l', 0x00000000, 0x41bcfe48},
2365 {'l', 0xc157d6c4, 0x00000000},
2366 {'l', 0x00000000, 0xc1bcfe48},
2367 {'l', 0xc234f089, 0x00000000},
2368 {'l', 0xb5c00000, 0xc151655c},
2369 {'l', 0x4226b61e, 0xc27df5b1},
2370 {'@', 0x00000035, 0x00005773},/*        5        x-advance: 87.449219 */
2371 {'M', 0x416d50c0, 0xc2c86716},
2372 {'l', 0x4254e2ca, 0x00000000},
2373 {'4', 0x005b0000, 0x0000feba},
2374 {'l', 0x00000000, 0x41c48294},
2375 {'8', 0xf52ff817, 0xfc2ffc17},
2376 {'q', 0x41863a6a, 0x00000000},
2377 {0, 0x41d49e10, 0x41131d34},
2378 {'q', 0x411cc750, 0x41131d34},
2379 {0, 0x411cc750, 0x41c731d2},
2380 {'q', 0x00000000, 0x4181655f},
2381 {0, 0xc12112e8, 0x41c957a0},
2382 {'q', 0xc12112e4, 0x410ed19d},
2383 {0, 0xc1e31d34, 0x410ed19d},
2384 {'8', 0xf89900ce, 0xe795f8cc},
2385 {'l', 0x00000000, 0xc159fc90},
2386 {'8', 0x27631a30, 0x0c6c0c33},
2387 {'q', 0x4139c598, 0x00000000},
2388 {0, 0x41931d36, 0xc0c36fae},
2389 {'q', 0x40d8e9a8, 0xc0c36fae},
2390 {0, 0x40d8e9a8, 0xc1849e12},
2391 {'q', 0x00000000, 0xc1278448},
2392 {0, 0xc0d8e9a8, 0xc1849e10},
2393 {'q', 0xc0d8e9a8, 0xc0c36fb0},
2394 {0, 0xc1931d36, 0xc0c36fb0},
2395 {'8', 0x09aa00d5, 0x1ea809d6},
2396 {'l', 0x00000000, 0xc249579f},
2397 {'@', 0x00000036, 0x00005773},/*        6        x-advance: 87.449219 */
2398 {'M', 0x423579fc, 0xc25e036f},
2399 {'q', 0xc1120a4c, 0x00000000},
2400 {0, 0xc167f240, 0x40c7bb40},
2401 {'q', 0xc0a9aa18, 0x40c7bb48},
2402 {0, 0xc0a9aa18, 0x4188e9aa},
2403 {'q', 0x00000000, 0x412ce2cc},
2404 {0, 0x40a9aa18, 0x4188e9aa},
2405 {'q', 0x40abcfe8, 0x40c7bb48},
2406 {0, 0x4167f240, 0x40c7bb48},
2407 {'q', 0x41120a50, 0x00000000},
2408 {0, 0x4166df5c, 0xc0c7bb46},
2409 {'q', 0x40abcfe8, 0xc0c9e112},
2410 {0, 0x40abcfe8, 0xc188e9aa},
2411 {'q', 0x00000000, 0xc12df5b0},
2412 {0, 0xc0abcfe8, 0xc188e9aa},
2413 {'9', 0xffcfffd6, 0xffcfff8d},
2414 {'m', 0x41d74d50, 0xc229eed1},
2415 {'l', 0x00000000, 0x41459578},
2416 {'8', 0xe3aeedd8, 0xf6aef6d7},
2417 {'q', 0xc156c3e0, 0x00000000},
2418 {0, 0xc1a44b99, 0x4110f768},
2419 {'q', 0xc0e180dc, 0x4110f768},
2420 {0, 0xc100dbec, 0x41db0f78},
2421 {'8', 0xb94fd21f, 0xe769e72f},
2422 {'q', 0x41719c58, 0x00000000},
2423 {0, 0x41be9aa2, 0x41131d34},
2424 {'q', 0x410cabd0, 0x41120a50},
2425 {0, 0x410cabd0, 0x41c731d2},
2426 {'q', 0x00000000, 0x4176fada},
2427 {0, 0xc1120a50, 0x41c61eee},
2428 {'q', 0xc1120a50, 0x41154301},
2429 {0, 0xc1c25cc8, 0x41154301},
2430 {'q', 0xc18b0f76, 0xb4c00000},
2431 {0, 0xc1d49e10, 0xc1549e11},
2432 {'q', 0xc1131d36, 0xc155b0f8},
2433 {0, 0xc1131d36, 0xc21aa181},
2434 {'q', 0x00000000, 0xc1be112c},
2435 {0, 0x41346716, 0xc21768ce},
2436 {'q', 0x41346718, 0xc16293c0},
2437 {0, 0x41f225cc, 0xc16293c0},
2438 {'8', 0x08520028, 0x18560829},
2439 {'@', 0x00000037, 0x00005773},/*        7        x-advance: 87.449219 */
2440 {'M', 0x41346716, 0xc2c86716},
2441 {'l', 0x4280dbeb, 0x00000000},
2442 {'l', 0x00000000, 0x40b8b2b0},
2443 {'l', 0xc21180dc, 0x42bcdbeb},
2444 {'l', 0xc16293c2, 0x00000000},
2445 {'l', 0x4208e9aa, 0xc2b1957a},
2446 {'l', 0xc2407bb4, 0x00000000},
2447 {'l', 0xb6000000, 0xc1368ce0},
2448 {'@', 0x00000038, 0x00005773},/*        8        x-advance: 87.449219 */
2449 {'M', 0x422ec3dd, 0xc23e55e8},
2450 {'q', 0xc11aa180, 0x00000000},
2451 {0, 0xc173c224, 0x40a55e80},
2452 {'q', 0xc0b01b7c, 0x40a55e80},
2453 {0, 0xc0b01b7c, 0x4163a6a8},
2454 {'q', 0x00000000, 0x4110f76a},
2455 {0, 0x40b01b7c, 0x4163a6a9},
2456 {'q', 0x40b24148, 0x40a55e7e},
2457 {0, 0x4173c224, 0x40a55e7e},
2458 {'q', 0x411aa184, 0x00000000},
2459 {0, 0x4173c228, 0xc0a55e7e},
2460 {'q', 0x40b24148, 0xc0a7844a},
2461 {0, 0x40b24148, 0xc163a6a9},
2462 {'q', 0x00000000, 0xc110f768},
2463 {0, 0xc0b24148, 0xc163a6a8},
2464 {'9', 0xffd7ffd4, 0xffd7ff87},
2465 {'m', 0xc158e9a8, 0xc0b8b2b0},
2466 {'q', 0xc10b98ea, 0xc0097310},
2467 {0, 0xc159fc90, 0xc101eed0},
2468 {'q', 0xc09aa182, 0xc0bf2410},
2469 {0, 0xc09aa182, 0xc1690528},
2470 {'q', 0x00000000, 0xc14036f8},
2471 {0, 0x41086037, 0xc197f240},
2472 {'q', 0x4109731e, 0xc0df5b10},
2473 {0, 0x41bbeb61, 0xc0df5b10},
2474 {'q', 0x416f7690, 0x00000000},
2475 {0, 0x41bbeb62, 0x40df5b10},
2476 {'q', 0x41086038, 0x40df5b10},
2477 {0, 0x41086038, 0x4197f240},
2478 {'q', 0x00000000, 0x41097320},
2479 {0, 0xc09cc750, 0x41690528},
2480 {'q', 0xc09aa180, 0x40bf2418},
2481 {0, 0xc157d6c4, 0x4101eed0},
2482 {'q', 0x411cc74c, 0x40120a50},
2483 {0, 0x4173c224, 0x410ed1a0},
2484 {'q', 0x40b01b80, 0x40d49e10},
2485 {0, 0x40b01b80, 0x4181eed0},
2486 {'q', 0x00000000, 0x41690528},
2487 {0, 0xc10ed198, 0x41b2cabd},
2488 {'q', 0xc10dbeb8, 0x40f920a5},
2489 {0, 0xc1cb7d6e, 0x40f920a5},
2490 {'q', 0xc1849e10, 0x34000000},
2491 {0, 0xc1cc06de, 0xc0f920a4},
2492 {'q', 0xc10dbeb7, 0xc0f920a5},
2493 {0, 0xc10dbeb7, 0xc1b2cabd},
2494 {'q', 0x00000000, 0xc1198e98},
2495 {0, 0x40b01b7e, 0xc181eed0},
2496 {'9', 0xffcb002c, 0xffb9007a},
2497 {'m', 0xc09eed1c, 0xc1ab4670},
2498 {'8', 0x61263e00, 0x226d2227},
2499 {'8', 0xde6c0045, 0x9f27de27},
2500 {'8', 0x9fd9c200, 0xde94ded9},
2501 {'8', 0x229300ba, 0x61da22da},
2502 {'@', 0x00000039, 0x00005773},/*        9        x-advance: 87.449219 */
2503 {'M', 0x41719c59, 0xc0052784},
2504 {'l', 0x00000000, 0xc145957a},
2505 {'8', 0x1d521328, 0x0a520a29},
2506 {'q', 0x4156c3dc, 0x00000000},
2507 {0, 0x41a3c226, 0xc10fe482},
2508 {'q', 0x40e3a6a8, 0xc110f768},
2509 {0, 0x4101eed4, 0xc1db98ea},
2510 {'8', 0x46b22ee1, 0x189718d1},
2511 {'q', 0xc1708974, 0x00000000},
2512 {0, 0xc1be9aa2, 0xc110f768},
2513 {'q', 0xc10b98e9, 0xc1120a50},
2514 {0, 0xc10b98e9, 0xc1c731d4},
2515 {'q', 0x00000000, 0xc176fad8},
2516 {0, 0x41120a4f, 0xc1c61eec},
2517 {'q', 0x41120a4e, 0xc1154300},
2518 {0, 0x41c25cc7, 0xc1154300},
2519 {'q', 0x418b0f76, 0x00000000},
2520 {0, 0x41d4149c, 0x4155b0f8},
2521 {'q', 0x41131d38, 0x41549e10},
2522 {0, 0x41131d38, 0x421aa180},
2523 {'q', 0x00000000, 0x41bd87bc},
2524 {0, 0xc1346718, 0x421768ce},
2525 {'q', 0xc133542c, 0x416180dd},
2526 {0, 0xc1f19c58, 0x416180dd},
2527 {'8', 0xf8ae00d8, 0xe8aaf8d7},
2528 {'m', 0x41d7d6c4, 0xc229eed2},
2529 {'q', 0x41120a50, 0x00000000},
2530 {0, 0x4166df5c, 0xc0c7bb40},
2531 {'q', 0x40abcfe0, 0xc0c7bb48},
2532 {0, 0x40abcfe0, 0xc188e9ac},
2533 {'q', 0x00000000, 0xc12ce2c8},
2534 {0, 0xc0abcfe0, 0xc1886034},
2535 {'q', 0xc0a9aa18, 0xc0c9e120},
2536 {0, 0xc166df5c, 0xc0c9e120},
2537 {'q', 0xc1120a50, 0x00000000},
2538 {0, 0xc167f240, 0x40c9e120},
2539 {'q', 0xc0a9aa18, 0x40c7bb40},
2540 {0, 0xc0a9aa18, 0x41886034},
2541 {'q', 0x00000000, 0x412df5b4},
2542 {0, 0x40a9aa18, 0x4188e9ac},
2543 {'q', 0x40abcfe0, 0x40c7bb40},
2544 {0, 0x4167f240, 0x40c7bb40},
2545 {'@', 0x0000003a, 0x00002e4f},/*        :        x-advance: 46.308594 */
2546 {'M', 0x4180dbeb, 0xc1886037},
2547 {'l', 0x416293c2, 0x00000000},
2548 {'4', 0x00880000, 0x0000ff8f},
2549 {'6', 0xff780000, 0xfe500000},
2550 {'l', 0x416293c2, 0x00000000},
2551 {'l', 0x00000000, 0x41886036},
2552 {'l', 0xc16293c2, 0x00000000},
2553 {'l', 0x00000000, 0xc1886036},
2554 {'@', 0x0000003b, 0x00002e4f},/*        ;        x-advance: 46.308594 */
2555 {'M', 0x4180dbeb, 0xc28e25cc},
2556 {'l', 0x416293c2, 0x00000000},
2557 {'4', 0x00880000, 0x0000ff8f},
2558 {'6', 0xff780000, 0x01b00000},
2559 {'l', 0x416293c2, 0x36000000},
2560 {'l', 0x00000000, 0x4138b2b0},
2561 {'l', 0xc1301b7c, 0x41abcfe4},
2562 {'l', 0xc10a8604, 0x00000000},
2563 {'l', 0x40b01b7c, 0xc1abcfe4},
2564 {'l', 0x00000000, 0xc138b2b0},
2565 {'@', 0x0000003c, 0x0000732a},/*        <        x-advance: 115.164062 */
2566 {'M', 0x42c93543, 0xc2874d51},
2567 {'l', 0xc28a8604, 0x41c50c08},
2568 {'l', 0x428a8604, 0x41c3f921},
2569 {'l', 0x00000000, 0x41436fac},
2570 {'l', 0xc2ac149e, 0xc1f9aa17},
2571 {'l', 0xb5800000, 0xc132414c},
2572 {'l', 0x42ac149e, 0xc1f9aa16},
2573 {'l', 0x00000000, 0x41436fa8},
2574 {'@', 0x0000003d, 0x0000732a},/*        =        x-advance: 115.164062 */
2575 {'M', 0x41690527, 0xc279aa18},
2576 {'l', 0x42ac149e, 0x00000000},
2577 {'4', 0x005a0000, 0x0000fd50},
2578 {'6', 0xffa60000, 0x00db0000},
2579 {'l', 0x42ac149e, 0x00000000},
2580 {'l', 0x00000000, 0x41368ce4},
2581 {'l', 0xc2ac149e, 0x00000000},
2582 {'l', 0xb5800000, 0xc1368ce4},
2583 {'@', 0x0000003e, 0x0000732a},/*        >        x-advance: 115.164062 */
2584 {'M', 0x41690527, 0xc2874d51},
2585 {'l', 0x00000000, 0xc1436fa8},
2586 {'l', 0x42ac149e, 0x41f9aa16},
2587 {'l', 0x00000000, 0x4132414c},
2588 {'l', 0xc2ac149e, 0x41f9aa17},
2589 {'l', 0xb5800000, 0xc1436fac},
2590 {'l', 0x428a414a, 0xc1c3f921},
2591 {'l', 0xc28a414a, 0xc1c50c08},
2592 {'@', 0x0000003f, 0x000048f3},/*        ?        x-advance: 72.949219 */
2593 {'M', 0x41d1eed1, 0xc1886037},
2594 {'l', 0x4159fc92, 0x00000000},
2595 {'4', 0x00880000, 0x0000ff94},
2596 {'6', 0xff780000, 0xffb20069},
2597 {'4', 0x0000ff9a, 0xffae0000},
2598 {'8', 0xa70fca00, 0xaf3fde0f},
2599 {'l', 0x40c149e0, 0xc0bf2418},
2600 {'8', 0xcb2ce41e, 0xcd0de70d},
2601 {'8', 0xb3ddd100, 0xe3a4e3de},
2602 {'8', 0x12a600d6, 0x369d12d1},
2603 {'l', 0x00000000, 0xc149e110},
2604 {'8', 0xd366e232, 0xf16bf134},
2605 {'q', 0x41459578, 0x00000000},
2606 {0, 0x419e63a6, 0x40d05270},
2607 {'q', 0x40f08970, 0x40d05280},
2608 {0, 0x40f08970, 0x41897320},
2609 {'8', 0x4ded2800, 0x52bd24ed},
2610 {'l', 0xc0bcfe48, 0x40b8b2b0},
2611 {'8', 0x27dd19e7, 0x1bf20df6},
2612 {'8', 0x1bfc0bfd, 0x2cff10ff},
2613 {'l', 0x00000000, 0x410414a0},
2614 {'@', 0x00000040, 0x00008973},/*        @        x-advance: 137.449219 */
2615 {'M', 0x424c9052, 0xc210293c},
2616 {'q', 0x00000000, 0x41198e9a},
2617 {0, 0x40987bb8, 0x41719c5a},
2618 {'8', 0x2b682b26, 0xd4670042},
2619 {'q', 0x40987bc0, 0xc0b01b80},
2620 {0, 0x40987bc0, 0xc1708974},
2621 {'q', 0x00000000, 0xc11655e8},
2622 {0, 0xc09aa180, 0xc16e63a4},
2623 {'8', 0xd498d4da, 0x2c9900c0},
2624 {'9', 0x002cffda, 0x0077ffda},
2625 {'m', 0x42124f08, 0x41a08973},
2626 {'8', 0x3db629e0, 0x13a013d7},
2627 {'q', 0xc138b2b0, 0x00000000},
2628 {0, 0xc19655e8, 0xc1052784},
2629 {'q', 0xc0e5cc78, 0xc1063a6a},
2630 {0, 0xc0e5cc78, 0xc1ae7f24},
2631 {'q', 0x00000000, 0xc156c3dc},
2632 {0, 0x40e7f240, 0xc1ae7f24},
2633 {'q', 0x40e7f240, 0xc1063a68},
2634 {0, 0x4195cc76, 0xc1063a68},
2635 {'8', 0x14610037, 0x3c491329},
2636 {'4', 0xffba0000, 0x0000004c},
2637 {'l', 0x00000000, 0x4245957a},
2638 {'q', 0x411cc748, 0xbfbcfe40},
2639 {0, 0x4174d508, 0xc10ed19a},
2640 {'q', 0x40b24150, 0xc0f08974},
2641 {0, 0x40b24150, 0xc19b2af3},
2642 {'8', 0x95efc700, 0xa3cdcef0},
2643 {'q', 0xc0df5b10, 0xc10cabd0},
2644 {0, 0xc1886038, 0xc156c3e0},
2645 {'q', 0xc1200000, 0xc09655e0},
2646 {0, 0xc1ae7f24, 0xc09655e0},
2647 {'q', 0xc104149c, 0x00000000},
2648 {0, 0xc17d6c3c, 0x400dbea0},
2649 {'q', 0xc0f2af40, 0x40097320},
2650 {0, 0xc1606df4, 0x40ce2cb0},
2651 {'q', 0xc1289734, 0x40db0f80},
2652 {0, 0xc184149f, 0x418fe482},
2653 {'q', 0xc0bcfe48, 0x41312e64},
2654 {0, 0xc0bcfe48, 0x41c036fc},
2655 {'q', 0x00000000, 0x412abcfc},
2656 {0, 0x4074d510, 0x419fffff},
2657 {'q', 0x407920a0, 0x41154302},
2658 {0, 0x4133542e, 0x41838b2b},
2659 {'q', 0x40e180e0, 0x40df5b0f},
2660 {0, 0x41827846, 0x412abcfe},
2661 {'q', 0x41143018, 0x4067f240},
2662 {0, 0x419e63a6, 0x4067f240},
2663 {'q', 0x410a8600, 0x00000000},
2664 {0, 0x4187d6c4, 0xc038b2ac},
2665 {'9', 0xffe90043, 0xffbd007a},
2666 {'l', 0x40c149e0, 0x40ee63a6},
2667 {'q', 0xc1063a68, 0x40d0527a},
2668 {0, 0xc19293c0, 0x41200001},
2669 {'q', 0xc11dda38, 0x405b0f70},
2670 {0, 0xc1a08974, 0x405b0f70},
2671 {'q', 0xc146a860, 0x00000000},
2672 {0, 0xc1bb61ee, 0xc08b98e8},
2673 {'q', 0xc1301b80, 0xc08dbeb6},
2674 {0, 0xc19cc74e, 0xc14d19c6},
2675 {'q', 0xc109731e, 0xc1063a6a},
2676 {0, 0xc151655e, 0xc19b2af4},
2677 {'q', 0xc08fe482, 0xc1312e62},
2678 {0, 0xc08fe482, 0xc1be112d},
2679 {'q', 0x00000000, 0xc1436fb0},
2680 {0, 0x40920a4e, 0xc1ba4f08},
2681 {'q', 0x40920a50, 0xc1312e64},
2682 {0, 0x41505278, 0xc19bb466},
2683 {'q', 0x410a8604, 0xc1086038},
2684 {0, 0x41a00000, 0xc1505278},
2685 {'q', 0x413579fc, 0xc0920a50},
2686 {0, 0x41c036fc, 0xc0920a50},
2687 {'q', 0x4163a6a8, 0x00000000},
2688 {0, 0x41d301b4, 0x40bad870},
2689 {'q', 0x41436fb0, 0x40bad880},
2690 {0, 0x41a3c228, 0x41849e14},
2691 {'q', 0x40a112e0, 0x40d27840},
2692 {0, 0x40f4d510, 0x4164b98c},
2693 {'q', 0x402bcfe0, 0x40f6fad8},
2694 {0, 0x402bcfe0, 0x417f9208},
2695 {'q', 0x00000000, 0x418d3543},
2696 {0, 0xc12abd00, 0x41ded19d},
2697 {'q', 0xc12abd00, 0x412338b2},
2698 {0, 0xc1ebb468, 0x4129aa17},
2699 {'l', 0x00000000, 0xc1255e7f},
2700 {'@', 0x00000041, 0x00005e06},/*        A        x-advance: 94.023438 */
2701 {'M', 0x423beb62, 0xc2adb0f7},
2702 {'4', 0x018eff6d, 0x00000126},
2703 {'6', 0xfe72ff6d, 0xff96ffc3},
2704 {'l', 0x4175e7f4, 0x00000000},
2705 {'l', 0x4218c06d, 0x42c86716},
2706 {'l', 0xc16180d8, 0x00000000},
2707 {'l', 0xc1120a50, 0xc1cda338},
2708 {'l', 0xc234abd0, 0x00000000},
2709 {'l', 0xc1120a4e, 0x41cda338},
2710 {'l', 0xc164b98e, 0x00000000},
2711 {'l', 0x42190527, 0xc2c86716},
2712 {'[', 0x00410041, 0x000003d3},
2713 {'@', 0x00000042, 0x00005e4b},/*        B        x-advance: 94.292969 */
2714 {'M', 0x41d86037, 0xc23f68ce},
2715 {'4', 0x01250000, 0x000000ad},
2716 {'q', 0x412f0894, 0x00000000},
2717 {0, 0x4181655c, 0xc08fe482},
2718 {'8', 0x912adc2a, 0x92d6b500},
2719 {'9', 0xffddffd7, 0xffddff7f},
2720 {'6', 0x0000ff53, 0xfeb70000},
2721 {'4', 0x00f10000, 0x000000a0},
2722 {'q', 0x411eed18, 0x00000000},
2723 {0, 0x416c3dd8, 0xc06c3de0},
2724 {'8', 0xa527e227, 0xa6d9c400},
2725 {'9', 0xffe2ffda, 0xffe2ff8a},
2726 {'6', 0x0000ff60, 0xffa7ff94},
2727 {'l', 0x420a8603, 0x00000000},
2728 {'q', 0x41780dc0, 0x00000000},
2729 {0, 0x41bf2414, 0x40ce2cb0},
2730 {'q', 0x41063a68, 0x40ce2ca0},
2731 {0, 0x41063a68, 0x419293c0},
2732 {'q', 0x00000000, 0x41131d38},
2733 {0, 0xc0897310, 0x416a1810},
2734 {'q', 0xc0897320, 0x40adf5b0},
2735 {0, 0xc149e114, 0x40d8e9a8},
2736 {'q', 0x411ffffc, 0x40097320},
2737 {0, 0x41780dbc, 0x410fe480},
2738 {'q', 0x40b24150, 0x40d8e9b0},
2739 {0, 0x40b24150, 0x4187d6c5},
2740 {'q', 0x00000000, 0x4156c3dd},
2741 {0, 0xc1120a50, 0x41a5e7f2},
2742 {'9', 0x003affb7, 0x003aff31},
2743 {'l', 0xc20fe482, 0x00000000},
2744 {'l', 0x00000000, 0xc2c86716},
2745 {'@', 0x00000043, 0x00005ff9},/*        C        x-advance: 95.972656 */
2746 {'M', 0x42b10c07, 0xc2b8f769},
2747 {'l', 0x00000000, 0x4164b990},
2748 {'q', 0xc0db0f80, 0xc0cc06e0},
2749 {0, 0xc16a1810, 0xc1187bb0},
2750 {'q', 0xc0f6fae0, 0xc049e120},
2751 {0, 0xc1838b2c, 0xc049e120},
2752 {'q', 0xc189731c, 0x00000000},
2753 {0, 0xc1d27843, 0x41289730},
2754 {'q', 0xc1120a50, 0x41278450},
2755 {0, 0xc1120a50, 0x41f2af40},
2756 {'q', 0x00000000, 0x419e63a7},
2757 {0, 0x41120a50, 0x41f2af40},
2758 {'q', 0x41120a4e, 0x4127844b},
2759 {0, 0x41d27843, 0x4127844b},
2760 {'q', 0x410b98e8, 0x00000000},
2761 {0, 0x41838b2c, 0xc049e114},
2762 {'9', 0xffe7003e, 0xffb40075},
2763 {'l', 0x00000000, 0x416293c2},
2764 {'q', 0xc0e3a6b0, 0x409aa180},
2765 {0, 0xc1719c60, 0x40e7f241},
2766 {'q', 0xc0fd6c30, 0x401aa180},
2767 {0, 0xc1863a68, 0x401aa180},
2768 {'q', 0xc1b60370, 0x34000000},
2769 {0, 0xc20f5b10, 0xc15e4828},
2770 {'q', 0xc151655c, 0xc15f5b10},
2771 {0, 0xc151655c, 0xc21836fb},
2772 {'q', 0x00000000, 0xc1c149e0},
2773 {0, 0x4151655e, 0xc21836fa},
2774 {'q', 0x4151655e, 0xc15f5b10},
2775 {0, 0x420f5b10, 0xc15f5b10},
2776 {'q', 0x410fe480, 0x00000000},
2777 {0, 0x41874d50, 0x401aa180},
2778 {'q', 0x40ff9210, 0x401655e0},
2779 {0, 0x416f7690, 0x40e3a6a0},
2780 {'@', 0x00000044, 0x000069d6},/*        D        x-advance: 105.835938 */
2781 {'M', 0x41d86037, 0xc2b21eed},
2782 {'4', 0x026f0000, 0x00000083},
2783 {'q', 0x41a5e7f2, 0x00000000},
2784 {0, 0x41f2af3e, 0xc11655e8},
2785 {'q', 0x411aa180, 0xc11655e8},
2786 {0, 0x411aa180, 0xc1ed50bf},
2787 {'q', 0x00000000, 0xc1a112e8},
2788 {0, 0xc11aa180, 0xc1ebb468},
2789 {'9', 0xffb5ffb4, 0xffb5ff0e},
2790 {'6', 0x0000ff7d, 0xffa7ff94},
2791 {'l', 0x41ded19c, 0x00000000},
2792 {'q', 0x41e90526, 0x00000000},
2793 {0, 0x422b01b7, 0x41425cc8},
2794 {'q', 0x4159fc90, 0x414149e0},
2795 {0, 0x4159fc90, 0x421768ce},
2796 {'q', 0x00000000, 0x41cf3f91},
2797 {0, 0xc15b0f78, 0x421836fa},
2798 {'9', 0x0061ff93, 0x0061feab},
2799 {'l', 0xc1ded19c, 0x00000000},
2800 {'l', 0x00000000, 0xc2c86716},
2801 {'@', 0x00000045, 0x000056d8},/*        E        x-advance: 86.843750 */
2802 {'M', 0x4157d6c4, 0xc2c86716},
2803 {'l', 0x427d6c3d, 0x00000000},
2804 {'l', 0x00000000, 0x41368ce0},
2805 {'l', 0xc24731d2, 0x00000000},
2806 {'l', 0xb6000000, 0x41ed50c2},
2807 {'l', 0x423edf5a, 0x00000000},
2808 {'l', 0x00000000, 0x41368ce0},
2809 {'l', 0xc23edf5a, 0x00000000},
2810 {'l', 0xb6000000, 0x42113c22},
2811 {'l', 0x424c06de, 0x35800000},
2812 {'l', 0x00000000, 0x41368ce3},
2813 {'l', 0xc28120a4, 0x00000000},
2814 {'l', 0xb6800000, 0xc2c86716},
2815 {'@', 0x00000046, 0x00004f0f},/*        F        x-advance: 79.058594 */
2816 {'M', 0x4157d6c4, 0xc2c86716},
2817 {'l', 0x426655e7, 0x00000000},
2818 {'l', 0x00000000, 0x41368ce0},
2819 {'l', 0xc2301b7c, 0x00000000},
2820 {'l', 0xb6000000, 0x41ec3dda},
2821 {'l', 0x421eed18, 0x00000000},
2822 {'l', 0x00000000, 0x41368ce4},
2823 {'l', 0xc21eed18, 0x00000000},
2824 {'l', 0xb6000000, 0x423f68ce},
2825 {'l', 0xc158e9aa, 0x00000000},
2826 {'l', 0x00000000, 0xc2c86716},
2827 {'@', 0x00000047, 0x00006a82},/*        G        x-advance: 106.507812 */
2828 {'M', 0x42a39fc9, 0xc164b98e},
2829 {'l', 0x00000000, 0xc1d74d51},
2830 {'l', 0xc1b12e64, 0x00000000},
2831 {'4', 0xffa70000, 0x0000011c},
2832 {'l', 0x00000000, 0x422c149e},
2833 {'q', 0xc0fb4670, 0x40b24146},
2834 {0, 0xc18a8600, 0x41074d4f},
2835 {'q', 0xc11768d0, 0x40346716},
2836 {0, 0xc1a19c5a, 0x40346716},
2837 {'q', 0xc1bbeb62, 0x34000000},
2838 {0, 0xc2131d36, 0xc15b0f76},
2839 {'q', 0xc1538b28, 0xc15c225c},
2840 {0, 0xc1538b28, 0xc2190528},
2841 {'q', 0x00000000, 0xc1c48294},
2842 {0, 0x41538b2a, 0xc2190526},
2843 {'q', 0x41549e12, 0xc15c2260},
2844 {0, 0x42131d36, 0xc15c2260},
2845 {'q', 0x411cc748, 0x00000000},
2846 {0, 0x4194b98c, 0x401aa180},
2847 {'9', 0x00130046, 0x00380082},
2848 {'l', 0x00000000, 0x4166df60},
2849 {'q', 0xc0f08970, 0xc0cc06e0},
2850 {0, 0xc17f9208, 0xc1198e98},
2851 {'q', 0xc1074d50, 0xc04e2cc0},
2852 {0, 0xc18e482a, 0xc04e2cc0},
2853 {'q', 0xc1931d34, 0x00000000},
2854 {0, 0xc1dd3542, 0x41244b98},
2855 {'q', 0xc1131d36, 0x41244b98},
2856 {0, 0xc1131d36, 0x41f4d50c},
2857 {'q', 0x00000000, 0x41a225cd},
2858 {0, 0x41131d36, 0x41f44b99},
2859 {'q', 0x4114301c, 0x41244b99},
2860 {0, 0x41dd3542, 0x41244b99},
2861 {'8', 0xf7660039, 0xe151f62d},
2862 {'@', 0x00000048, 0x0000675b},/*        H        x-advance: 103.355469 */
2863 {'M', 0x4157d6c4, 0xc2c86716},
2864 {'l', 0x4158e9aa, 0x00000000},
2865 {'l', 0x00000000, 0x42244b99},
2866 {'l', 0x42450c06, 0x00000000},
2867 {'l', 0x00000000, 0xc2244b99},
2868 {'l', 0x4158e9a8, 0x00000000},
2869 {'l', 0x00000000, 0x42c86716},
2870 {'l', 0xc158e9a8, 0x00000000},
2871 {'l', 0x00000000, 0xc23edf5b},
2872 {'l', 0xc2450c06, 0x00000000},
2873 {'l', 0xb6000000, 0x423edf5b},
2874 {'l', 0xc158e9aa, 0x00000000},
2875 {'l', 0x00000000, 0xc2c86716},
2876 {'@', 0x00000049, 0x00002889},/*        I        x-advance: 40.535156 */
2877 {'M', 0x4157d6c4, 0xc2c86716},
2878 {'l', 0x4158e9aa, 0x00000000},
2879 {'l', 0x00000000, 0x42c86716},
2880 {'l', 0xc158e9aa, 0x00000000},
2881 {'l', 0x00000000, 0xc2c86716},
2882 {'@', 0x0000004a, 0x00002889},/*        J        x-advance: 40.535156 */
2883 {'M', 0x4157d6c4, 0xc2c86716},
2884 {'4', 0x0000006c, 0x02e90000},
2885 {'q', 0x00000000, 0x4190f769},
2886 {0, 0xc0dd3544, 0x41d27845},
2887 {'9', 0x0041ffca, 0x0041ff50},
2888 {'4', 0x0000ffd7, 0xffa50000},
2889 {'l', 0x40874d50, 0x00000000},
2890 {'q', 0x410fe482, 0x00000000},
2891 {0, 0x414af3f9, 0xc0a112e6},
2892 {'q', 0x406c3ddc, 0xc0a112e5},
2893 {0, 0x406c3ddc, 0xc1906df5},
2894 {'l', 0x00000000, 0xc2ba7165},
2895 {'@', 0x0000004b, 0x00005a22},/*        K        x-advance: 90.132812 */
2896 {'M', 0x4157d6c4, 0xc2c86716},
2897 {'l', 0x4158e9aa, 0x00000000},
2898 {'l', 0x00000000, 0x4229655e},
2899 {'l', 0x4233dda2, 0xc229655e},
2900 {'l', 0x418b98ec, 0x00000000},
2901 {'l', 0xc246ed1a, 0x423ad87b},
2902 {'l', 0x42552784, 0x4255f5b1},
2903 {'l', 0xc18ed19c, 0x00000000},
2904 {'l', 0xc2407bb4, 0xc2410527},
2905 {'l', 0xb6000000, 0x42410527},
2906 {'l', 0xc158e9aa, 0x00000000},
2907 {'l', 0x00000000, 0xc2c86716},
2908 {'@', 0x0000004c, 0x00004c93},/*        L        x-advance: 76.574219 */
2909 {'M', 0x4157d6c4, 0xc2c86716},
2910 {'l', 0x4158e9aa, 0x00000000},
2911 {'l', 0x00000000, 0x42b1957a},
2912 {'l', 0x42432af4, 0xb6400000},
2913 {'l', 0x00000000, 0x41368ce3},
2914 {'l', 0xc279655f, 0x00000000},
2915 {'l', 0x00000000, 0xc2c86716},
2916 {'[', 0x0041004c, 0x00000327},
2917 {'@', 0x0000004d, 0x00007697},/*        M        x-advance: 118.589844 */
2918 {'M', 0x4157d6c4, 0xc2c86716},
2919 {'l', 0x41a19c58, 0x00000000},
2920 {'l', 0x41cc9054, 0x42886036},
2921 {'l', 0x41cda336, 0xc2886036},
2922 {'l', 0x41a19c5c, 0x00000000},
2923 {'l', 0x00000000, 0x42c86716},
2924 {'l', 0xc1538b30, 0x00000000},
2925 {'l', 0x00000000, 0xc2aff920},
2926 {'l', 0xc1ceb61c, 0x4289731c},
2927 {'l', 0xc159fc94, 0x36800000},
2928 {'l', 0xc1ceb61e, 0xc289731c},
2929 {'l', 0x00000000, 0x42aff920},
2930 {'l', 0xc1527844, 0x00000000},
2931 {'l', 0x00000000, 0xc2c86716},
2932 {'@', 0x0000004e, 0x000066d1},/*        N        x-advance: 102.816406 */
2933 {'M', 0x4157d6c4, 0xc2c86716},
2934 {'l', 0x41920a4f, 0x00000000},
2935 {'l', 0x4231b7d6, 0x42a7a6a8},
2936 {'l', 0x00000000, 0xc2a7a6a8},
2937 {'l', 0x41527848, 0x00000000},
2938 {'l', 0x00000000, 0x42c86716},
2939 {'l', 0xc1920a50, 0x00000000},
2940 {'l', 0xc231b7d6, 0xc2a7a6a8},
2941 {'l', 0x00000000, 0x42a7a6a8},
2942 {'l', 0xc1527844, 0x00000000},
2943 {'l', 0x00000000, 0xc2c86716},
2944 {'@', 0x0000004f, 0x00006c30},/*        O        x-advance: 108.187500 */
2945 {'M', 0x4258a4f0, 0xc2b6036f},
2946 {'q', 0xc16c3dd8, 0x00000000},
2947 {0, 0xc1bbeb61, 0x41301b78},
2948 {'q', 0xc10a8604, 0x41301b80},
2949 {0, 0xc10a8604, 0x41f00000},
2950 {'q', 0x00000000, 0x419768cf},
2951 {0, 0x410a8604, 0x41ef768d},
2952 {'q', 0x410b98ea, 0x41301b7d},
2953 {0, 0x41bbeb61, 0x41301b7d},
2954 {'q', 0x416c3dd8, 0x00000000},
2955 {0, 0x41bad87c, 0xc1301b7d},
2956 {'q', 0x410a8600, 0xc1301b7c},
2957 {0, 0x410a8600, 0xc1ef768d},
2958 {'q', 0x00000000, 0xc197f240},
2959 {0, 0xc10a8600, 0xc1f00000},
2960 {'9', 0xffa8ffbc, 0xffa8ff46},
2961 {'m', 0x00000000, 0xc1301b80},
2962 {'q', 0x41a89730, 0x00000000},
2963 {0, 0x4206c3de, 0x416293c0},
2964 {'q', 0x4149e110, 0x416180e0},
2965 {0, 0x4149e110, 0x421768ce},
2966 {'q', 0x00000000, 0x41bd87bc},
2967 {0, 0xc149e110, 0x421768ce},
2968 {'q', 0xc149e118, 0x416180dd},
2969 {0, 0xc206c3de, 0x416180dd},
2970 {'q', 0xc1a920a4, 0xb4c00000},
2971 {0, 0xc2074d50, 0xc16180dc},
2972 {'q', 0xc149e114, 0xc16180db},
2973 {0, 0xc149e114, 0xc21768ce},
2974 {'q', 0x00000000, 0xc1be112c},
2975 {0, 0x4149e112, 0xc21768ce},
2976 {'q', 0x414af3fa, 0xc16293c0},
2977 {0, 0x42074d50, 0xc16293c0},
2978 {'[', 0x002d004f, 0x000003d3},
2979 {'@', 0x00000050, 0x000052e2},/*        P        x-advance: 82.882812 */
2980 {'M', 0x41d86037, 0xc2b21eed},
2981 {'4', 0x012d0000, 0x00000088},
2982 {'q', 0x411768cc, 0x00000000},
2983 {0, 0x416a180c, 0xc09cc750},
2984 {'8', 0x9129d929, 0x91d7b900},
2985 {'9', 0xffd9ffd7, 0xffd9ff8b},
2986 {'6', 0x0000ff78, 0xffa7ff94},
2987 {'l', 0x41f4d50c, 0x00000000},
2988 {'q', 0x4186c3dc, 0x00000000},
2989 {0, 0x41cb7d6a, 0x40f4d510},
2990 {'q', 0x410a8608, 0x40f2af40},
2991 {0, 0x410a8608, 0x41b24148},
2992 {'q', 0x00000000, 0x416d50c0},
2993 {0, 0xc10a8608, 0x41b35430},
2994 {'9', 0x003cffbc, 0x003cff35},
2995 {'l', 0xc1886037, 0x00000000},
2996 {'l', 0x00000000, 0x422112e6},
2997 {'l', 0xc158e9aa, 0x00000000},
2998 {'l', 0x00000000, 0xc2c86716},
2999 {'@', 0x00000051, 0x00006c30},/*        Q        x-advance: 108.187500 */
3000 {'M', 0x4258a4f0, 0xc2b6036f},
3001 {'q', 0xc16c3dd8, 0x00000000},
3002 {0, 0xc1bbeb61, 0x41301b78},
3003 {'q', 0xc10a8604, 0x41301b80},
3004 {0, 0xc10a8604, 0x41f00000},
3005 {'q', 0x00000000, 0x419768cf},
3006 {0, 0x410a8604, 0x41ef768d},
3007 {'q', 0x410b98ea, 0x41301b7d},
3008 {0, 0x41bbeb61, 0x41301b7d},
3009 {'q', 0x416c3dd8, 0x00000000},
3010 {0, 0x41bad87c, 0xc1301b7d},
3011 {'q', 0x410a8600, 0xc1301b7c},
3012 {0, 0x410a8600, 0xc1ef768d},
3013 {'q', 0x00000000, 0xc197f240},
3014 {0, 0xc10a8600, 0xc1f00000},
3015 {'9', 0xffa8ffbc, 0xffa8ff46},
3016 {'m', 0x4197f240, 0x42b263a6},
3017 {'4', 0x009c008e, 0x0000ff7d},
3018 {'l', 0xc16d50bc, 0xc1805278},
3019 {'8', 0x01e501ef, 0x00ef00f7},
3020 {'q', 0xc1a920a4, 0x00000000},
3021 {0, 0xc2074d50, 0xc16180dc},
3022 {'q', 0xc149e114, 0xc16293c1},
3023 {0, 0xc149e114, 0xc21768ce},
3024 {'q', 0x00000000, 0xc1be112c},
3025 {0, 0x4149e112, 0xc21768ce},
3026 {'q', 0x414af3fa, 0xc16293c0},
3027 {0, 0x42074d50, 0xc16293c0},
3028 {'q', 0x41a89730, 0x00000000},
3029 {0, 0x4206c3de, 0x416293c0},
3030 {'q', 0x4149e110, 0x416180e0},
3031 {0, 0x4149e110, 0x421768ce},
3032 {'q', 0x00000000, 0x418b98ea},
3033 {0, 0xc0e180e0, 0x41eeed1a},
3034 {'q', 0xc0df5b10, 0x4146a860},
3035 {0, 0xc1a225cc, 0x419293c2},
3036 {'[', 0x002d0051, 0x000003d3},
3037 {'@', 0x00000052, 0x00005f80},/*        R        x-advance: 95.500000 */
3038 {'M', 0x427406df, 0xc23beb62},
3039 {'8', 0x32430b22, 0x6a422621},
3040 {'4', 0x00db006e, 0x0000ff8c},
3041 {'l', 0xc14d19c8, 0xc1cda338},
3042 {'8', 0x96b3b0d9, 0xe69be6db},
3043 {'l', 0xc16c3dda, 0x00000000},
3044 {'l', 0x00000000, 0x4229655e},
3045 {'4', 0x0000ff94, 0xfcdf0000},
3046 {'l', 0x41f4d50c, 0x00000000},
3047 {'q', 0x4189731c, 0x00000000},
3048 {0, 0x41cd19c6, 0x40e5cc70},
3049 {'q', 0x41074d50, 0x40e5cc80},
3050 {0, 0x41074d50, 0x41ad6c40},
3051 {'q', 0x00000000, 0x411768cc},
3052 {0, 0xc08dbec0, 0x417b4670},
3053 {'9', 0x0031ffde, 0x0045ff9a},
3054 {'m', 0xc207d6c4, 0xc2285278},
3055 {'4', 0x011c0000, 0x00000088},
3056 {'q', 0x411cc74c, 0x00000000},
3057 {0, 0x416c3dd8, 0xc08fe480},
3058 {'8', 0x9628dc28, 0x97d8ba00},
3059 {'q', 0xc09eed18, 0xc08fe480},
3060 {0, 0xc16c3dd8, 0xc08fe480},
3061 {'l', 0xc1886037, 0x00000000},
3062 {'@', 0x00000053, 0x0000573f},/*        S        x-advance: 87.246094 */
3063 {'M', 0x42931d35, 0xc2c1d354},
3064 {'l', 0x00000000, 0x41538b28},
3065 {'q', 0xc0f6fad0, 0xc06c3dc0},
3066 {0, 0xc1690528, 0xc0b01b70},
3067 {'q', 0xc0db0f70, 0xbfe7f240},
3068 {0, 0xc1538b28, 0xbfe7f240},
3069 {'q', 0xc1312e64, 0x00000000},
3070 {0, 0xc188e9ab, 0x40897310},
3071 {'8', 0x61d122d1, 0x501f3500},
3072 {'9', 0x001a0020, 0x002b0079},
3073 {'l', 0x410301b8, 0x3fd6c3e0},
3074 {'q', 0x4172af40, 0x4038b2b0},
3075 {0, 0x41b2cabc, 0x412338b0},
3076 {'q', 0x40e7f240, 0x40e7f240},
3077 {0, 0x40e7f240, 0x419bb467},
3078 {'q', 0x00000000, 0x41690528},
3079 {0, 0xc11cc750, 0x41b0a4f0},
3080 {'q', 0xc11bb464, 0x40f08975},
3081 {0, 0xc1e4b98c, 0x40f08975},
3082 {'q', 0xc0e3a6a8, 0x34000000},
3083 {0, 0xc172af40, 0xbfce2cab},
3084 {'9', 0xfff4ffc1, 0xffdaff7c},
3085 {'l', 0x00000000, 0xc15f5b0f},
3086 {'q', 0x4104149e, 0x4094301c},
3087 {0, 0x4181655e, 0x40df5b0e},
3088 {'q', 0x40fd6c3c, 0x401655e8},
3089 {0, 0x417920a6, 0x401655e8},
3090 {'q', 0x4139c594, 0x00000000},
3091 {0, 0x418f5b0e, 0xc0920a4e},
3092 {'8', 0x9832dc32, 0xa4dcc500},
3093 {'9', 0xffdfffdd, 0xffcfff8a},
3094 {'l', 0xc10414a0, 0xbfce2cc0},
3095 {'q', 0xc172af3e, 0xc04149e0},
3096 {0, 0xc1af920a, 0xc11768cc},
3097 {'q', 0xc0d8e9a6, 0xc0ce2cb0},
3098 {0, 0xc0d8e9a6, 0xc18f5b0e},
3099 {'q', 0x00000000, 0xc1549e18},
3100 {0, 0x41154301, 0xc1a7844c},
3101 {'q', 0x411655e8, 0xc0f4d510},
3102 {0, 0x41ceb61f, 0xc0f4d510},
3103 {'q', 0x40e180d8, 0x00000000},
3104 {0, 0x4165cc74, 0x3fa338c0},
3105 {'q', 0x40ea1808, 0x3fa338c0},
3106 {0, 0x416f768c, 0x4074d500},
3107 {'[', 0x00410053, 0x0000028c},
3108 {'@', 0x00000054, 0x000053f5},/*        T        x-advance: 83.957031 */
3109 {'M', 0xbece2cac, 0xc2c86716},
3110 {'l', 0x42a987bb, 0x00000000},
3111 {'l', 0x00000000, 0x41368ce0},
3112 {'l', 0xc20e4828, 0x00000000},
3113 {'l', 0x00000000, 0x42b1957a},
3114 {'l', 0xc159fc90, 0x00000000},
3115 {'l', 0x00000000, 0xc2b1957a},
3116 {'l', 0xc20e4829, 0x00000000},
3117 {'l', 0xb5b00000, 0xc1368ce0},
3118 {'@', 0x00000055, 0x0000649a},/*        U        x-advance: 100.601562 */
3119 {'M', 0x413f2414, 0xc2c86716},
3120 {'4', 0x0000006c, 0x01e60000},
3121 {'q', 0x00000000, 0x4180dbeb},
3122 {0, 0x40bad87c, 0x41b9c595},
3123 {'q', 0x40bad87c, 0x40e180da},
3124 {0, 0x419768cd, 0x40e180da},
3125 {'q', 0x41505278, 0x00000000},
3126 {0, 0x4196df5a, 0xc0e180da},
3127 {'9', 0xffc8002e, 0xff47002e},
3128 {'4', 0xfe1a0000, 0x0000006c},
3129 {'l', 0x00000000, 0x427a338b},
3130 {'q', 0x00000000, 0x419cc74d},
3131 {0, 0xc11bb468, 0x41ecc74c},
3132 {'q', 0xc11aa180, 0x41200001},
3133 {0, 0xc1e4b98e, 0x41200001},
3134 {'q', 0xc197f240, 0xb4c00000},
3135 {0, 0xc1e5cc74, 0xc1200000},
3136 {'q', 0xc11aa180, 0xc11fffff},
3137 {0, 0xc11aa180, 0xc1ecc74c},
3138 {'l', 0x00000000, 0xc27a338b},
3139 {'@', 0x00000056, 0x00005e06},/*        V        x-advance: 94.023438 */
3140 {'M', 0x421d50c0, 0x00000000},
3141 {'l', 0xc2190527, 0xc2c86716},
3142 {'l', 0x416293c1, 0x00000000},
3143 {'l', 0x41fdf5b2, 0x42a8b98e},
3144 {'l', 0x41fe7f24, 0xc2a8b98e},
3145 {'l', 0x416180d8, 0x00000000},
3146 {'l', 0xc218c06d, 0x42c86716},
3147 {'l', 0xc175e7f4, 0x00000000},
3148 {'@', 0x00000057, 0x000087e7},/*        W        x-advance: 135.902344 */
3149 {'M', 0x40920a4f, 0xc2c86716},
3150 {'l', 0x415b0f76, 0x00000000},
3151 {'l', 0x41a89731, 0x42a9655e},
3152 {'l', 0x41a80dbe, 0xc2a9655e},
3153 {'l', 0x4173c224, 0x00000000},
3154 {'l', 0x41a89734, 0x42a9655e},
3155 {'l', 0x41a80dbc, 0xc2a9655e},
3156 {'l', 0x415c2260, 0x00000000},
3157 {'l', 0xc1c957a0, 0x42c86716},
3158 {'l', 0xc1886038, 0x00000000},
3159 {'l', 0xc1a920a4, 0xc2adf5b1},
3160 {'l', 0xc1aabcfe, 0x42adf5b1},
3161 {'l', 0xc1886036, 0x00000000},
3162 {'l', 0xc1c8ce2c, 0xc2c86716},
3163 {'@', 0x00000058, 0x00005e29},/*        X        x-advance: 94.160156 */
3164 {'M', 0x410a8603, 0xc2c86716},
3165 {'l', 0x41690527, 0x00000000},
3166 {'l', 0x41c731d3, 0x4214fe48},
3167 {'l', 0x41c844b8, 0xc214fe48},
3168 {'l', 0x41690528, 0x00000000},
3169 {'l', 0xc200dbeb, 0x42407bb4},
3170 {'l', 0x4209731d, 0x42505278},
3171 {'l', 0xc1690528, 0x00000000},
3172 {'l', 0xc1e180da, 0xc22a7844},
3173 {'l', 0xc1e31d35, 0x422a7844},
3174 {'l', 0xc16a180e, 0x00000000},
3175 {'l', 0x420f1656, 0xc255f5b1},
3176 {'l', 0xc1f9aa18, 0xc23ad87b},
3177 {'@', 0x00000059, 0x000053f5},/*        Y        x-advance: 83.957031 */
3178 {'M', 0xbe89731d, 0xc2c86716},
3179 {'l', 0x41690527, 0x00000000},
3180 {'l', 0x41de4829, 0x4224d50c},
3181 {'l', 0x41dcabd0, 0xc224d50c},
3182 {'l', 0x41690528, 0x00000000},
3183 {'l', 0xc20dbeb6, 0x4251eed1},
3184 {'l', 0x00000000, 0x423edf5b},
3185 {'l', 0xc159fc90, 0x00000000},
3186 {'l', 0x00000000, 0xc23edf5b},
3187 {'l', 0xc20dbeb6, 0xc251eed1},
3188 {'@', 0x0000005a, 0x00005e29},/*        Z        x-advance: 94.160156 */
3189 {'M', 0x40f6fad8, 0xc2c86716},
3190 {'l', 0x429d731c, 0x00000000},
3191 {'l', 0x00000000, 0x41255e80},
3192 {'l', 0xc27d6c3c, 0x429ce9aa},
3193 {'l', 0x4281cc74, 0xb6400000},
3194 {'l', 0x00000000, 0x41368ce3},
3195 {'l', 0xc2a39fc8, 0x00000000},
3196 {'l', 0xb6400000, 0xc1255e7f},
3197 {'l', 0x427d6c3d, 0xc29ce9aa},
3198 {'l', 0xc2773f91, 0x00000000},
3199 {'l', 0x00000000, 0xc1368ce0},
3200 {'@', 0x0000005b, 0x0000359f},/*        [        x-advance: 53.621094 */
3201 {'M', 0x413cfe48, 0xc2d0dbeb},
3202 {'l', 0x41e3a6a8, 0x00000000},
3203 {'l', 0x00000000, 0x41198e98},
3204 {'l', 0xc180dbeb, 0x00000000},
3205 {'l', 0x00000000, 0x42ceb61f},
3206 {'l', 0x4180dbeb, 0xb5800000},
3207 {'l', 0x00000000, 0x41198e9b},
3208 {'l', 0xc1e3a6a8, 0x00000000},
3209 {'l', 0x00000000, 0xc2f519c5},
3210 {'@', 0x0000005c, 0x00002e4f},/*       \         x-advance: 46.308594 */
3211 {'M', 0x41368ce3, 0xc2c86716},
3212 {'l', 0x420b98e9, 0x42e1e7f2},
3213 {'l', 0xc1368ce4, 0xb5800000},
3214 {'l', 0xc20b98e9, 0xc2e1e7f2},
3215 {'l', 0x41368ce3, 0x00000000},
3216 {'@', 0x0000005d, 0x0000359f},/*        ]        x-advance: 53.621094 */
3217 {'M', 0x42273f92, 0xc2d0dbeb},
3218 {'l', 0x00000000, 0x42f519c5},
3219 {'l', 0xc1e3a6a8, 0x36000000},
3220 {'l', 0xb5800000, 0xc1198e9b},
3221 {'l', 0x41805278, 0x00000000},
3222 {'l', 0x00000000, 0xc2ceb61f},
3223 {'l', 0xc1805278, 0x00000000},
3224 {'l', 0xb5800000, 0xc1198e98},
3225 {'l', 0x41e3a6a8, 0x00000000},
3226 {'@', 0x0000005e, 0x0000732a},/*        ^        x-advance: 115.164062 */
3227 {'M', 0x42805278, 0xc2c86716},
3228 {'l', 0x4211c596, 0x421587bb},
3229 {'l', 0xc157d6c8, 0x00000000},
3230 {'l', 0xc1ec3dd8, 0xc1d4149e},
3231 {'l', 0xc1ec3ddb, 0x41d4149e},
3232 {'l', 0xc157d6c3, 0x00000000},
3233 {'l', 0x4211c595, 0xc21587bb},
3234 {'l', 0x41527844, 0x00000000},
3235 {'@', 0x0000005f, 0x000044b9},/*        _        x-advance: 68.722656 */
3236 {'M', 0x428c225d, 0x41b68ce3},
3237 {'l', 0x00000000, 0x41198e9a},
3238 {'l', 0xc28ed19d, 0x00000000},
3239 {'l', 0x36600000, 0xc1198e9a},
3240 {'l', 0x428ed19d, 0x00000000},
3241 {'@', 0x00000060, 0x000044b9},/*        `        x-advance: 68.722656 */
3242 {'M', 0x41c50c07, 0xc2dbdda3},
3243 {'l', 0x419768cd, 0x41c8ce2c},
3244 {'l', 0xc1244b98, 0x00000000},
3245 {'l', 0xc1af0896, 0xc1c8ce2c},
3246 {'l', 0x41538b2a, 0x00000000},
3247 {'@', 0x00000061, 0x0000543a},/*        a        x-advance: 84.226562 */
3248 {'M', 0x423c74d5, 0xc2172414},
3249 {'q', 0xc16f768c, 0x00000000},
3250 {0, 0xc1a5e7f2, 0x405b0f70},
3251 {'8', 0x5dd21bd2, 0x53223400},
3252 {'q', 0x408b98e8, 0x4074d50c},
3253 {0, 0x413cfe46, 0x4074d50c},
3254 {'q', 0x41244b9c, 0x00000000},
3255 {0, 0x41838b2c, 0xc0e7f242},
3256 {'9', 0xffc60031, 0xff650031},
3257 {'4', 0xffea0000, 0x0000ff9e},
3258 {'m', 0x41c50c06, 0xc0a338b8},
3259 {'4', 0x01570000, 0x0000ff9e},
3260 {'l', 0x00000000, 0xc1368ce3},
3261 {'q', 0xc0874d50, 0x40db0f77},
3262 {0, 0xc1289734, 0x412225cd},
3263 {'q', 0xc0c9e110, 0x404e2caa},
3264 {0, 0xc176fad8, 0x404e2caa},
3265 {'q', 0xc138b2ae, 0x34000000},
3266 {0, 0xc1931d34, 0xc0ce2cab},
3267 {'q', 0xc0d8e9ac, 0xc0d05278},
3268 {0, 0xc0d8e9ac, 0xc18b0f76},
3269 {'q', 0x00000000, 0xc14af3fc},
3270 {0, 0x41074d50, 0xc1990528},
3271 {'9', 0xffcd0044, 0xffcd00ca},
3272 {'4', 0x0000008a, 0xfff70000},
3273 {'q', 0x00000000, 0xc1086034},
3274 {0, 0xc0b46718, 0xc1527844},
3275 {'q', 0xc0b24148, 0xc09655e0},
3276 {0, 0xc17b4670, 0xc09655e0},
3277 {'8', 0x0c9c00cd, 0x25a30cd0},
3278 {'l', 0x00000000, 0xc1368ce4},
3279 {'8', 0xe169ec36, 0xf663f633},
3280 {'q', 0x41827844, 0x00000000},
3281 {0, 0x41c2e63a, 0x41074d50},
3282 {'q', 0x4100dbec, 0x41074d54},
3283 {0, 0x4100dbec, 0x41cd19c6},
3284 {'@', 0x00000062, 0x0000573f},/*        b        x-advance: 87.246094 */
3285 {'M', 0x4285d354, 0xc216112e},
3286 {'q', 0x00000000, 0xc159fc90},
3287 {0, 0xc0b46718, 0xc1aabcfe},
3288 {'q', 0xc0b24148, 0xc0f920a8},
3289 {0, 0xc175e7f0, 0xc0f920a8},
3290 {'q', 0xc11cc750, 0x00000000},
3291 {0, 0xc176fada, 0x40f920a8},
3292 {'q', 0xc0b24148, 0x40f6fad8},
3293 {0, 0xc0b24148, 0x41aabcfe},
3294 {'q', 0x00000000, 0x4159fc90},
3295 {0, 0x40b24148, 0x41ab4671},
3296 {'q', 0x40b46714, 0x40f6fad8},
3297 {0, 0x4176fada, 0x40f6fad8},
3298 {'q', 0x411cc74c, 0x00000000},
3299 {0, 0x4175e7f0, 0xc0f6fad8},
3300 {'9', 0xffc2002d, 0xff55002d},
3301 {'m', 0xc2280dbe, 0xc1d1eed2},
3302 {'q', 0x407920a0, 0xc0d6c3d8},
3303 {0, 0x411cc74c, 0xc11eed1c},
3304 {'q', 0x40bf2410, 0xc0527840},
3305 {0, 0x4163a6a8, 0xc0527840},
3306 {'q', 0x415b0f74, 0x00000000},
3307 {0, 0x41b1b7d6, 0x412df5b0},
3308 {'q', 0x41097320, 0x412df5b4},
3309 {0, 0x41097320, 0x41e4b990},
3310 {'q', 0x00000000, 0x418dbeb6},
3311 {0, 0xc1097320, 0x41e4b98e},
3312 {'q', 0xc1086038, 0x412df5b1},
3313 {0, 0xc1b1b7d6, 0x412df5b1},
3314 {'q', 0xc10414a0, 0xb4c00000},
3315 {0, 0xc163a6a8, 0xc04e2cad},
3316 {'9', 0xffe6ffd1, 0xffb0ffb2},
3317 {'l', 0x00000000, 0x41346716},
3318 {'l', 0xc146a860, 0x00000000},
3319 {'l', 0x00000000, 0xc2d0dbeb},
3320 {'l', 0x4146a860, 0x00000000},
3321 {'l', 0x00000000, 0x4222af3f},
3322 {'@', 0x00000063, 0x00004b92},/*        c        x-advance: 75.570312 */
3323 {'M', 0x4286180e, 0xc2909052},
3324 {'l', 0x00000000, 0x4138b2ac},
3325 {'8', 0xdeace9d7, 0xf5acf5d7},
3326 {'q', 0xc14036fc, 0x00000000},
3327 {0, 0xc1954302, 0x40f4d508},
3328 {'q', 0xc0d49e10, 0x40f2af40},
3329 {0, 0xc0d49e10, 0x41aabcfe},
3330 {'q', 0x00000000, 0x415c225c},
3331 {0, 0x40d49e10, 0x41ab4671},
3332 {'q', 0x40d49e10, 0x40f2af3e},
3333 {0, 0x41954302, 0x40f2af3e},
3334 {'8', 0xf554002a, 0xde54f52a},
3335 {'l', 0x00000000, 0x41368ce2},
3336 {'8', 0x1cab13d7, 0x09a309d4},
3337 {'q', 0xc187d6c4, 0x00000000},
3338 {0, 0xc1d7d6c4, 0xc12abcfe},
3339 {'q', 0xc1200000, 0xc12abcff},
3340 {0, 0xc1200000, 0xc1e655e8},
3341 {'q', 0xb5000000, 0xc1931d36},
3342 {0, 0x412112e6, 0xc1e768d0},
3343 {'q', 0x412225cc, 0xc1289730},
3344 {0, 0x41ddbeb5, 0xc1289730},
3345 {'8', 0x0959002d, 0x1b54092b},
3346 {'@', 0x00000064, 0x0000573f},/*        d        x-advance: 87.246094 */
3347 {'M', 0x4279aa18, 0xc27f0897},
3348 {'l', 0x00000000, 0xc222af3f},
3349 {'l', 0x41459578, 0x00000000},
3350 {'4', 0x03430000, 0x0000ff9e},
3351 {'l', 0x00000000, 0xc1346716},
3352 {'q', 0xc07920b0, 0x40d6c3dd},
3353 {0, 0xc11dda34, 0x41200000},
3354 {'q', 0xc0bcfe48, 0x404e2caa},
3355 {0, 0xc163a6a8, 0x404e2caa},
3356 {'q', 0xc159fc90, 0x34000000},
3357 {0, 0xc1b1b7d7, 0xc12df5b0},
3358 {'q', 0xc1086036, 0xc12df5b0},
3359 {0, 0xc1086036, 0xc1e4b98e},
3360 {'q', 0xb5000000, 0xc18dbeb6},
3361 {0, 0x41086036, 0xc1e4b990},
3362 {'q', 0x4109731e, 0xc12df5b0},
3363 {0, 0x41b1b7d7, 0xc12df5b0},
3364 {'q', 0x41052784, 0x00000000},
3365 {0, 0x4163a6a8, 0x40527840},
3366 {'9', 0x0019002f, 0x004f004e},
3367 {'m', 0xc2285278, 0x41d1eed2},
3368 {'q', 0xb6000000, 0x4159fc90},
3369 {0, 0x40b24148, 0x41ab4671},
3370 {'q', 0x40b46714, 0x40f6fad8},
3371 {0, 0x4176fad8, 0x40f6fad8},
3372 {'q', 0x411cc74c, 0x00000000},
3373 {0, 0x4176fad8, 0xc0f6fad8},
3374 {'q', 0x40b46718, 0xc0f920a4},
3375 {0, 0x40b46718, 0xc1ab4671},
3376 {'q', 0x00000000, 0xc159fc90},
3377 {0, 0xc0b46718, 0xc1aabcfe},
3378 {'q', 0xc0b46718, 0xc0f920a8},
3379 {0, 0xc176fad8, 0xc0f920a8},
3380 {'q', 0xc11cc74e, 0x00000000},
3381 {0, 0xc176fad8, 0x40f920a8},
3382 {'q', 0xc0b2414c, 0x40f6fad8},
3383 {0, 0xc0b2414c, 0x41aabcfe},
3384 {'@', 0x00000065, 0x00005490},/*        e        x-advance: 84.562500 */
3385 {'M', 0x429a7f24, 0xc222af3f},
3386 {'4', 0x00300000, 0x0000fe3a},
3387 {'q', 0x3f4e2ca0, 0x414c06de},
3388 {0, 0x40f4d508, 0x419bb466},
3389 {'q', 0x40dd3548, 0x40d49e12},
3390 {0, 0x41998e9a, 0x40d49e12},
3391 {'8', 0xf36e0038, 0xd76af335},
3392 {'l', 0x00000000, 0x413ad87b},
3393 {'q', 0xc0d49e10, 0x40346716},
3394 {0, 0xc159fc8c, 0x4089731d},
3395 {'q', 0xc0df5b10, 0x3fbcfe49},
3396 {0, 0xc16293c4, 0x3fbcfe49},
3397 {'q', 0xc18fe482, 0x00000000},
3398 {0, 0xc1e4301b, 0xc127844c},
3399 {'q', 0xc127844a, 0xc127844b},
3400 {0, 0xc127844a, 0xc1e293c2},
3401 {'q', 0xb5000000, 0xc193a6a8},
3402 {0, 0x411eed1a, 0xc1ea180e},
3403 {'q', 0x411ffffe, 0xc12df5b0},
3404 {0, 0x41d74d4f, 0xc12df5b0},
3405 {'q', 0x4172af40, 0x00000000},
3406 {0, 0x41bfad88, 0x411cc750},
3407 {'9', 0x004d0046, 0x00d40046},
3408 {'m', 0xc1459578, 0xc067f240},
3409 {'q', 0xbe097400, 0xc12225cc},
3410 {0, 0xc0b68ce8, 0xc1816560},
3411 {'q', 0xc0b01b80, 0xc0c149d8},
3412 {0, 0xc16a180c, 0xc0c149d8},
3413 {'q', 0xc1255e80, 0x00000000},
3414 {0, 0xc1849e12, 0x40bad878},
3415 {'q', 0xc0c59578, 0x40bad878},
3416 {0, 0xc0e3a6a8, 0x41838b2a},
3417 {'l', 0x42301b7e, 0xbd897200},
3418 {'@', 0x00000066, 0x00003063},/*        f        x-advance: 48.386719 */
3419 {'M', 0x424c06df, 0xc2d0dbeb},
3420 {'4', 0x00520000, 0x0000ffa2},
3421 {'8', 0x15b600cb, 0x4dec15ec},
3422 {'l', 0x00000000, 0x40d49e10},
3423 {'l', 0x41a2af40, 0x00000000},
3424 {'l', 0x00000000, 0x41198ea0},
3425 {'l', 0xc1a2af40, 0x00000000},
3426 {'l', 0x00000000, 0x42832414},
3427 {'l', 0xc146a85f, 0x00000000},
3428 {'l', 0x00000000, 0xc2832414},
3429 {'0', 0xb40000a2, 0xd700005e},
3430 {'q', 0x00000000, 0xc148ce30},
3431 {0, 0x40bad87a, 0xc1920a50},
3432 {'q', 0x40bad87c, 0xc0b8b2b0},
3433 {0, 0x4194301b, 0xc0b8b2b0},
3434 {'l', 0x413ad87c, 0x00000000},
3435 {'@', 0x00000067, 0x0000573f},/*        g        x-advance: 87.246094 */
3436 {'M', 0x4279aa18, 0xc219d354},
3437 {'q', 0x00000000, 0xc156c3dc},
3438 {0, 0xc0b24150, 0xc1a67166},
3439 {'q', 0xc0b01b78, 0xc0ec3dd8},
3440 {0, 0xc1780dbc, 0xc0ec3dd8},
3441 {'q', 0xc11eed1a, 0x00000000},
3442 {0, 0xc1780dbe, 0x40ec3dd8},
3443 {'q', 0xc0b01b80, 0x40ec3de0},
3444 {0, 0xc0b01b80, 0x41a67166},
3445 {'q', 0x00000000, 0x4155b0f8},
3446 {0, 0x40b01b80, 0x41a5e7f2},
3447 {'q', 0x40b24148, 0x40ec3dda},
3448 {0, 0x41780dbe, 0x40ec3dda},
3449 {'q', 0x41200000, 0x00000000},
3450 {0, 0x41780dbc, 0xc0ec3dda},
3451 {'9', 0xffc5002c, 0xff5b002c},
3452 {'m', 0x41459578, 0x41e90528},
3453 {'q', 0x00000000, 0x41998e9a},
3454 {0, 0xc1086038, 0x41e4b98e},
3455 {'q', 0xc1086034, 0x41154300},
3456 {0, 0xc1d0dbea, 0x41154300},
3457 {'8', 0xf99e00cc, 0xe8a7f8d2},
3458 {'l', 0x00000000, 0xc14036fb},
3459 {'8', 0x2255172b, 0x0b560b2a},
3460 {'q', 0x41425cc4, 0x00000000},
3461 {0, 0x419180dc, 0xc0c9e112},
3462 {'9', 0xffcd0030, 0xff670030},
3463 {'l', 0x00000000, 0xc0c36fb0},
3464 {'q', 0xc074d510, 0x40d49e12},
3465 {0, 0xc11cc750, 0x411eed1a},
3466 {'q', 0xc0bf2410, 0x40527844},
3467 {0, 0xc164b98c, 0x40527844},
3468 {'q', 0xc15d3544, 0x00000000},
3469 {0, 0xc1b2414a, 0xc1289732},
3470 {'q', 0xc1074d50, 0xc1289732},
3471 {0, 0xc1074d50, 0xc1df5b0f},
3472 {'q', 0xb5000000, 0xc18b98ea},
3473 {0, 0x41074d50, 0xc1dfe484},
3474 {'q', 0x41074d50, 0xc1289730},
3475 {0, 0x41b2414a, 0xc1289730},
3476 {'q', 0x41052784, 0x00000000},
3477 {0, 0x4164b98c, 0x40527840},
3478 {'9', 0x001a002f, 0x004f004e},
3479 {'l', 0x00000000, 0xc1368ce4},
3480 {'l', 0x41459578, 0x00000000},
3481 {'l', 0x00000000, 0x4283ad88},
3482 {'@', 0x00000068, 0x0000571d},/*        h        x-advance: 87.113281 */
3483 {'M', 0x4296df5b, 0xc23579fc},
3484 {'4', 0x016a0000, 0x0000ff9e},
3485 {'l', 0x00000000, 0xc233dda3},
3486 {'q', 0x00000000, 0xc12abcfc},
3487 {0, 0xc0852780, 0xc17f9208},
3488 {'q', 0xc0852788, 0xc0a9aa18},
3489 {0, 0xc147bb48, 0xc0a9aa18},
3490 {'q', 0xc1200000, 0x00000000},
3491 {0, 0xc17c5956, 0x40cc06d8},
3492 {'9', 0x0033ffd2, 0x008bffd2},
3493 {'l', 0x00000000, 0x4229eed1},
3494 {'l', 0xc146a860, 0x00000000},
3495 {'4', 0xfcbd0000, 0x00000063},
3496 {'l', 0x00000000, 0x4223c225},
3497 {'8', 0xaf53ca23, 0xe66fe630},
3498 {'q', 0x414f3f90, 0x00000000},
3499 {0, 0x419cc74e, 0x4100dbf0},
3500 {'q', 0x40d49e10, 0x40ff9208},
3501 {0, 0x40d49e10, 0x41bc74d4},
3502 {'@', 0x00000069, 0x00002630},/*        i        x-advance: 38.187500 */
3503 {'M', 0x414f3f92, 0xc29655e8},
3504 {'l', 0x4145957a, 0x00000000},
3505 {'4', 0x02590000, 0x0000ff9e},
3506 {'6', 0xfda70000, 0xff160000},
3507 {'l', 0x4145957a, 0x00000000},
3508 {'l', 0x00000000, 0x417a3388},
3509 {'l', 0xc145957a, 0x00000000},
3510 {'l', 0x00000000, 0xc17a3388},
3511 {'@', 0x0000006a, 0x00002630},/*        j        x-advance: 38.187500 */
3512 {'M', 0x414f3f92, 0xc29655e8},
3513 {'4', 0x00000062, 0x02640000},
3514 {'q', 0x00000000, 0x4165cc71},
3515 {0, 0xc0b01b80, 0x41a67163},
3516 {'9', 0x0033ffd5, 0x0033ff74},
3517 {'4', 0x0000ffdb, 0xffad0000},
3518 {'l', 0x40527845, 0x00000000},
3519 {'8', 0xe74c0038, 0x9414e614},
3520 {'6', 0xfd9c0000, 0xff160000},
3521 {'l', 0x4145957a, 0x00000000},
3522 {'l', 0x00000000, 0x417a3388},
3523 {'l', 0xc145957a, 0x00000000},
3524 {'l', 0x00000000, 0xc17a3388},
3525 {'@', 0x0000006b, 0x00004f98},/*        k        x-advance: 79.593750 */
3526 {'M', 0x4147bb46, 0xc2d0dbeb},
3527 {'l', 0x4146a860, 0x00000000},
3528 {'l', 0x00000000, 0x4276b61e},
3529 {'l', 0x421361ee, 0xc201aa18},
3530 {'l', 0x417c5958, 0x00000000},
3531 {'l', 0xc21f768d, 0x420cabd0},
3532 {'l', 0x42262cab, 0x42200000},
3533 {'l', 0xc180dbea, 0x00000000},
3534 {'l', 0xc218c06e, 0xc212d87b},
3535 {'l', 0x36000000, 0x4212d87b},
3536 {'l', 0xc146a860, 0x00000000},
3537 {'l', 0x00000000, 0xc2d0dbeb},
3538 {'@', 0x0000006c, 0x00002630},/*        l        x-advance: 38.187500 */
3539 {'M', 0x414f3f92, 0xc2d0dbeb},
3540 {'l', 0x4145957a, 0x00000000},
3541 {'l', 0x00000000, 0x42d0dbeb},
3542 {'l', 0xc145957a, 0x00000000},
3543 {'l', 0x00000000, 0xc2d0dbeb},
3544 {'@', 0x0000006d, 0x000085e4},/*        m        x-advance: 133.890625 */
3545 {'M', 0x428ef3f9, 0xc272f3f9},
3546 {'q', 0x40943020, 0xc1052784},
3547 {0, 0x41312e60, 0xc1448294},
3548 {'q', 0x40ce2cb0, 0xc07d6c40},
3549 {0, 0x4172af40, 0xc07d6c40},
3550 {'q', 0x413beb60, 0x00000000},
3551 {0, 0x4190f768, 0x410414a0},
3552 {'9', 0x00410033, 0x00ba0033},
3553 {'4', 0x016a0000, 0x0000ff9d},
3554 {'l', 0x00000000, 0xc233dda3},
3555 {'q', 0x00000000, 0xc12ce2cc},
3556 {0, 0xc074d500, 0xc1805278},
3557 {'q', 0xc074d500, 0xc0a78448},
3558 {0, 0xc13ad878, 0xc0a78448},
3559 {'q', 0xc1198ea0, 0x00000000},
3560 {0, 0xc172af40, 0x40cc06d8},
3561 {'9', 0x0033ffd4, 0x008bffd4},
3562 {'4', 0x01530000, 0x0000ff9d},
3563 {'l', 0x00000000, 0xc233dda3},
3564 {'q', 0x00000000, 0xc12df5b0},
3565 {0, 0xc074d510, 0xc1805278},
3566 {'q', 0xc074d500, 0xc0a78448},
3567 {0, 0xc13cfe48, 0xc0a78448},
3568 {'q', 0xc11768cc, 0x00000000},
3569 {0, 0xc1708972, 0x40ce2ca8},
3570 {'9', 0x0033ffd4, 0x008affd4},
3571 {'l', 0x00000000, 0x4229eed1},
3572 {'l', 0xc146a860, 0x00000000},
3573 {'4', 0xfda70000, 0x00000063},
3574 {'l', 0x00000000, 0x413ad87c},
3575 {'q', 0x40874d50, 0xc0dd3538},
3576 {0, 0x412225ce, 0xc12338b4},
3577 {'q', 0x40bcfe48, 0xc0527840},
3578 {0, 0x41606df4, 0xc0527840},
3579 {'8', 0x216f0041, 0x6044212e},
3580 {'@', 0x0000006e, 0x0000571d},/*        n        x-advance: 87.113281 */
3581 {'M', 0x4296df5b, 0xc23579fc},
3582 {'4', 0x016a0000, 0x0000ff9e},
3583 {'l', 0x00000000, 0xc233dda3},
3584 {'q', 0x00000000, 0xc12abcfc},
3585 {0, 0xc0852780, 0xc17f9208},
3586 {'q', 0xc0852788, 0xc0a9aa18},
3587 {0, 0xc147bb48, 0xc0a9aa18},
3588 {'q', 0xc1200000, 0x00000000},
3589 {0, 0xc17c5956, 0x40cc06d8},
3590 {'9', 0x0033ffd2, 0x008bffd2},
3591 {'l', 0x00000000, 0x4229eed1},
3592 {'l', 0xc146a860, 0x00000000},
3593 {'4', 0xfda70000, 0x00000063},
3594 {'l', 0x00000000, 0x413ad87c},
3595 {'8', 0xaf53ca23, 0xe66fe630},
3596 {'q', 0x414f3f90, 0x00000000},
3597 {0, 0x419cc74e, 0x4100dbf0},
3598 {'q', 0x40d49e10, 0x40ff9208},
3599 {0, 0x40d49e10, 0x41bc74d4},
3600 {'@', 0x0000006f, 0x00005418},/*        o        x-advance: 84.093750 */
3601 {'M', 0x42285278, 0xc2850527},
3602 {'q', 0xc11eed18, 0x00000000},
3603 {0, 0xc17b4670, 0x40f920a0},
3604 {'q', 0xc0b8b2b0, 0x40f6fad8},
3605 {0, 0xc0b8b2b0, 0x41a9aa18},
3606 {'q', 0x00000000, 0x4157d6c2},
3607 {0, 0x40b68ce0, 0x41aa338b},
3608 {'q', 0x40b8b2b0, 0x40f6fad6},
3609 {0, 0x417c5958, 0x40f6fad6},
3610 {'q', 0x411dda34, 0x00000000},
3611 {0, 0x417a338c, 0xc0f920a6},
3612 {'q', 0x40b8b2b0, 0xc0f920a4},
3613 {0, 0x40b8b2b0, 0xc1a9aa17},
3614 {'q', 0x00000000, 0xc155b0f8},
3615 {0, 0xc0b8b2b0, 0xc1a920a6},
3616 {'9', 0xffc2ffd2, 0xffc2ff83},
3617 {'m', 0x00000000, 0xc1278450},
3618 {'q', 0x4180dbec, 0x00000000},
3619 {0, 0x41ca6a84, 0x41278450},
3620 {'q', 0x41131d38, 0x41278448},
3621 {0, 0x41131d38, 0x41e7f240},
3622 {'q', 0x00000000, 0x4193a6a8},
3623 {0, 0xc1131d38, 0x41e7f240},
3624 {'q', 0xc1131d30, 0x4127844d},
3625 {0, 0xc1ca6a84, 0x4127844d},
3626 {'q', 0xc181655e, 0xb4c00000},
3627 {0, 0xc1caf3f9, 0xc127844c},
3628 {'q', 0xc1120a4e, 0xc1289731},
3629 {0, 0xc1120a4e, 0xc1e7f240},
3630 {'q', 0xb5000000, 0xc194301c},
3631 {0, 0x41120a4e, 0xc1e7f240},
3632 {'q', 0x41131d36, 0xc1278450},
3633 {0, 0x41caf3f9, 0xc1278450},
3634 {'[', 0x002d006f, 0x0000028c},
3635 {'@', 0x00000070, 0x0000573f},/*        p        x-advance: 87.246094 */
3636 {'M', 0x41c731d3, 0xc1346716},
3637 {'l', 0x00000000, 0x421f768c},
3638 {'l', 0xc146a860, 0x36000000},
3639 {'4', 0xfcc20000, 0x00000063},
3640 {'l', 0x00000000, 0x41368ce4},
3641 {'q', 0x407920a8, 0xc0d6c3d8},
3642 {0, 0x411cc74e, 0xc11eed1c},
3643 {'q', 0x40bf2410, 0xc0527840},
3644 {0, 0x4163a6a8, 0xc0527840},
3645 {'q', 0x415b0f74, 0x00000000},
3646 {0, 0x41b1b7d6, 0x412df5b0},
3647 {'q', 0x41097320, 0x412df5b4},
3648 {0, 0x41097320, 0x41e4b990},
3649 {'q', 0x00000000, 0x418dbeb6},
3650 {0, 0xc1097320, 0x41e4b98e},
3651 {'q', 0xc1086038, 0x412df5b1},
3652 {0, 0xc1b1b7d6, 0x412df5b1},
3653 {'q', 0xc10414a0, 0xb4c00000},
3654 {0, 0xc163a6a8, 0xc04e2cad},
3655 {'9', 0xffe6ffd1, 0xffb0ffb2},
3656 {'m', 0x42280dbe, 0xc1d1eed1},
3657 {'q', 0x00000000, 0xc159fc90},
3658 {0, 0xc0b46718, 0xc1aabcfe},
3659 {'q', 0xc0b24148, 0xc0f920a8},
3660 {0, 0xc175e7f0, 0xc0f920a8},
3661 {'q', 0xc11cc750, 0x00000000},
3662 {0, 0xc176fada, 0x40f920a8},
3663 {'q', 0xc0b24148, 0x40f6fad8},
3664 {0, 0xc0b24148, 0x41aabcfe},
3665 {'q', 0x00000000, 0x4159fc90},
3666 {0, 0x40b24148, 0x41ab4671},
3667 {'q', 0x40b46714, 0x40f6fad8},
3668 {0, 0x4176fada, 0x40f6fad8},
3669 {'q', 0x411cc74c, 0x00000000},
3670 {0, 0x4175e7f0, 0xc0f6fad8},
3671 {'q', 0x40b46718, 0xc0f920a4},
3672 {0, 0x40b46718, 0xc1ab4671},
3673 {'@', 0x00000071, 0x0000573f},/*        q        x-advance: 87.246094 */
3674 {'M', 0x41a2af3f, 0xc216112e},
3675 {'q', 0x00000000, 0x4159fc90},
3676 {0, 0x40b2414c, 0x41ab4671},
3677 {'q', 0x40b46714, 0x40f6fad8},
3678 {0, 0x4176fad8, 0x40f6fad8},
3679 {'q', 0x411cc74c, 0x00000000},
3680 {0, 0x4176fad8, 0xc0f6fad8},
3681 {'q', 0x40b46718, 0xc0f920a4},
3682 {0, 0x40b46718, 0xc1ab4671},
3683 {'q', 0x00000000, 0xc159fc90},
3684 {0, 0xc0b46718, 0xc1aabcfe},
3685 {'q', 0xc0b46718, 0xc0f920a8},
3686 {0, 0xc176fad8, 0xc0f920a8},
3687 {'q', 0xc11cc74e, 0x00000000},
3688 {0, 0xc176fad8, 0x40f920a8},
3689 {'9', 0x003dffd4, 0x00aaffd4},
3690 {'m', 0x42285278, 0x41d1eed1},
3691 {'q', 0xc07920b0, 0x40d6c3dd},
3692 {0, 0xc11dda34, 0x41200000},
3693 {'q', 0xc0bcfe48, 0x404e2caa},
3694 {0, 0xc163a6a8, 0x404e2caa},
3695 {'q', 0xc159fc90, 0x34000000},
3696 {0, 0xc1b1b7d7, 0xc12df5b0},
3697 {'q', 0xc1086036, 0xc12df5b0},
3698 {0, 0xc1086036, 0xc1e4b98e},
3699 {'q', 0xb5000000, 0xc18dbeb6},
3700 {0, 0x41086036, 0xc1e4b990},
3701 {'q', 0x4109731e, 0xc12df5b0},
3702 {0, 0x41b1b7d7, 0xc12df5b0},
3703 {'q', 0x41052784, 0x00000000},
3704 {0, 0x4163a6a8, 0x40527840},
3705 {'9', 0x0019002f, 0x004f004e},
3706 {'l', 0x00000000, 0xc1368ce4},
3707 {'l', 0x41459578, 0x00000000},
3708 {'l', 0x00000000, 0x42cf844c},
3709 {'l', 0xc1459578, 0xb6800000},
3710 {'l', 0x00000000, 0xc21f768c},
3711 {'@', 0x00000072, 0x00003882},/*        r        x-advance: 56.507812 */
3712 {'M', 0x42620a4f, 0xc27e7f24},
3713 {'8', 0xf3dcf7f0, 0xfcd6fced},
3714 {'q', 0xc127844c, 0x00000000},
3715 {0, 0xc180dbeb, 0x40db0f78},
3716 {'9', 0x0036ffd4, 0x009cffd4},
3717 {'l', 0x00000000, 0x421e63a6},
3718 {'l', 0xc146a860, 0x00000000},
3719 {'4', 0xfda70000, 0x00000063},
3720 {'l', 0x00000000, 0x413ad87c},
3721 {'q', 0x407920a8, 0xc0db0f78},
3722 {0, 0x412225ce, 0xc12225cc},
3723 {'q', 0x40c7bb40, 0xc056c3e0},
3724 {0, 0x4172af3c, 0xc056c3e0},
3725 {'8', 0x0116000a, 0x031b010c},
3726 {'l', 0x3d897400, 0x414af3f8},
3727 {'@', 0x00000073, 0x0000479c},/*        s        x-advance: 71.609375 */
3728 {'M', 0x42737d6c, 0xc291e7f2},
3729 {'l', 0x00000000, 0x413ad87c},
3730 {'8', 0xe0aaebd7, 0xf6a3f6d3},
3731 {'8', 0x169200b7, 0x43dc16dc},
3732 {'8', 0x361a2200, 0x2569131a},
3733 {'l', 0x40874d50, 0x3f708980},
3734 {'q', 0x41527844, 0x40346720},
3735 {0, 0x41954302, 0x40ff9208},
3736 {'q', 0x40b24150, 0x40a338b4},
3737 {0, 0x40b24150, 0x4164b990},
3738 {'q', 0x00000000, 0x4127844b},
3739 {0, 0xc1052788, 0x41849e11},
3740 {'q', 0xc104149c, 0x40c36fad},
3741 {0, 0xc1b6036e, 0x40c36fad},
3742 {'8', 0xf79c00d0, 0xe492f7cc},
3743 {'l', 0x00000000, 0xc14c06df},
3744 {'8', 0x2a6b1c36, 0x0d690d35},
3745 {'8', 0xe96b0045, 0xbd25e825},
3746 {'q', 0x00000000, 0xc0a112e8},
3747 {0, 0xc05b0f70, 0xc0f6fad8},
3748 {'9', 0xffebffe6, 0xffd7ff8a},
3749 {'l', 0xc0897320, 0xbf80dbe0},
3750 {'q', 0xc1379fc8, 0xc01aa180},
3751 {0, 0xc1849e11, 0xc0ec3de0},
3752 {'q', 0xc0a338b2, 0xc0a112e0},
3753 {0, 0xc0a338b2, 0xc15c225c},
3754 {'q', 0x00000000, 0xc129aa18},
3755 {0, 0x40f08972, 0xc18301b8},
3756 {'q', 0x40f08974, 0xc0b8b2b0},
3757 {0, 0x41aabcff, 0xc0b8b2b0},
3758 {'8', 0x08670036, 0x18590830},
3759 {'@', 0x00000074, 0x000035e4},/*        t        x-advance: 53.890625 */
3760 {'M', 0x41c9579f, 0xc2c10527},
3761 {'l', 0x00000000, 0x41aabcfc},
3762 {'l', 0x41cb7d6d, 0x00000000},
3763 {'4', 0x004c0000, 0x0000ff35},
3764 {'l', 0x00000000, 0x422338b2},
3765 {'8', 0x5e134900, 0x14521414},
3766 {'4', 0x00000065, 0x00520000},
3767 {'l', 0xc14af3f8, 0x00000000},
3768 {'q', 0xc164b990, 0x00000000},
3769 {0, 0xc19dda34, 0xc0a9aa18},
3770 {'9', 0xffd6ffd5, 0xff65ffd5},
3771 {'l', 0x00000000, 0xc22338b2},
3772 {'l', 0xc110f768, 0x00000000},
3773 {'l', 0xb5000000, 0xc1198ea0},
3774 {'l', 0x4110f768, 0x00000000},
3775 {'l', 0x35800000, 0xc1aabcfc},
3776 {'l', 0x4146a85f, 0x00000000},
3777 {'@', 0x00000075, 0x0000571d},/*        u        x-advance: 87.113281 */
3778 {'M', 0x413ad87b, 0xc1ed50c0},
3779 {'4', 0xfe940000, 0x00000062},
3780 {'l', 0x00000000, 0x4234225d},
3781 {'q', 0x00000000, 0x412abcfe},
3782 {0, 0x40852784, 0x41805278},
3783 {'q', 0x40852780, 0x40a9aa18},
3784 {0, 0x4147bb44, 0x40a9aa18},
3785 {'q', 0x41200000, 0x00000000},
3786 {0, 0x417c5958, 0xc0cc06de},
3787 {'9', 0xffcd002e, 0xff75002e},
3788 {'l', 0x00000000, 0xc22a7845},
3789 {'l', 0x41459574, 0x00000000},
3790 {'4', 0x02590000, 0x0000ff9e},
3791 {'l', 0x00000000, 0xc138b2af},
3792 {'8', 0x51ad36dd, 0x1a921ad1},
3793 {'q', 0xc14f3f94, 0x34000000},
3794 {0, 0xc19d50c1, 0xc100dbeb},
3795 {'9', 0xffc0ffcb, 0xff44ffcb},
3796 {'m', 0x41f89732, 0xc23d4302},
3797 {'l', 0x00000000, 0x00000000},
3798 {'@', 0x00000076, 0x00005157},/*        v        x-advance: 81.339844 */
3799 {'M', 0x408301b8, 0xc29655e8},
3800 {'l', 0x4151655e, 0x00000000},
3801 {'l', 0x41bbeb61, 0x427c5958},
3802 {'l', 0x41bbeb62, 0xc27c5958},
3803 {'l', 0x41516560, 0x00000000},
3804 {'l', 0xc1e180dc, 0x429655e8},
3805 {'l', 0xc1863a6a, 0x00000000},
3806 {'l', 0xc1e180dc, 0xc29655e8},
3807 {'@', 0x00000077, 0x0000706a},/*        w        x-advance: 112.414062 */
3808 {'M', 0x40b8b2af, 0xc29655e8},
3809 {'l', 0x4145957a, 0x00000000},
3810 {'l', 0x4176fad6, 0x426aa181},
3811 {'l', 0x4175e7f4, 0xc26aa181},
3812 {'l', 0x41690528, 0x00000000},
3813 {'l', 0x4176fad4, 0x426aa181},
3814 {'l', 0x4175e7f8, 0xc26aa181},
3815 {'l', 0x41459578, 0x00000000},
3816 {'l', 0xc19d50c0, 0x429655e8},
3817 {'l', 0xc1690528, 0x00000000},
3818 {'l', 0xc1816560, 0xc2767165},
3819 {'l', 0xc181eed0, 0x42767165},
3820 {'l', 0xc1690528, 0x00000000},
3821 {'l', 0xc19d50c0, 0xc29655e8},
3822 {'@', 0x00000078, 0x00005157},/*        x        x-advance: 81.339844 */
3823 {'M', 0x4296df5b, 0xc29655e8},
3824 {'l', 0xc1d9731e, 0x42124f09},
3825 {'l', 0x41e4b98e, 0x421a5cc7},
3826 {'l', 0xc1690524, 0x00000000},
3827 {'l', 0xc1af0898, 0xc1ec3dda},
3828 {'l', 0xc1af0897, 0x41ec3dda},
3829 {'l', 0xc1690527, 0x00000000},
3830 {'l', 0x41e98e9a, 0xc21d50c0},
3831 {'l', 0xc1d5b0f7, 0xc20f5b10},
3832 {'l', 0x41690526, 0x00000000},
3833 {'l', 0x419f768e, 0x41d63a6c},
3834 {'l', 0x419f768c, 0xc1d63a6c},
3835 {'l', 0x41690528, 0x00000000},
3836 {'@', 0x00000079, 0x00005157},/*        y        x-advance: 81.339844 */
3837 {'M', 0x4230e9aa, 0x40df5b0f},
3838 {'q', 0xc0a78450, 0x4156c3dc},
3839 {0, 0xc12338b4, 0x418c225c},
3840 {'9', 0x0020ffd9, 0x0020ff96},
3841 {'4', 0x0000ffb2, 0xffae0000},
3842 {'l', 0x40e7f242, 0x00000000},
3843 {'8', 0xed3f0028, 0xa531ed16},
3844 {'l', 0x400dbeb0, 0xc0b46716},
3845 {'l', 0xc1f338b2, 0xc293eb62},
3846 {'l', 0x4151655e, 0x00000000},
3847 {'l', 0x41bbeb61, 0x426b2af4},
3848 {'l', 0x41bbeb62, 0xc26b2af4},
3849 {'l', 0x41516560, 0x00000000},
3850 {'l', 0xc204149e, 0x42a44b99},
3851 {'@', 0x0000007a, 0x00004825},/*        z        x-advance: 72.144531 */
3852 {'M', 0x40f2af3f, 0xc29655e8},
3853 {'l', 0x426aa180, 0x00000000},
3854 {'l', 0x00000000, 0x41346718},
3855 {'l', 0xc239c595, 0x42581b7d},
3856 {'l', 0x4239c595, 0x35800000},
3857 {'l', 0x00000000, 0x411dda33},
3858 {'l', 0xc271579f, 0x00000000},
3859 {'l', 0x00000000, 0xc1346716},
3860 {'l', 0x4239c595, 0xc2581b7c},
3861 {'l', 0xc2330f76, 0x00000000},
3862 {'l', 0xb5000000, 0xc11dda38},
3863 {'@', 0x0000007b, 0x00005773},/*        {        x-advance: 87.449219 */
3864 {'M', 0x428c8973, 0x414c06df},
3865 {'4', 0x004d0000, 0x0000ffdf},
3866 {'q', 0xc185b0f8, 0x00000000},
3867 {0, 0xc1b35432, 0xc09eed1c},
3868 {'9', 0xffd9ffd3, 0xff62ffd3},
3869 {'l', 0x00000000, 0xc1805278},
3870 {'q', 0x00000000, 0xc12225cc},
3871 {0, 0xc067f240, 0xc1606df6},
3872 {'9', 0xffe1ffe4, 0xffe1ff97},
3873 {'4', 0x0000ffe0, 0xffb40000},
3874 {'l', 0x408301b8, 0x00000000},
3875 {'8', 0xe269004c, 0x911ce11c},
3876 {'l', 0x00000000, 0xc180dbec},
3877 {'q', 0x00000000, 0xc16d50c0},
3878 {0, 0x40b46710, 0xc19dda30},
3879 {'9', 0xffd9002d, 0xffd900b3},
3880 {'4', 0x00000021, 0x004c0000},
3881 {'l', 0xc0920a50, 0x00000000},
3882 {'8', 0x179e00b5, 0x63e917e9},
3883 {'l', 0x00000000, 0x41852786},
3884 {'q', 0x00000000, 0x41289730},
3885 {0, 0xc0459580, 0x4174d50c},
3886 {'8', 0x33ad26e8, 0x34530e3b},
3887 {'9', 0x00260018, 0x00790018},
3888 {'l', 0x00000000, 0x41852785},
3889 {'8', 0x63174b00, 0x17621717},
3890 {'l', 0x40920a50, 0x00000000},
3891 {'@', 0x0000007c, 0x00002e4f},/*        |        x-advance: 46.308594 */
3892 {'M', 0x41e6df5b, 0xc2d2112e},
3893 {'l', 0x00000000, 0x4309731d},
3894 {'l', 0xc1368ce4, 0x00000000},
3895 {'l', 0x00000000, 0xc309731d},
3896 {'l', 0x41368ce4, 0x00000000},
3897 {'@', 0x0000007d, 0x00005773},/*        }        x-advance: 87.449219 */
3898 {'M', 0x4189731d, 0x414c06df},
3899 {'l', 0x409655e8, 0x00000000},
3900 {'8', 0xe961004b, 0x9d17e917},
3901 {'l', 0x00000000, 0xc1852784},
3902 {'q', 0x00000000, 0xc127844a},
3903 {0, 0x404149e0, 0xc173c224},
3904 {'8', 0xcc53da18, 0xcdadf3c5},
3905 {'9', 0xffdaffe8, 0xff86ffe8},
3906 {'l', 0x00000000, 0xc1852786},
3907 {'8', 0x9de9b400, 0xe99fe9ea},
3908 {'4', 0x0000ffdb, 0xffb40000},
3909 {'l', 0x40874d50, 0x00000000},
3910 {'q', 0x4185b0f7, 0x00000000},
3911 {0, 0x41b24149, 0x409eed20},
3912 {'9', 0x0027002d, 0x009d002d},
3913 {'l', 0x00000000, 0x4180dbec},
3914 {'8', 0x6f1c5000, 0x1e691e1c},
3915 {'4', 0x00000021, 0x004c0000},
3916 {'l', 0xc0852780, 0x00000000},
3917 {'q', 0xc1187bb8, 0x00000000},
3918 {0, 0xc1527848, 0x407920a0},
3919 {'9', 0x001fffe4, 0x0070ffe4},
3920 {'l', 0x00000000, 0x41805278},
3921 {'q', 0x00000000, 0x416d50c0},
3922 {0, 0xc0b46718, 0x419e63a6},
3923 {'9', 0x0027ffd4, 0x0027ff4e},
3924 {'l', 0xc0874d50, 0x00000000},
3925 {'l', 0x00000000, 0xc11aa181},
3926 {'@', 0x0000007e, 0x0000732a},/*        ~        x-advance: 115.164062 */
3927 {'M', 0x42c93543, 0xc25b5430},
3928 {'l', 0x00000000, 0x413f2414},
3929 {'8', 0x3c982ac8, 0x129d12d1},
3930 {'q', 0xc0ec3dd0, 0x00000000},
3931 {0, 0xc189731c, 0xc07d6c40},
3932 {'8', 0xfdf8fefb, 0xfcf5fffd},
3933 {'q', 0xc1267168, 0xc0852780},
3934 {0, 0xc185b0f8, 0xc0852780},
3935 {'8', 0x14a300d1, 0x409e14d2},
3936 {'l', 0x00000000, 0xc13f2414},
3937 {'8', 0xc468d638, 0xee64ee30},
3938 {'q', 0x40ec3dd8, 0x00000000},
3939 {0, 0x4189fc90, 0x4080dbe8},
3940 {'8', 0x03080205, 0x040b0104},
3941 {'q', 0x41267164, 0x40852780},
3942 {0, 0x4185b0f6, 0x40852780},
3943 {'8', 0xec5b002e, 0xbf64ec2d},
3944 };
3945 #define CTX_FONT_ascii 1
3946 #endif
3947 #endif //_CTX_INTERNAL_FONT_
3948 #ifndef __CTX_LIST__
3949 #define __CTX_LIST__
3950 
3951 #if !__COSMOPOLITAN__
3952 #include <stdlib.h>
3953 #endif
3954 
3955 /* The whole ctx_list implementation is in the header and will be inlined
3956  * wherever it is used.
3957  */
3958 
ctx_calloc(size_t size,size_t count)3959 static inline void *ctx_calloc (size_t size, size_t count)
3960 {
3961   size_t byte_size = size * count;
3962   char *ret = (char*)malloc (byte_size);
3963   for (size_t i = 0; i < byte_size; i++)
3964      ret[i] = 0;
3965   return ret;
3966 }
3967 
3968 typedef struct _CtxList CtxList;
3969 struct _CtxList {
3970   void *data;
3971   CtxList *next;
3972   void (*freefunc)(void *data, void *freefunc_data);
3973   void *freefunc_data;
3974 };
3975 
ctx_list_prepend_full(CtxList ** list,void * data,void (* freefunc)(void * data,void * freefunc_data),void * freefunc_data)3976 static inline void ctx_list_prepend_full (CtxList **list, void *data,
3977     void (*freefunc)(void *data, void *freefunc_data),
3978     void *freefunc_data)
3979 {
3980   CtxList *new_= (CtxList*)ctx_calloc (sizeof (CtxList), 1);
3981   new_->next = *list;
3982   new_->data=data;
3983   new_->freefunc=freefunc;
3984   new_->freefunc_data = freefunc_data;
3985   *list = new_;
3986 }
3987 
ctx_list_length(CtxList * list)3988 static inline int ctx_list_length (CtxList *list)
3989 {
3990   int length = 0;
3991   CtxList *l;
3992   for (l = list; l; l = l->next, length++);
3993   return length;
3994 }
3995 
ctx_list_prepend(CtxList ** list,void * data)3996 static inline void ctx_list_prepend (CtxList **list, void *data)
3997 {
3998   CtxList *new_ = (CtxList*) ctx_calloc (sizeof (CtxList), 1);
3999   new_->next= *list;
4000   new_->data=data;
4001   *list = new_;
4002 }
4003 
ctx_list_nth(CtxList * list,int no)4004 static inline CtxList *ctx_list_nth (CtxList *list, int no)
4005 {
4006   while (no-- && list)
4007     { list = list->next; }
4008   return list;
4009 }
4010 
ctx_list_nth_data(CtxList * list,int no)4011 static inline void *ctx_list_nth_data (CtxList *list, int no)
4012 {
4013   CtxList *l = ctx_list_nth (list, no);
4014   if (l)
4015     return l->data;
4016   return NULL;
4017 }
4018 
4019 
4020 static inline void
ctx_list_insert_before(CtxList ** list,CtxList * sibling,void * data)4021 ctx_list_insert_before (CtxList **list, CtxList *sibling,
4022                        void *data)
4023 {
4024   if (*list == NULL || *list == sibling)
4025     {
4026       ctx_list_prepend (list, data);
4027     }
4028   else
4029     {
4030       CtxList *prev = NULL;
4031       for (CtxList *l = *list; l; l=l->next)
4032         {
4033           if (l == sibling)
4034             { break; }
4035           prev = l;
4036         }
4037       if (prev)
4038         {
4039           CtxList *new_ = (CtxList*)ctx_calloc (sizeof (CtxList), 1);
4040           new_->next = sibling;
4041           new_->data = data;
4042           prev->next=new_;
4043         }
4044     }
4045 }
4046 
ctx_list_remove_link(CtxList ** list,CtxList * link)4047 static inline void ctx_list_remove_link (CtxList **list, CtxList *link)
4048 {
4049   CtxList *iter, *prev = NULL;
4050   if ((*list) == link)
4051     {
4052       prev = (*list)->next;
4053       *list = prev;
4054       link->next = NULL;
4055       return;
4056     }
4057   for (iter = *list; iter; iter = iter->next)
4058     if (iter == link)
4059       {
4060         if (prev)
4061           prev->next = iter->next;
4062         link->next = NULL;
4063         return;
4064       }
4065     else
4066       prev = iter;
4067 }
4068 
ctx_list_remove(CtxList ** list,void * data)4069 static inline void ctx_list_remove (CtxList **list, void *data)
4070 {
4071   CtxList *iter, *prev = NULL;
4072   if ((*list)->data == data)
4073     {
4074       if ((*list)->freefunc)
4075         (*list)->freefunc ((*list)->data, (*list)->freefunc_data);
4076       prev = (*list)->next;
4077       free (*list);
4078       *list = prev;
4079       return;
4080     }
4081   for (iter = *list; iter; iter = iter->next)
4082     if (iter->data == data)
4083       {
4084         if (iter->freefunc)
4085           iter->freefunc (iter->data, iter->freefunc_data);
4086         prev->next = iter->next;
4087         free (iter);
4088         break;
4089       }
4090     else
4091       prev = iter;
4092 }
4093 
ctx_list_free(CtxList ** list)4094 static inline void ctx_list_free (CtxList **list)
4095 {
4096   while (*list)
4097     ctx_list_remove (list, (*list)->data);
4098 }
4099 
4100 static inline void
ctx_list_reverse(CtxList ** list)4101 ctx_list_reverse (CtxList **list)
4102 {
4103   CtxList *new_ = NULL;
4104   CtxList *l;
4105   for (l = *list; l; l=l->next)
4106     ctx_list_prepend (&new_, l->data);
4107   ctx_list_free (list);
4108   *list = new_;
4109 }
4110 
ctx_list_last(CtxList * list)4111 static inline void *ctx_list_last (CtxList *list)
4112 {
4113   if (list)
4114     {
4115       CtxList *last;
4116       for (last = list; last->next; last=last->next);
4117       return last->data;
4118     }
4119   return NULL;
4120 }
4121 
ctx_list_concat(CtxList ** list,CtxList * list_b)4122 static inline void ctx_list_concat (CtxList **list, CtxList *list_b)
4123 {
4124   if (*list)
4125     {
4126       CtxList *last;
4127       for (last = *list; last->next; last=last->next);
4128       last->next = list_b;
4129       return;
4130     }
4131   *list = list_b;
4132 }
4133 
ctx_list_append_full(CtxList ** list,void * data,void (* freefunc)(void * data,void * freefunc_data),void * freefunc_data)4134 static inline void ctx_list_append_full (CtxList **list, void *data,
4135     void (*freefunc)(void *data, void *freefunc_data),
4136     void *freefunc_data)
4137 {
4138   CtxList *new_ = (CtxList*) ctx_calloc (sizeof (CtxList), 1);
4139   new_->data=data;
4140   new_->freefunc = freefunc;
4141   new_->freefunc_data = freefunc_data;
4142   ctx_list_concat (list, new_);
4143 }
4144 
ctx_list_append(CtxList ** list,void * data)4145 static inline void ctx_list_append (CtxList **list, void *data)
4146 {
4147   ctx_list_append_full (list, data, NULL, NULL);
4148 }
4149 
4150 static inline void
ctx_list_insert_at(CtxList ** list,int no,void * data)4151 ctx_list_insert_at (CtxList **list,
4152                     int       no,
4153                     void     *data)
4154 {
4155   if (*list == NULL || no == 0)
4156     {
4157       ctx_list_prepend (list, data);
4158     }
4159   else
4160     {
4161       int pos = 0;
4162       CtxList *prev = NULL;
4163       CtxList *sibling = NULL;
4164       for (CtxList *l = *list; l && pos < no; l=l->next)
4165         {
4166           prev = sibling;
4167           sibling = l;
4168           pos ++;
4169         }
4170       if (prev)
4171         {
4172           CtxList *new_ = (CtxList*)ctx_calloc (sizeof (CtxList), 1);
4173           new_->next = sibling;
4174           new_->data = data;
4175           prev->next=new_;
4176           return;
4177         }
4178       ctx_list_append (list, data);
4179     }
4180 }
4181 
4182 static CtxList*
ctx_list_merge_sorted(CtxList * list1,CtxList * list2,int (* compare)(const void * a,const void * b,void * userdata),void * userdata)4183 ctx_list_merge_sorted (CtxList* list1,
4184                        CtxList* list2,
4185     int(*compare)(const void *a, const void *b, void *userdata), void *userdata
4186 )
4187 {
4188   if (list1 == NULL)
4189      return(list2);
4190   else if (list2==NULL)
4191      return(list1);
4192 
4193   if (compare (list1->data, list2->data, userdata) >= 0)
4194   {
4195     list1->next = ctx_list_merge_sorted (list1->next,list2, compare, userdata);
4196     /*list1->next->prev = list1;
4197       list1->prev = NULL;*/
4198     return list1;
4199   }
4200   else
4201   {
4202     list2->next = ctx_list_merge_sorted (list1,list2->next, compare, userdata);
4203     /*list2->next->prev = list2;
4204       list2->prev = NULL;*/
4205     return list2;
4206   }
4207 }
4208 
4209 static void
ctx_list_split_half(CtxList * head,CtxList ** list1,CtxList ** list2)4210 ctx_list_split_half (CtxList*  head,
4211                      CtxList** list1,
4212                      CtxList** list2)
4213 {
4214   CtxList* fast;
4215   CtxList* slow;
4216   if (head==NULL || head->next==NULL)
4217   {
4218     *list1 = head;
4219     *list2 = NULL;
4220   }
4221   else
4222   {
4223     slow = head;
4224     fast = head->next;
4225 
4226     while (fast != NULL)
4227     {
4228       fast = fast->next;
4229       if (fast != NULL)
4230       {
4231         slow = slow->next;
4232         fast = fast->next;
4233       }
4234     }
4235 
4236     *list1 = head;
4237     *list2 = slow->next;
4238     slow->next = NULL;
4239   }
4240 }
4241 
ctx_list_sort(CtxList ** head,int (* compare)(const void * a,const void * b,void * userdata),void * userdata)4242 static inline void ctx_list_sort (CtxList **head,
4243     int(*compare)(const void *a, const void *b, void *userdata),
4244     void *userdata)
4245 {
4246   CtxList* list1;
4247   CtxList* list2;
4248 
4249   /* Base case -- length 0 or 1 */
4250   if ((*head == NULL) || ((*head)->next == NULL))
4251   {
4252     return;
4253   }
4254 
4255   ctx_list_split_half (*head, &list1, &list2);
4256   ctx_list_sort (&list1, compare, userdata);
4257   ctx_list_sort (&list2, compare, userdata);
4258   *head = ctx_list_merge_sorted (list1, list2, compare, userdata);
4259 }
4260 
ctx_list_insert_sorted(CtxList ** list,void * item,int (* compare)(const void * a,const void * b,void * userdata),void * userdata)4261 static inline void ctx_list_insert_sorted (CtxList **list,
4262                                            void     *item,
4263     int(*compare)(const void *a, const void *b, void *userdata),
4264                                            void     *userdata)
4265 {
4266   ctx_list_prepend (list, item);
4267   ctx_list_sort (list, compare, userdata);
4268 }
4269 
4270 
ctx_list_find_custom(CtxList * list,void * needle,int (* compare)(const void * a,const void * b),void * userdata)4271 static inline CtxList *ctx_list_find_custom (CtxList *list,
4272                                          void    *needle,
4273                                          int(*compare)(const void *a, const void *b),
4274                                          void *userdata)
4275 {
4276   CtxList *l;
4277   for (l = list; l; l = l->next)
4278   {
4279     if (compare (l->data, needle) == 0)
4280       return l;
4281   }
4282   return NULL;
4283 }
4284 
4285 #endif
4286 /* definitions that determine which features are included and their settings,
4287  * for particular platforms - in particular microcontrollers ctx might need
4288  * tuning for different quality/performance/resource constraints.
4289  *
4290  * the way to configure ctx is to set these defines, before both including it
4291  * as a header and in the file where CTX_IMPLEMENTATION is set to include the
4292  * implementation for different featureset and runtime settings.
4293  *
4294  */
4295 
4296 /* whether the font rendering happens in backend or front-end of API, the
4297  * option is used set to 0 by the tool that converts ttf fonts to ctx internal
4298  * representation - both should be possible so that this tool can be made
4299  * into a TTF/OTF font import at runtime (perhaps even with live subsetting).
4300  */
4301 #ifndef CTX_BACKEND_TEXT
4302 #define CTX_BACKEND_TEXT 1
4303 #endif
4304 
4305 
4306 #define CTX_RASTERIZER_AA_SLOPE_LIMIT3          (65536/CTX_SUBDIV/15)
4307 #define CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA  (65536/CTX_SUBDIV/15)
4308 //#define CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA (120536/CTX_SUBDIV/15)
4309 //#define CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA (105000/CTX_SUBDIV/15)
4310 #define CTX_RASTERIZER_AA_SLOPE_LIMIT5         (140425/CTX_SUBDIV/15)
4311 #define CTX_RASTERIZER_AA_SLOPE_LIMIT15        (260425/CTX_SUBDIV/15)
4312 
4313 /* subpixel-aa coordinates used in BITPACKing of drawlist
4314  *
4315  * powers of 2 is faster
4316  */
4317 #ifndef CTX_SUBDIV
4318 #define CTX_SUBDIV   8  //  max framebufer width 4095
4319 //#define CTX_SUBDIV  10  //  max framebufer width 3250
4320 //#define CTX_SUBDIV  16  //  max framebufer width 2047
4321 //#define CTX_SUBDIV  24  //  max framebufer width 1350
4322 //#define CTX_SUBDIV  32  //  max framebufer width 1023
4323 #endif
4324 
4325 
4326 // 8    12 68 40 24
4327 // 16   12 68 40 24
4328 /* scale-factor for font outlines prior to bit quantization by CTX_SUBDIV
4329  *
4330  * changing this also changes font file format - the value should be baked
4331  * into the ctxf files making them less dependent on the ctx used to
4332  * generate them
4333  */
4334 #define CTX_BAKE_FONT_SIZE    160
4335 
4336 /* pack some linetos/curvetos/movetos into denser drawlist instructions,
4337  * permitting more vectors to be stored in the same space, experimental
4338  * feature with added overhead.
4339  */
4340 #ifndef CTX_BITPACK
4341 #define CTX_BITPACK           1
4342 #endif
4343 
4344 /* whether we have a shape-cache where we keep pre-rasterized bitmaps of
4345  * commonly occuring small shapes, disabled by default since it has some
4346  * glitches (and potential hangs with multi threading).
4347  */
4348 #ifndef CTX_SHAPE_CACHE
4349 #define CTX_SHAPE_CACHE        0
4350 #endif
4351 
4352 /* size (in pixels, w*h) that we cache rasterization for
4353  */
4354 #ifndef CTX_SHAPE_CACHE_DIM
4355 #define CTX_SHAPE_CACHE_DIM      (16*8)
4356 #endif
4357 
4358 #ifndef CTX_SHAPE_CACHE_MAX_DIM
4359 #define CTX_SHAPE_CACHE_MAX_DIM  20
4360 #endif
4361 
4362 /* maximum number of entries in shape cache
4363  */
4364 #ifndef CTX_SHAPE_CACHE_ENTRIES
4365 #define CTX_SHAPE_CACHE_ENTRIES  160
4366 #endif
4367 
4368 
4369 #ifndef CTX_PARSER_FIXED_TEMP
4370 #define CTX_PARSER_FIXED_TEMP 0
4371          // when 1  CTX_PARSER_MAXLEN is the fixed max stringlen
4372 #endif   // and no allocations happens beyond creating the parser,
4373          // when 0 the scratchbuf for parsing is a separate dynamically
4374          // growing buffer, that maxes out at CTX_PARSER_MAXLEN
4375          //
4376 #ifndef CTX_PARSER_MAXLEN
4377 #if CTX_PARSER_FIXED_TEMP
4378 #define CTX_PARSER_MAXLEN  1024*128        // This is the maximum texture/string size supported
4379 #else
4380 #define CTX_PARSER_MAXLEN  1024*1024*16    // 16mb
4381 #endif
4382 #endif
4383 
4384 #ifndef CTX_COMPOSITING_GROUPS
4385 #define CTX_COMPOSITING_GROUPS   1
4386 #endif
4387 
4388 /* maximum nesting level of compositing groups
4389  */
4390 #ifndef CTX_GROUP_MAX
4391 #define CTX_GROUP_MAX             8
4392 #endif
4393 
4394 #ifndef CTX_ENABLE_CLIP
4395 #define CTX_ENABLE_CLIP           1
4396 #endif
4397 
4398 /* use a 1bit clip buffer, saving RAM on microcontrollers, other rendering
4399  * will still be antialiased.
4400  */
4401 #ifndef CTX_1BIT_CLIP
4402 #define CTX_1BIT_CLIP             0
4403 #endif
4404 
4405 
4406 #ifndef CTX_ENABLE_SHADOW_BLUR
4407 #define CTX_ENABLE_SHADOW_BLUR    1
4408 #endif
4409 
4410 #ifndef CTX_GRADIENTS
4411 #define CTX_GRADIENTS             1
4412 #endif
4413 
4414 #ifndef CTX_ALIGNED_STRUCTS
4415 #define CTX_ALIGNED_STRUCTS       1
4416 #endif
4417 
4418 #ifndef CTX_GRADIENT_CACHE
4419 #define CTX_GRADIENT_CACHE        1
4420 #endif
4421 
4422 #ifndef CTX_FONTS_FROM_FILE
4423 #define CTX_FONTS_FROM_FILE  0
4424 #endif
4425 
4426 #ifndef CTX_GET_CONTENTS
4427 #if CTX_FONTS_FROM_FILE
4428 #define CTX_GET_CONTENTS    1
4429 #else
4430 #define CTX_GET_CONTENTS    0
4431 #endif
4432 #endif
4433 
4434 #ifndef CTX_FORMATTER
4435 #define CTX_FORMATTER       1
4436 #endif
4437 
4438 #ifndef CTX_PARSER
4439 #define CTX_PARSER          1
4440 #endif
4441 
4442 #ifndef CTX_CURRENT_PATH
4443 #define CTX_CURRENT_PATH    1
4444 #endif
4445 
4446 #ifndef CTX_XML
4447 #define CTX_XML             1
4448 #endif
4449 
4450 #ifndef CTX_VT
4451 #define CTX_VT              0
4452 #endif
4453 
4454 /* when ctx_math is defined, which it is by default, we use ctx' own
4455  * implementations of math functions, instead of relying on math.h
4456  * the possible inlining gives us a slight speed-gain, and on
4457  * embedded platforms guarantees that we do not do double precision
4458  * math.
4459  */
4460 #ifndef CTX_MATH
4461 #define CTX_MATH           1  // use internal fast math for sqrt,sin,cos,atan2f etc.
4462 #endif
4463 
4464 #define ctx_log(fmt, ...)
4465 //#define ctx_log(str, a...) fprintf(stderr, str, ##a)
4466 
4467 /* the initial journal size - for both rasterizer
4468  * edgelist and drawlist.
4469  */
4470 #ifndef CTX_MIN_JOURNAL_SIZE
4471 #define CTX_MIN_JOURNAL_SIZE      512
4472 #endif
4473 
4474 /* The maximum size we permit the drawlist to grow to,
4475  * the memory used is this number * 9, where 9 is sizeof(CtxEntry)
4476  */
4477 #ifndef CTX_MAX_JOURNAL_SIZE
4478 //#define CTX_MAX_JOURNAL_SIZE   CTX_MIN_JOURNAL_SIZE
4479 #define CTX_MAX_JOURNAL_SIZE 1024*1024*16
4480 #endif
4481 
4482 #ifndef CTX_DRAWLIST_STATIC
4483 #define CTX_DRAWLIST_STATIC  0
4484 #endif
4485 
4486 #ifndef CTX_MIN_EDGE_LIST_SIZE
4487 #define CTX_MIN_EDGE_LIST_SIZE   1024
4488 #endif
4489 
4490 #ifndef CTX_RASTERIZER_AA
4491 #define CTX_RASTERIZER_AA 15   // vertical-AA of CTX_ANTIALIAS_DEFAULT
4492 #endif
4493 
4494 /* The maximum complexity of a single path
4495  */
4496 #ifndef CTX_MAX_EDGE_LIST_SIZE
4497 #define CTX_MAX_EDGE_LIST_SIZE  CTX_MIN_EDGE_LIST_SIZE
4498 #endif
4499 
4500 #ifndef CTX_STRINGPOOL_SIZE
4501   // XXX should be possible to make zero and disappear when codepaths not in use
4502   //     to save size, for card10 this is defined as a low number (some text
4503   //     properties still make use of it)
4504   //
4505   //     for desktop-use this should be fully dynamic, possibly
4506   //     with chained pools, gradients are stored here.
4507 #define CTX_STRINGPOOL_SIZE     1000 //
4508 #endif
4509 
4510 /* whether we dither or not for gradients
4511  */
4512 #ifndef CTX_DITHER
4513 #define CTX_DITHER 0
4514 #endif
4515 
4516 /*  only source-over clear and copy will work, the API still
4517  *  through - but the renderer is limited, for use to measure
4518  *  size and possibly in severely constrained ROMs.
4519  */
4520 #ifndef CTX_BLENDING_AND_COMPOSITING
4521 #define CTX_BLENDING_AND_COMPOSITING 1
4522 #endif
4523 
4524 /*  this forces the inlining of some performance
4525  *  critical paths.
4526  */
4527 #ifndef CTX_FORCE_INLINES
4528 #define CTX_FORCE_INLINES               1
4529 #endif
4530 
4531 /* create one-off inlined inner loop for normal blend mode (for floating point,
4532  * for RGBA8 manual loops overrrides
4533  */
4534 #ifndef CTX_INLINED_NORMAL
4535 #define CTX_INLINED_NORMAL      1
4536 #endif
4537 
4538 #ifndef CTX_INLINED_GRADIENTS
4539 #define CTX_INLINED_GRADIENTS   1
4540 #endif
4541 
4542 #ifndef CTX_BRAILLE_TEXT
4543 #define CTX_BRAILLE_TEXT        0
4544 #endif
4545 
4546 /* Build code paths for grayscale rasterization, this makes clipping
4547  * faster.
4548  */
4549 #ifndef CTX_NATIVE_GRAYA8
4550 #define CTX_NATIVE_GRAYA8       1
4551 #endif
4552 
4553 /* enable CMYK rasterization targets
4554  */
4555 #ifndef CTX_ENABLE_CMYK
4556 #define CTX_ENABLE_CMYK         1
4557 #endif
4558 
4559 /* enable color management, slightly increases CtxColor struct size, can
4560  * be disabled for microcontrollers.
4561  */
4562 #ifndef CTX_ENABLE_CM
4563 #define CTX_ENABLE_CM           1
4564 #endif
4565 
4566 #ifndef CTX_EVENTS
4567 #define CTX_EVENTS              1
4568 #endif
4569 
4570 #ifndef CTX_LIMIT_FORMATS
4571 #define CTX_LIMIT_FORMATS       0
4572 #endif
4573 
4574 #ifndef CTX_ENABLE_FLOAT
4575 #define CTX_ENABLE_FLOAT        0
4576 #endif
4577 
4578 /* by default ctx includes all pixel formats, on microcontrollers
4579  * it can be useful to slim down code and runtime size by only
4580  * defining the used formats, set CTX_LIMIT_FORMATS to 1, and
4581  * manually add CTX_ENABLE_ flags for each of them.
4582  */
4583 #if CTX_LIMIT_FORMATS
4584 #if CTX_NATIVE_GRAYA8
4585 #define CTX_ENABLE_GRAYA8               1
4586 #define CTX_ENABLE_GRAY8                1
4587 #endif
4588 #else
4589 
4590 #define CTX_ENABLE_GRAY1                1
4591 #define CTX_ENABLE_GRAY2                1
4592 #define CTX_ENABLE_GRAY4                1
4593 #define CTX_ENABLE_GRAY8                1
4594 #define CTX_ENABLE_GRAYA8               1
4595 #define CTX_ENABLE_GRAYF                1
4596 #define CTX_ENABLE_GRAYAF               1
4597 
4598 #define CTX_ENABLE_RGB8                 1
4599 #define CTX_ENABLE_RGBA8                1
4600 #define CTX_ENABLE_BGRA8                1
4601 #define CTX_ENABLE_RGB332               1
4602 #define CTX_ENABLE_RGB565               1
4603 #define CTX_ENABLE_RGB565_BYTESWAPPED   1
4604 #define CTX_ENABLE_RGBAF                1
4605 #ifdef CTX_ENABLE_FLOAT
4606 #undef CTX_ENABLE_FLOAT
4607 #endif
4608 #define CTX_ENABLE_FLOAT                1
4609 #define CTX_ENABLE_YUV420               1
4610 
4611 #if CTX_ENABLE_CMYK
4612 #define CTX_ENABLE_CMYK8                1
4613 #define CTX_ENABLE_CMYKA8               1
4614 #define CTX_ENABLE_CMYKAF               1
4615 #endif
4616 #endif
4617 
4618 #ifndef CTX_RGB565_ALPHA
4619 #define CTX_RGB565_ALPHA                0   // when enabled pure purple is transparent,
4620                                             // for a ~15% overall performance hit
4621 #endif
4622 
4623 #ifndef CTX_RGB332_ALPHA
4624 #define CTX_RGB332_ALPHA                0   // when enabled pure purple is transparent,
4625                                             // for a ~15% overall performance hit
4626 #endif
4627 
4628 /* by including ctx-font-regular.h, or ctx-font-mono.h the
4629  * built-in fonts using ctx drawlist encoding is enabled
4630  */
4631 #if CTX_FONT_regular || CTX_FONT_mono || CTX_FONT_bold \
4632   || CTX_FONT_italic || CTX_FONT_sans || CTX_FONT_serif \
4633   || CTX_FONT_ascii
4634 #ifndef CTX_FONT_ENGINE_CTX
4635 #define CTX_FONT_ENGINE_CTX        1
4636 #endif
4637 #endif
4638 
4639 #ifndef CTX_FONT_ENGINE_CTX_FS
4640 #define CTX_FONT_ENGINE_CTX_FS 0
4641 #endif
4642 
4643 /* If stb_strutype.h is included before ctx.h add integration code for runtime loading
4644  * of opentype fonts.
4645  */
4646 #ifdef __STB_INCLUDE_STB_TRUETYPE_H__
4647 #ifndef CTX_FONT_ENGINE_STB
4648 #define CTX_FONT_ENGINE_STB        1
4649 #endif
4650 #else
4651 #define CTX_FONT_ENGINE_STB        0
4652 #endif
4653 
4654 #ifdef _BABL_H
4655 #define CTX_BABL 1
4656 #else
4657 #define CTX_BABL 0
4658 #endif
4659 
4660 #ifndef CTX_ALWAYS_USE_NEAREST_FOR_SCALE1
4661 #define CTX_ALWAYS_USE_NEAREST_FOR_SCALE1 1
4662 #endif
4663 
4664 /* force add format if we have shape cache */
4665 #if CTX_SHAPE_CACHE
4666 #ifdef CTX_ENABLE_GRAY8
4667 #undef CTX_ENABLE_GRAY8
4668 #endif
4669 #define CTX_ENABLE_GRAY8  1
4670 #endif
4671 
4672 /* include the bitpack packer, can be opted out of to decrease code size
4673  */
4674 #ifndef CTX_BITPACK_PACKER
4675 #define CTX_BITPACK_PACKER 0
4676 #endif
4677 
4678 /* enable RGBA8 intermediate format for
4679  *the indirectly implemented pixel-formats.
4680  */
4681 #if CTX_ENABLE_GRAY1 | CTX_ENABLE_GRAY2 | CTX_ENABLE_GRAY4 | CTX_ENABLE_RGB565 | CTX_ENABLE_RGB565_BYTESWAPPED | CTX_ENABLE_RGB8 | CTX_ENABLE_RGB332
4682 
4683   #ifdef CTX_ENABLE_RGBA8
4684     #undef CTX_ENABLE_RGBA8
4685   #endif
4686   #define CTX_ENABLE_RGBA8  1
4687 #endif
4688 
4689 #ifdef CTX_ENABLE_CMYKF
4690 #ifdef CTX_ENABLE_FLOAT
4691 #undef CTX_ENABLE_FLOAT
4692 #endif
4693 #define CTX_ENABLE_FLOAT 1
4694 #endif
4695 
4696 #ifdef CTX_ENABLE_GRAYF
4697 #ifdef CTX_ENABLE_FLOAT
4698 #undef CTX_ENABLE_FLOAT
4699 #endif
4700 #define CTX_ENABLE_FLOAT 1
4701 #endif
4702 
4703 #ifdef CTX_ENABLE_GRAYAF
4704 #ifdef CTX_ENABLE_FLOAT
4705 #undef CTX_ENABLE_FLOAT
4706 #endif
4707 #define CTX_ENABLE_FLOAT 1
4708 #endif
4709 
4710 #ifdef CTX_ENABLE_RGBAF
4711 #ifdef CTX_ENABLE_FLOAT
4712 #undef CTX_ENABLE_FLOAT
4713 #endif
4714 #define CTX_ENABLE_FLOAT 1
4715 #endif
4716 
4717 #ifdef CTX_ENABLE_CMYKAF
4718 #ifdef CTX_ENABLE_FLOAT
4719 #undef CTX_ENABLE_FLOAT
4720 #endif
4721 #define CTX_ENABLE_FLOAT 1
4722 #endif
4723 
4724 #ifdef CTX_ENABLE_CMYKF
4725 #ifdef CTX_ENABLE_FLOAT
4726 #undef CTX_ENABLE_FLOAT
4727 #endif
4728 #define CTX_ENABLE_FLOAT 1
4729 #endif
4730 
4731 
4732 /* enable cmykf which is cmyk intermediate format
4733  */
4734 #ifdef CTX_ENABLE_CMYK8
4735 #ifdef CTX_ENABLE_CMYKF
4736 #undef CTX_ENABLE_CMYKF
4737 #endif
4738 #define CTX_ENABLE_CMYKF  1
4739 #endif
4740 #ifdef CTX_ENABLE_CMYKA8
4741 #ifdef CTX_ENABLE_CMYKF
4742 #undef CTX_ENABLE_CMYKF
4743 #endif
4744 #define CTX_ENABLE_CMYKF  1
4745 #endif
4746 
4747 #ifdef CTX_ENABLE_CMYKF8
4748 #ifdef CTX_ENABLE_CMYK
4749 #undef CTX_ENABLE_CMYK
4750 #endif
4751 #define CTX_ENABLE_CMYK   1
4752 #endif
4753 
4754 #define CTX_PI                              3.141592653589793f
4755 #ifndef CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS
4756 #define CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS  400
4757 #endif
4758 
4759 #ifndef CTX_MAX_FRAMEBUFFER_WIDTH
4760 #define CTX_MAX_FRAMEBUFFER_WIDTH 2560
4761 #endif
4762 
4763 #ifndef CTX_MAX_FONTS
4764 #define CTX_MAX_FONTS            3
4765 #endif
4766 
4767 #ifndef CTX_MAX_STATES
4768 #define CTX_MAX_STATES           10
4769 #endif
4770 
4771 #ifndef CTX_MAX_EDGES
4772 #define CTX_MAX_EDGES            257
4773 #endif
4774 
4775 #ifndef CTX_MAX_LINGERING_EDGES
4776 #define CTX_MAX_LINGERING_EDGES  64
4777 #endif
4778 
4779 
4780 #ifndef CTX_MAX_PENDING
4781 #define CTX_MAX_PENDING          128
4782 #endif
4783 
4784 #ifndef CTX_MAX_TEXTURES
4785 #define CTX_MAX_TEXTURES         32
4786 #endif
4787 
4788 #ifndef CTX_HASH_ROWS
4789 #define CTX_HASH_ROWS            8
4790 #endif
4791 #ifndef CTX_HASH_COLS
4792 #define CTX_HASH_COLS            8
4793 #endif
4794 
4795 #ifndef CTX_MAX_THREADS
4796 #define CTX_MAX_THREADS          8 // runtime is max of cores/2 and this
4797 #endif
4798 
4799 #ifndef CTX_FRAGMENT_SPECIALIZE
4800 #define CTX_FRAGMENT_SPECIALIZE 1
4801 #endif
4802 
4803 #define CTX_RASTERIZER_EDGE_MULTIPLIER  1024
4804                                         // increasing this to 2048
4805                                         // removes artifacts in top half of res-diagram -
4806                                         // but reduces maximum available buffer width
4807 #ifndef CTX_IMPLEMENTATION
4808 #define CTX_IMPLEMENTATION 0
4809 #else
4810 #undef CTX_IMPLEMENTATION
4811 #define CTX_IMPLEMENTATION 1
4812 #endif
4813 
4814 
4815 #ifdef CTX_RASTERIZER
4816 #if CTX_RASTERIZER==0
4817 #if CTX_SDL || CTX_FB
4818 #undef CTX_RASTERIZER
4819 #define CTX_RASTERIZER 1
4820 #endif
4821 #else
4822 #undef CTX_RASTERIZER
4823 #define CTX_RASTERIZER 1
4824 #endif
4825 #endif
4826 
4827 #if CTX_RASTERIZER
4828 #ifndef CTX_COMPOSITE
4829 #define CTX_COMPOSITE 1
4830 #endif
4831 #else
4832 #ifndef CTX_COMPOSITE
4833 #define CTX_COMPOSITE 0
4834 #endif
4835 #endif
4836 
4837 #ifndef CTX_GRADIENT_CACHE_ELEMENTS
4838 #define CTX_GRADIENT_CACHE_ELEMENTS 256
4839 #endif
4840 
4841 #ifndef CTX_PARSER_MAX_ARGS
4842 #define CTX_PARSER_MAX_ARGS 20
4843 #endif
4844 
4845 
4846 #ifndef CTX_SCREENSHOT
4847 #define CTX_SCREENSHOT 0
4848 #endif
4849 
4850 #ifndef CTX_ALSA_AUDIO
4851 #define CTX_ALSA_AUDIO 0
4852 #endif
4853 
4854 #if NO_ALSA
4855 #undef CTX_ALSA_AUDIO
4856 #define CTX_ALSA_AUDIO 0
4857 #endif
4858 
4859 #ifndef CTX_AUDIO
4860 #define CTX_AUDIO 0
4861 #endif
4862 
4863 #ifndef CTX_TILED
4864 #if CTX_SDL || CTX_FB || CTX_KMS
4865 #define CTX_TILED 1
4866 #else
4867 #define CTX_TILED 0
4868 #endif
4869 #endif
4870 
4871 #ifndef CTX_THREADS
4872 #if CTX_TILED
4873 #define CTX_THREADS 1
4874 #else
4875 #define CTX_THREADS 0
4876 #endif
4877 #endif
4878 
4879 #if CTX_THREADS
4880 #include <pthread.h>
4881 #define mtx_lock pthread_mutex_lock
4882 #define mtx_unlock pthread_mutex_unlock
4883 #define mtx_t pthread_mutex_t
4884 #define cnd_t pthread_cond_t
4885 #define mtx_plain NULL
4886 #define mtx_init pthread_mutex_init
4887 #define cnd_init(a) pthread_cond_init(a,NULL)
4888 #define cnd_wait pthread_cond_wait
4889 #define cnd_broadcast pthread_cond_broadcast
4890 #define thrd_create(tid, tiled_render_fun, args) pthread_create(tid, NULL, tiled_render_fun, args)
4891 #define thrd_t pthread_t
4892 #endif
4893 
4894 
4895  /* Copyright (C) 2020 Øyvind Kolås <pippin@gimp.org>
4896  */
4897 
4898 #if CTX_FORMATTER
4899 
4900 /* returns the maximum string length including terminating \0 */
4901 int ctx_a85enc_len (int input_length);
4902 int ctx_a85enc (const void *srcp, char *dst, int count);
4903 
4904 #if CTX_PARSER
4905 
4906 int ctx_a85dec (const char *src, char *dst, int count);
4907 int ctx_a85len (const char *src, int count);
4908 #endif
4909 
4910 #endif
4911 #ifndef __CTX_EXTRA_H
4912 #define __CTX_EXTRA_H
4913 
4914 #if CTX_FORCE_INLINES
4915 #define CTX_INLINE inline __attribute__((always_inline))
4916 #else
4917 #define CTX_INLINE inline
4918 #endif
4919 
4920 
4921 #define CTX_CLAMP(val,min,max) ((val)<(min)?(min):(val)>(max)?(max):(val))
ctx_mini(int a,int b)4922 static CTX_INLINE int   ctx_mini (int a, int b)     { return (a < b) * a + (a >= b) * b; }
ctx_minf(float a,float b)4923 static CTX_INLINE float ctx_minf (float a, float b) { return (a < b) * a + (a >= b) * b; }
ctx_maxi(int a,int b)4924 static CTX_INLINE int   ctx_maxi (int a, int b)     { return (a > b) * a + (a <= b) * b; }
ctx_maxf(float a,float b)4925 static CTX_INLINE float ctx_maxf (float a, float b) { return (a > b) * a + (a <= b) * b; }
4926 
4927 
4928 typedef enum CtxOutputmode
4929 {
4930   CTX_OUTPUT_MODE_QUARTER,
4931   CTX_OUTPUT_MODE_BRAILLE,
4932   CTX_OUTPUT_MODE_SIXELS,
4933   CTX_OUTPUT_MODE_GRAYS,
4934   CTX_OUTPUT_MODE_CTX,
4935   CTX_OUTPUT_MODE_CTX_COMPACT,
4936   CTX_OUTPUT_MODE_UI
4937 } CtxOutputmode;
4938 
4939 
4940 
4941 
4942 
4943 
ctx_pow2(float a)4944 static inline float ctx_pow2 (float a) { return a * a; }
4945 #if CTX_MATH
4946 
4947 static CTX_INLINE float
ctx_fabsf(float x)4948 ctx_fabsf (float x)
4949 {
4950   union
4951   {
4952     float f;
4953     uint32_t i;
4954   } u = { x };
4955   u.i &= 0x7fffffff;
4956   return u.f;
4957 }
4958 
4959 static CTX_INLINE float
ctx_invsqrtf(float x)4960 ctx_invsqrtf (float x)
4961 {
4962   union
4963   {
4964     float f;
4965     uint32_t i;
4966   } u = { x };
4967   float xhalf = 0.5f * x;
4968   int i=u.i;
4969   i = 0x5f3759df - (i >> 1);
4970   x = u.f;
4971   x *= (1.5f - xhalf * x * x);
4972   x *= (1.5f - xhalf * x * x); //repeating Newton-Raphson step for higher precision
4973   return x;
4974 }
4975 
4976 static CTX_INLINE float
ctx_invsqrtf_fast(float x)4977 ctx_invsqrtf_fast (float x)
4978 {
4979   union
4980   {
4981     float f;
4982     uint32_t i;
4983   } u = { x };
4984 
4985 //float xhalf = 0.5f * x;
4986   int i=u.i;
4987   i = 0x5f3759df - (i >> 1);
4988   x = u.f;
4989 //x *= (1.5f - xhalf * x * x);
4990   return x;
4991 }
4992 
ctx_sqrtf(float a)4993 CTX_INLINE static float ctx_sqrtf (float a)
4994 {
4995   return 1.0f/ctx_invsqrtf (a);
4996 }
4997 
ctx_sqrtf_fast(float a)4998 CTX_INLINE static float ctx_sqrtf_fast (float a)
4999 {
5000   return 1.0f/ctx_invsqrtf_fast (a);
5001 }
5002 
ctx_hypotf(float a,float b)5003 CTX_INLINE static float ctx_hypotf (float a, float b)
5004 {
5005   return ctx_sqrtf (ctx_pow2 (a)+ctx_pow2 (b) );
5006 }
5007 
ctx_hypotf_fast(float a,float b)5008 CTX_INLINE static float ctx_hypotf_fast (float a, float b)
5009 {
5010   return ctx_sqrtf_fast (ctx_pow2 (a)+ctx_pow2 (b) );
5011 }
5012 
5013 CTX_INLINE static float
ctx_sinf(float x)5014 ctx_sinf (float x)
5015 {
5016   if (x < -CTX_PI * 2)
5017     {
5018       x = -x;
5019       long ix = x / (CTX_PI * 2);
5020       x = x - ix * CTX_PI * 2;
5021       x = -x;
5022     }
5023   if (x < -CTX_PI * 1000)
5024   {
5025     x = -0.5;
5026   }
5027   if (x > CTX_PI * 1000)
5028   {
5029           // really large numbers tend to cause practically inifinite
5030           // loops since the > CTX_PI * 2 seemingly fails
5031     x = 0.5;
5032   }
5033   if (x > CTX_PI * 2)
5034     {
5035       long ix = x / (CTX_PI * 2);
5036       x = x - (ix * CTX_PI * 2);
5037     }
5038   while (x < -CTX_PI)
5039     { x += CTX_PI * 2; }
5040   while (x > CTX_PI)
5041     { x -= CTX_PI * 2; }
5042 
5043   /* source : http://mooooo.ooo/chebyshev-sine-approximation/ */
5044   float coeffs[]=
5045   {
5046     -0.10132118f,           // x
5047       0.0066208798f,         // x^3
5048       -0.00017350505f,        // x^5
5049       0.0000025222919f,      // x^7
5050       -0.000000023317787f,    // x^9
5051       0.00000000013291342f
5052     }; // x^11
5053   float x2 = x*x;
5054   float p11 = coeffs[5];
5055   float p9  = p11*x2 + coeffs[4];
5056   float p7  = p9*x2  + coeffs[3];
5057   float p5  = p7*x2  + coeffs[2];
5058   float p3  = p5*x2  + coeffs[1];
5059   float p1  = p3*x2  + coeffs[0];
5060   return (x - CTX_PI + 0.00000008742278f) *
5061          (x + CTX_PI - 0.00000008742278f) * p1 * x;
5062 }
5063 
ctx_atan2f(float y,float x)5064 static CTX_INLINE float ctx_atan2f (float y, float x)
5065 {
5066   float atan, z;
5067   if ( x == 0.0f )
5068     {
5069       if ( y > 0.0f )
5070         { return CTX_PI/2; }
5071       if ( y == 0.0f )
5072         { return 0.0f; }
5073       return -CTX_PI/2;
5074     }
5075   z = y/x;
5076   if ( ctx_fabsf ( z ) < 1.0f )
5077     {
5078       atan = z/ (1.0f + 0.28f*z*z);
5079       if (x < 0.0f)
5080         {
5081           if ( y < 0.0f )
5082             { return atan - CTX_PI; }
5083           return atan + CTX_PI;
5084         }
5085     }
5086   else
5087     {
5088       atan = CTX_PI/2 - z/ (z*z + 0.28f);
5089       if ( y < 0.0f ) { return atan - CTX_PI; }
5090     }
5091   return atan;
5092 }
5093 
5094 
ctx_atanf(float a)5095 static CTX_INLINE float ctx_atanf (float a)
5096 {
5097   return ctx_atan2f ( (a), 1.0f);
5098 }
5099 
ctx_asinf(float x)5100 static CTX_INLINE float ctx_asinf (float x)
5101 {
5102   return ctx_atanf ( (x) * (ctx_invsqrtf (1.0f-ctx_pow2 (x) ) ) );
5103 }
5104 
ctx_acosf(float x)5105 static CTX_INLINE float ctx_acosf (float x)
5106 {
5107   return ctx_atanf ( (ctx_sqrtf (1.0f-ctx_pow2 (x) ) / (x) ) );
5108 }
5109 
ctx_cosf(float a)5110 CTX_INLINE static float ctx_cosf (float a)
5111 {
5112   return ctx_sinf ( (a) + CTX_PI/2.0f);
5113 }
5114 
ctx_tanf(float a)5115 static CTX_INLINE float ctx_tanf (float a)
5116 {
5117   return (ctx_cosf (a) /ctx_sinf (a) );
5118 }
5119 static CTX_INLINE float
ctx_floorf(float x)5120 ctx_floorf (float x)
5121 {
5122   return (int)x; // XXX
5123 }
5124 static CTX_INLINE float
ctx_expf(float x)5125 ctx_expf (float x)
5126 {
5127   union { uint32_t i; float f; } v =
5128     {  (uint32_t)( (1 << 23) * (x + 183.1395965f)) };
5129   return v.f;
5130 }
5131 
5132 /* define more trig based on having sqrt, sin and atan2 */
5133 
5134 #else
5135 #if !__COSMOPOLITAN__
5136 #include <math.h>
5137 #endif
ctx_fabsf(float x)5138 static inline float ctx_fabsf (float x)           { return fabsf (x); }
ctx_floorf(float x)5139 static inline float ctx_floorf (float x)          { return floorf (x); }
ctx_sinf(float x)5140 static inline float ctx_sinf (float x)            { return sinf (x); }
ctx_atan2f(float y,float x)5141 static inline float ctx_atan2f (float y, float x) { return atan2f (y, x); }
ctx_hypotf(float a,float b)5142 static inline float ctx_hypotf (float a, float b) { return hypotf (a, b); }
ctx_acosf(float a)5143 static inline float ctx_acosf (float a)           { return acosf (a); }
ctx_cosf(float a)5144 static inline float ctx_cosf (float a)            { return cosf (a); }
ctx_tanf(float a)5145 static inline float ctx_tanf (float a)            { return tanf (a); }
ctx_expf(float p)5146 static inline float ctx_expf (float p)            { return expf (p); }
ctx_sqrtf(float a)5147 static inline float ctx_sqrtf (float a)           { return sqrtf (a); }
5148 #endif
5149 
_ctx_parse_float(const char * str,char ** endptr)5150 static inline float _ctx_parse_float (const char *str, char **endptr)
5151 {
5152   return strtod (str, endptr); /* XXX: , vs . problem in some locales */
5153 }
5154 
5155 const char *ctx_get_string (Ctx *ctx, uint32_t hash);
5156 void ctx_set_string (Ctx *ctx, uint32_t hash, const char *value);
5157 typedef struct _CtxColor CtxColor;
5158 
5159 void
5160 ctx_matrix_translate (CtxMatrix *matrix, float x, float y);
5161 
5162 
5163 void ctx_get_matrix (Ctx *ctx, CtxMatrix *matrix);
5164 void ctx_set_matrix (Ctx *ctx, CtxMatrix *matrix);
5165 int _ctx_is_rasterizer (Ctx *ctx);
5166 
5167 int ctx_color (Ctx *ctx, const char *string);
5168 typedef struct _CtxState CtxState;
5169 CtxColor *ctx_color_new ();
5170 CtxState *ctx_get_state (Ctx *ctx);
5171 void ctx_color_get_rgba (CtxState *state, CtxColor *color, float *out);
5172 void ctx_color_set_rgba (CtxState *state, CtxColor *color, float r, float g, float b, float a);
5173 void ctx_color_free (CtxColor *color);
5174 void ctx_set_color (Ctx *ctx, uint32_t hash, CtxColor *color);
5175 int  ctx_get_color (Ctx *ctx, uint32_t hash, CtxColor *color);
5176 int  ctx_color_set_from_string (Ctx *ctx, CtxColor *color, const char *string);
5177 
5178 int ctx_color_is_transparent (CtxColor *color);
5179 int ctx_utf8_len (const unsigned char first_byte);
5180 
5181 void ctx_user_to_device          (Ctx *ctx, float *x, float *y);
5182 void ctx_user_to_device_distance (Ctx *ctx, float *x, float *y);
5183 const char *ctx_utf8_skip (const char *s, int utf8_length);
5184 int ctx_is_set_now (Ctx *ctx, uint32_t hash);
5185 void ctx_set_size (Ctx *ctx, int width, int height);
5186 
ctx_matrix_get_scale(CtxMatrix * matrix)5187 static inline float ctx_matrix_get_scale (CtxMatrix *matrix)
5188 {
5189    return ctx_maxf (ctx_maxf (ctx_fabsf (matrix->m[0][0]),
5190                          ctx_fabsf (matrix->m[0][1]) ),
5191                ctx_maxf (ctx_fabsf (matrix->m[1][0]),
5192                          ctx_fabsf (matrix->m[1][1]) ) );
5193 }
5194 
5195 #if CTX_GET_CONTENTS
5196 int
5197 _ctx_file_get_contents (const char     *path,
5198                         unsigned char **contents,
5199                         long           *length);
5200 #endif
5201 
5202 #if CTX_FONTS_FROM_FILE
5203 int   ctx_load_font_ttf_file (const char *name, const char *path);
5204 #endif
5205 
5206 #if CTX_BABL
5207 void ctx_rasterizer_colorspace_babl (CtxState      *state,
5208                                      CtxColorSpace  space_slot,
5209                                      const Babl    *space);
5210 #endif
5211 void ctx_rasterizer_colorspace_icc (CtxState      *state,
5212                                     CtxColorSpace  space_slot,
5213                                     char          *icc_data,
5214                                     int            icc_length);
5215 
5216 
5217 CtxBuffer *ctx_buffer_new_bare (void);
5218 
5219 void ctx_buffer_set_data (CtxBuffer *buffer,
5220                           void *data, int width, int height,
5221                           int stride,
5222                           CtxPixelFormat pixel_format,
5223                           void (*freefunc) (void *pixels, void *user_data),
5224                           void *user_data);
5225 
5226 int _ctx_set_frame (Ctx *ctx, int frame);
5227 int _ctx_frame (Ctx *ctx);
5228 
5229 
5230 void ctx_exit (Ctx *ctx);
5231 void ctx_list_backends(void);
5232 int ctx_pixel_format_ebpp (CtxPixelFormat format);
5233 
5234 #endif
5235 #ifndef __CTX_CONSTANTS
5236 #define __CTX_CONSTANTS
5237 
5238 #define TOKENHASH(a)    ((uint64_t)a)
5239 
5240 #define CTX_strokeSource TOKENHASH(3387288669)
5241 #define CTX_add_stop TOKENHASH(3572486242)
5242 #define CTX_addStop TOKENHASH(3805374936)
5243 #define CTX_alphabetic TOKENHASH(2558771929)
5244 #define CTX_arc TOKENHASH(7298)
5245 #define CTX_arc_to TOKENHASH(4010563993)
5246 #define CTX_arcTo TOKENHASH(4138935887)
5247 #define CTX_begin_path TOKENHASH(3275811535)
5248 #define CTX_beginPath TOKENHASH(2384638508)
5249 #define CTX_bevel TOKENHASH(25538884)
5250 #define CTX_bottom TOKENHASH(905225156)
5251 #define CTX_cap TOKENHASH(32838)
5252 #define CTX_center TOKENHASH(1219785030)
5253 #define CTX_clear TOKENHASH(37825286)
5254 #define CTX_color TOKENHASH(38757318)
5255 #define CTX_copy TOKENHASH(1672134)
5256 #define CTX_clip TOKENHASH(1067782)
5257 #define CTX_close_path TOKENHASH(3215881683)
5258 #define CTX_closePath TOKENHASH(3625577848)
5259 #define CTX_cmyka TOKENHASH(2870086)
5260 #define CTX_cmyk TOKENHASH(772934)
5261 #define CTX_cmykaS TOKENHASH(3116500921)
5262 #define CTX_cmykS TOKENHASH(934005574)
5263 #define CTX_color TOKENHASH(38757318)
5264 #define CTX_blending TOKENHASH(3402343403)
5265 #define CTX_blend TOKENHASH(9317124)
5266 #define CTX_blending_mode TOKENHASH(4000829592)
5267 #define CTX_blendingMode TOKENHASH(2577020122)
5268 #define CTX_blend_mode TOKENHASH(2229422236)
5269 #define CTX_blendMode TOKENHASH(3450578624)
5270 #define CTX_composite TOKENHASH(2191186513)
5271 #define CTX_compositing_mode TOKENHASH(3415700633)
5272 #define CTX_compositingMode TOKENHASH(3625102151)
5273 #define CTX_curve_to TOKENHASH(3569729066)
5274 #define CTX_curveTo TOKENHASH(3536162037)
5275 #define CTX_darken TOKENHASH(950767688)
5276 #define CTX_defineGlyph TOKENHASH(3698027829)
5277 #define CTX_defineTexture TOKENHASH(4201008335)
5278 #define CTX_kerningPair TOKENHASH(3655936472)
5279 #define CTX_destinationIn TOKENHASH(2718725020)
5280 #define CTX_destination_in TOKENHASH(3351938654)
5281 #define CTX_destinationAtop TOKENHASH(3609906960)
5282 #define CTX_destination_atop TOKENHASH(2783515582)
5283 #define CTX_destinationOver TOKENHASH(2378926016)
5284 #define CTX_destination_over TOKENHASH(2856771196)
5285 #define CTX_destinationOut TOKENHASH(3944490553)
5286 #define CTX_destination_out TOKENHASH(3021444620)
5287 #define CTX_difference TOKENHASH(2530251746)
5288 #define CTX_done TOKENHASH(357320)
5289 #define CTX_drgba TOKENHASH(2243720)
5290 #define CTX_drgb TOKENHASH(146568)
5291 #define CTX_drgbaS TOKENHASH(2541895879)
5292 #define CTX_drgbS TOKENHASH(933379208)
5293 #define CTX_end TOKENHASH(9098)
5294 #define CTX_endfun TOKENHASH(983966602)
5295 #define CTX_end_group TOKENHASH(2564160724)
5296 #define CTX_endGroup TOKENHASH(3639210663)
5297 #define CTX_even_odd TOKENHASH(2587574889)
5298 #define CTX_evenOdd TOKENHASH(4065502508)
5299 #define CTX_exit TOKENHASH(1330698)
5300 #define CTX_fill TOKENHASH(811596)
5301 #define CTX_fill_rule TOKENHASH(3026141741)
5302 #define CTX_fillRule TOKENHASH(2727819936)
5303 #define CTX_flush TOKENHASH(18066188)
5304 #define CTX_font TOKENHASH(1340364)
5305 #define CTX_font_size TOKENHASH(3138232552)
5306 #define CTX_setFontSize TOKENHASH(2794810212)
5307 #define CTX_fontSize TOKENHASH(2516141542)
5308 #define CTX_function TOKENHASH(2157387644)
5309 #define CTX_getkey TOKENHASH(1688969550)
5310 #define CTX_global_alpha TOKENHASH(4195339170)
5311 #define CTX_globalAlpha TOKENHASH(3503999095)
5312 #define CTX_glyph TOKENHASH(17877774)
5313 #define CTX_gradient_add_stop TOKENHASH(2527862800)
5314 #define CTX_gradientAddStop TOKENHASH(2707733066)
5315 #define CTX_graya TOKENHASH(3738766)
5316 #define CTX_gray TOKENHASH(1641614)
5317 #define CTX_grayaS TOKENHASH(3152913809)
5318 #define CTX_grayS TOKENHASH(934874254)
5319 #define CTX_hanging TOKENHASH(3379012612)
5320 #define CTX_height TOKENHASH(1359432016)
5321 #define CTX_hor_line_to TOKENHASH(3576305368)
5322 #define CTX_horLineTo TOKENHASH(2768557894)
5323 #define CTX_hue TOKENHASH(11600)
5324 #define CTX_identity TOKENHASH(4244560551)
5325 #define CTX_ideographic TOKENHASH(4062138887)
5326 #define CTX_imageSmoothing TOKENHASH(3391439578)
5327 #define CTX_join TOKENHASH(936916)
5328 #define CTX_laba TOKENHASH(69720)
5329 #define CTX_lab TOKENHASH(4184)
5330 #define CTX_lcha TOKENHASH(82136)
5331 #define CTX_lch TOKENHASH(16600)
5332 #define CTX_labaS TOKENHASH(933302360)
5333 #define CTX_labS TOKENHASH(29167704)
5334 #define CTX_lchaS TOKENHASH(933314776)
5335 #define CTX_lchS TOKENHASH(29180120)
5336 #define CTX_left TOKENHASH(1323352)
5337 #define CTX_lighter TOKENHASH(3085731552)
5338 #define CTX_lighten TOKENHASH(2243427702)
5339 #define CTX_linear_gradient TOKENHASH(2750495200)
5340 #define CTX_linearGradient TOKENHASH(2530643087)
5341 #define CTX_line_cap TOKENHASH(3442398380)
5342 #define CTX_lineCap TOKENHASH(4099906770)
5343 #define CTX_setLineCap TOKENHASH(3062640202)
5344 #define CTX_line_height TOKENHASH(2825006065)
5345 #define CTX_line_join TOKENHASH(2796226529)
5346 #define CTX_lineJoin TOKENHASH(3149521206)
5347 #define CTX_setLineJoin TOKENHASH(3876390174)
5348 #define CTX_line_spacing TOKENHASH(3474024390)
5349 #define CTX_line_to TOKENHASH(2950597468)
5350 #define CTX_lineTo TOKENHASH(3995194545)
5351 #define CTX_lineDash TOKENHASH(2275747153)
5352 #define CTX_lineDashOffset TOKENHASH(2164798257)
5353 #define CTX_line_width TOKENHASH(2644675969)
5354 #define CTX_lineWidth TOKENHASH(4067116285)
5355 #define CTX_setLineWidth TOKENHASH(3835759450)
5356 #define CTX_view_box TOKENHASH(3076034236)
5357 #define CTX_viewBox TOKENHASH(3661895848)
5358 #define CTX_middle TOKENHASH(360981082)
5359 #define CTX_miter TOKENHASH(38117978)
5360 #define CTX_miter_limit TOKENHASH(2692682139)
5361 #define CTX_miterLimit TOKENHASH(3784823268)
5362 #define CTX_move_to TOKENHASH(3482077014)
5363 #define CTX_moveTo TOKENHASH(3135948887)
5364 #define CTX_multiply TOKENHASH(2379318058)
5365 #define CTX_new_page TOKENHASH(3781461413)
5366 #define CTX_newPage TOKENHASH(3875814849)
5367 #define CTX_new_path TOKENHASH(4253517559)
5368 #define CTX_newPath TOKENHASH(2442450175)
5369 #define CTX_new_state TOKENHASH(3282144098)
5370 #define CTX_none TOKENHASH(357340)
5371 #define CTX_nonzero TOKENHASH(2230085415)
5372 #define CTX_non_zero TOKENHASH(3127422280)
5373 #define CTX_normal TOKENHASH(808293340)
5374 #define CTX_quad_to TOKENHASH(3896875982)
5375 #define CTX_quadTo TOKENHASH(3916306495)
5376 #define CTX_radial_gradient TOKENHASH(4226017763)
5377 #define CTX_radialGradient TOKENHASH(3218566169)
5378 #define CTX_rectangle TOKENHASH(4111149391)
5379 #define CTX_rect TOKENHASH(1317220)
5380 #define CTX_rel_arc_to TOKENHASH(2653353243)
5381 #define CTX_relArcTo TOKENHASH(2940381656)
5382 #define CTX_rel_curve_to TOKENHASH(2413603721)
5383 #define CTX_relCurveTo TOKENHASH(3745640049)
5384 #define CTX_rel_hor_line_to TOKENHASH(3292310681)
5385 #define CTX_relHorLineTo TOKENHASH(2661057467)
5386 #define CTX_relVerLineTo TOKENHASH(3868849192)
5387 #define CTX_rel_line_to TOKENHASH(2865414393)
5388 #define CTX_relLineTo TOKENHASH(2437091951)
5389 #define CTX_rel_move_to TOKENHASH(4169997481)
5390 #define CTX_relMoveTo TOKENHASH(2527491593)
5391 #define CTX_rel_quad_to TOKENHASH(4209276505)
5392 #define CTX_relQuadTo TOKENHASH(3961311908)
5393 #define CTX_rel_smoothq_to TOKENHASH(3923163705)
5394 #define CTX_relSmoothqTo TOKENHASH(2913202089)
5395 #define CTX_rel_smooth_to TOKENHASH(4229528839)
5396 #define CTX_relSmoothTo TOKENHASH(3458671695)
5397 #define CTX_rel_ver_line_to TOKENHASH(2484242991)
5398 #define CTX_restore TOKENHASH(2936409475)
5399 #define CTX_reset TOKENHASH(42309988)
5400 #define CTX_rgba TOKENHASH(70116)
5401 #define CTX_rgb TOKENHASH(4580)
5402 #define CTX_rgbaS TOKENHASH(933302756)
5403 #define CTX_rgbS TOKENHASH(29168100)
5404 #define CTX_right TOKENHASH(42482276)
5405 #define CTX_rotate TOKENHASH(377594852)
5406 #define CTX_round TOKENHASH(9350116)
5407 #define CTX_round_rectangle TOKENHASH(2766896494)
5408 #define CTX_roundRectangle TOKENHASH(3688082153)
5409 #define CTX_save TOKENHASH(372838)
5410 #define CTX_scale TOKENHASH(11274470)
5411 #define CTX_screen TOKENHASH(950374630)
5412 #define CTX_setkey TOKENHASH(1688969574)
5413 #define CTX_shadowBlur TOKENHASH(3119062524)
5414 #define CTX_shadowColor TOKENHASH(3795289804)
5415 #define CTX_shadowOffsetX TOKENHASH(4134163333)
5416 #define CTX_shadowOffsetY TOKENHASH(3519010566)
5417 #define CTX_smooth_quad_to TOKENHASH(3789701842)
5418 #define CTX_smoothQuadTo TOKENHASH(4024936051)
5419 #define CTX_smooth_to TOKENHASH(2307159288)
5420 #define CTX_smoothTo TOKENHASH(3997790061)
5421 #define CTX_sourceIn TOKENHASH(3513756343)
5422 #define CTX_source_in TOKENHASH(3936775584)
5423 #define CTX_sourceAtop TOKENHASH(3201391080)
5424 #define CTX_source_atop TOKENHASH(3568635572)
5425 #define CTX_sourceOut TOKENHASH(4217691207)
5426 #define CTX_source_out TOKENHASH(2998974401)
5427 #define CTX_sourceOver TOKENHASH(4071274055)
5428 #define CTX_sourceTransform TOKENHASH(3608891648)
5429 #define CTX_source_over TOKENHASH(2221728393)
5430 #define CTX_square TOKENHASH(373402726)
5431 #define CTX_start TOKENHASH(43126054)
5432 #define CTX_start_move TOKENHASH(2528525896)
5433 #define CTX_start_group TOKENHASH(2643259216)
5434 #define CTX_startGroup TOKENHASH(4199711715)
5435 #define CTX_stroke TOKENHASH(359634214)
5436 #define CTX_text_align TOKENHASH(2641259250)
5437 #define CTX_textAlign TOKENHASH(4087119491)
5438 #define CTX_texture TOKENHASH(2603404275)
5439 #define CTX_text_baseline TOKENHASH(2666328946)
5440 #define CTX_text_baseline TOKENHASH(2666328946)
5441 #define CTX_textBaseline TOKENHASH(3671121506)
5442 #define CTX_fillRect TOKENHASH(2617922007)
5443 #define CTX_text TOKENHASH(1360232)
5444 #define CTX_text_direction TOKENHASH(2683352974)
5445 #define CTX_textDirection TOKENHASH(2303324726)
5446 #define CTX_text_stroke TOKENHASH(2394879415)
5447 #define CTX_strokeText TOKENHASH(4077103477)
5448 #define CTX_strokeRect TOKENHASH(3918462693)
5449 #define CTX_top TOKENHASH(33768)
5450 #define CTX_transform TOKENHASH(3717307466)
5451 #define CTX_translate TOKENHASH(2746303805)
5452 #define CTX_verLineTo TOKENHASH(2881865279)
5453 #define CTX_ver_line_to TOKENHASH(3445689061)
5454 #define CTX_width TOKENHASH(18096750)
5455 #define CTX_winding TOKENHASH(3743938776)
5456 #define CTX_x TOKENHASH(48)
5457 #define CTX_xor TOKENHASH(37872)
5458 #define CTX_y TOKENHASH(50)
5459 #define CTX_colorSpace TOKENHASH(2624117287)
5460 #define CTX_userRGB TOKENHASH(2839509677)
5461 #define CTX_userCMYK TOKENHASH(4240023559)
5462 #define CTX_deviceRGB TOKENHASH(3975717407)
5463 #define CTX_deviceCMYK TOKENHASH(4096729420)
5464 #define CTX_silver TOKENHASH(1219912294)
5465 #define CTX_fuchsia TOKENHASH(3356500405)
5466 #define CTX_gray TOKENHASH(1641614)
5467 #define CTX_yellow TOKENHASH(1575772530)
5468 #define CTX_white TOKENHASH(11815470)
5469 #define CTX_maroon TOKENHASH(972001370)
5470 #define CTX_magenta TOKENHASH(2383173845)
5471 #define CTX_blue TOKENHASH(371460)
5472 #define CTX_green TOKENHASH(29699214)
5473 #define CTX_red TOKENHASH(8548)
5474 #define CTX_purple TOKENHASH(361796960)
5475 #define CTX_olive TOKENHASH(11946782)
5476 #define CTX_teal TOKENHASH(788840)
5477 #define CTX_black TOKENHASH(23268100)
5478 #define CTX_cyan TOKENHASH(921158)
5479 #define CTX_navy TOKENHASH(1683548)
5480 #define CTX_lime TOKENHASH(354904)
5481 #define CTX_aqua TOKENHASH(109634)
5482 #define CTX_transparent TOKENHASH(3143361910)
5483 #define CTX_currentColor TOKENHASH(2944012414)
5484 
5485 #endif
5486 
5487 
5488 
5489 #ifndef __CTX_LIBC_H
5490 #define __CTX_LIBC_H
5491 
5492 #if !__COSMOPOLITAN__
5493 #include <stddef.h>
5494 #endif
5495 
5496 #if 0
5497 static inline void
5498 ctx_memset (void *ptr, uint8_t val, int length)
5499 {
5500   uint8_t *p = (uint8_t *) ptr;
5501   for (int i = 0; i < length; i ++)
5502     { p[i] = val; }
5503 }
5504 #else
5505 #define ctx_memset memset
5506 #endif
5507 
5508 
ctx_strcpy(char * dst,const char * src)5509 static inline void ctx_strcpy (char *dst, const char *src)
5510 {
5511   int i = 0;
5512   for (i = 0; src[i]; i++)
5513     { dst[i] = src[i]; }
5514   dst[i] = 0;
5515 }
5516 
_ctx_strchr(const char * haystack,char needle)5517 static inline char *_ctx_strchr (const char *haystack, char needle)
5518 {
5519   const char *p = haystack;
5520   while (*p && *p != needle)
5521     {
5522       p++;
5523     }
5524   if (*p == needle)
5525     { return (char *) p; }
5526   return NULL;
5527 }
ctx_strchr(const char * haystack,char needle)5528 static inline char *ctx_strchr (const char *haystack, char needle)
5529 {
5530   return _ctx_strchr (haystack, needle);
5531 }
5532 
ctx_strcmp(const char * a,const char * b)5533 static inline int ctx_strcmp (const char *a, const char *b)
5534 {
5535   int i;
5536   for (i = 0; a[i] && b[i]; a++, b++)
5537     if (a[0] != b[0])
5538       { return 1; }
5539   if (a[0] == 0 && b[0] == 0) { return 0; }
5540   return 1;
5541 }
5542 
ctx_strncmp(const char * a,const char * b,size_t n)5543 static inline int ctx_strncmp (const char *a, const char *b, size_t n)
5544 {
5545   size_t i;
5546   for (i = 0; a[i] && b[i] && i < n; a++, b++)
5547     if (a[0] != b[0])
5548       { return 1; }
5549   return 0;
5550 }
5551 
ctx_strlen(const char * s)5552 static inline int ctx_strlen (const char *s)
5553 {
5554   int len = 0;
5555   for (; *s; s++) { len++; }
5556   return len;
5557 }
5558 
ctx_strstr(const char * h,const char * n)5559 static inline char *ctx_strstr (const char *h, const char *n)
5560 {
5561   int needle_len = ctx_strlen (n);
5562   if (n[0]==0)
5563     { return (char *) h; }
5564   while (h)
5565     {
5566       h = ctx_strchr (h, n[0]);
5567       if (!h)
5568         { return NULL; }
5569       if (!ctx_strncmp (h, n, needle_len) )
5570         { return (char *) h; }
5571       h++;
5572     }
5573   return NULL;
5574 }
5575 
5576 #endif
5577 
5578 #if CTX_IMPLEMENTATION|CTX_COMPOSITE
5579 
5580 #ifndef __CTX_INTERNAL_H
5581 #define __CTX_INTERNAL_H
5582 
5583 #if !__COSMOPOLITAN__
5584 #include <stdlib.h>
5585 #include <stdio.h>
5586 #include <unistd.h>
5587 #include <math.h>
5588 #endif
5589 
5590 #define CTX_BRANCH_HINTS  1
5591 
5592 #if CTX_BRANCH_HINTS
5593 #define CTX_LIKELY(x)      __builtin_expect(!!(x), 1)
5594 #define CTX_UNLIKELY(x)    __builtin_expect(!!(x), 0)
5595 #else
5596 #define CTX_LIKELY(x)      (x)
5597 #define CTX_UNLIKELY(x)    (x)
5598 #endif
5599 
5600 typedef struct _CtxRasterizer CtxRasterizer;
5601 typedef struct _CtxGState     CtxGState;
5602 typedef struct _CtxState      CtxState;
5603 
5604 typedef struct _CtxSource CtxSource;
5605 
5606 
5607 #define CTX_VALID_RGBA_U8     (1<<0)
5608 #define CTX_VALID_RGBA_DEVICE (1<<1)
5609 #if CTX_ENABLE_CM
5610 #define CTX_VALID_RGBA        (1<<2)
5611 #endif
5612 #if CTX_ENABLE_CMYK
5613 #define CTX_VALID_CMYKA       (1<<3)
5614 #define CTX_VALID_DCMYKA      (1<<4)
5615 #endif
5616 #define CTX_VALID_GRAYA       (1<<5)
5617 #define CTX_VALID_GRAYA_U8    (1<<6)
5618 #define CTX_VALID_LABA        ((1<<7) | CTX_VALID_GRAYA)
5619 
5620 struct _CtxColor
5621 {
5622   uint8_t magic; // for colors used in keydb, set to a non valid start of
5623                  // string value.
5624   uint8_t rgba[4];
5625   uint8_t l_u8;
5626   uint8_t original; // the bitmask of the originally set color
5627   uint8_t valid;    // bitmask of which members contain valid
5628   // values, gets denser populated as more
5629   // formats are requested from a set color.
5630   float   device_red;
5631   float   device_green;
5632   float   device_blue;
5633   float   alpha;
5634   float   l;        // luminance and gray
5635 #if CTX_ENABLE_LAB  // NYI
5636   float   a;
5637   float   b;
5638 #endif
5639 #if CTX_ENABLE_CMYK
5640   float   device_cyan;
5641   float   device_magenta;
5642   float   device_yellow;
5643   float   device_key;
5644   float   cyan;
5645   float   magenta;
5646   float   yellow;
5647   float   key;
5648 #endif
5649 
5650 #if CTX_ENABLE_CM
5651 #if CTX_BABL
5652   const Babl *space; // gets copied from state when color is declared
5653 #else
5654   void   *space; // gets copied from state when color is declared,
5655 #endif
5656   float   red;
5657   float   green;
5658   float   blue;
5659 #endif
5660 };
5661 
5662 typedef struct _CtxGradientStop CtxGradientStop;
5663 
5664 struct _CtxGradientStop
5665 {
5666   float   pos;
5667   CtxColor color;
5668 };
5669 
5670 
5671 enum _CtxSourceType
5672 {
5673   CTX_SOURCE_COLOR = 0,
5674   CTX_SOURCE_TEXTURE,
5675   CTX_SOURCE_LINEAR_GRADIENT,
5676   CTX_SOURCE_RADIAL_GRADIENT,
5677   CTX_SOURCE_INHERIT_FILL
5678 };
5679 
5680 typedef enum _CtxSourceType CtxSourceType;
5681 
5682 typedef struct _CtxPixelFormatInfo CtxPixelFormatInfo;
5683 
5684 
5685 struct _CtxBuffer
5686 {
5687   void               *data;
5688   int                 width;
5689   int                 height;
5690   int                 stride;
5691   char               *eid;        // might be NULL, when not - should be unique for pixel contents
5692   int                 frame;      // last frame used in, everything > 3 can be removed,
5693                                   // as clients wont rely on it.
5694   CtxPixelFormatInfo *format;
5695   void (*free_func) (void *pixels, void *user_data);
5696   void               *user_data;
5697 
5698 #if CTX_ENABLE_CM
5699 #if CTX_BABL
5700   const Babl *space;
5701 #else
5702   void       *space;
5703 #endif
5704 #endif
5705 #if 1
5706   CtxBuffer          *color_managed; /* only valid for one render target, cache
5707                                         for a specific space
5708                                         */
5709 #endif
5710 };
5711 
5712 //void _ctx_user_to_device          (CtxState *state, float *x, float *y);
5713 //void _ctx_user_to_device_distance (CtxState *state, float *x, float *y);
5714 
5715 typedef struct _CtxGradient CtxGradient;
5716 struct _CtxGradient
5717 {
5718   CtxGradientStop stops[16];
5719   int n_stops;
5720 };
5721 
5722 struct _CtxSource
5723 {
5724   int type;
5725   CtxMatrix  set_transform;
5726   CtxMatrix  transform;
5727   union
5728   {
5729     CtxColor color;
5730     struct
5731     {
5732       uint8_t rgba[4]; // shares data with set color
5733       uint8_t pad;
5734       CtxBuffer *buffer;
5735     } texture;
5736     struct
5737     {
5738       float x0;
5739       float y0;
5740       float x1;
5741       float y1;
5742       float dx;
5743       float dy;
5744       float start;
5745       float end;
5746       float length;
5747       float rdelta;
5748     } linear_gradient;
5749     struct
5750     {
5751       float x0;
5752       float y0;
5753       float r0;
5754       float x1;
5755       float y1;
5756       float r1;
5757       float rdelta;
5758     } radial_gradient;
5759   };
5760 };
5761 
5762 struct _CtxGState
5763 {
5764   int           keydb_pos;
5765   int           stringpool_pos;
5766 
5767   CtxMatrix     transform;
5768   CtxSource     source_stroke;
5769   CtxSource     source_fill;
5770   float         global_alpha_f;
5771   uint8_t       global_alpha_u8;
5772 
5773   float         line_width;
5774   float         line_dash_offset;
5775   float         miter_limit;
5776   float         font_size;
5777 #if CTX_ENABLE_SHADOW_BLUR
5778   float         shadow_blur;
5779   float         shadow_offset_x;
5780   float         shadow_offset_y;
5781 #endif
5782   int           clipped:1;
5783 
5784   int16_t       clip_min_x;
5785   int16_t       clip_min_y;
5786   int16_t       clip_max_x;
5787   int16_t       clip_max_y;
5788 
5789 #if CTX_ENABLE_CM
5790 #if CTX_BABL
5791   const Babl   *device_space;
5792   const Babl   *texture_space;
5793   const Babl   *rgb_space;
5794   const Babl   *cmyk_space;
5795 
5796   const Babl   *fish_rgbaf_user_to_device;
5797   const Babl   *fish_rgbaf_texture_to_device;
5798   const Babl   *fish_rgbaf_device_to_user;
5799 
5800 #else
5801   void         *device_space;
5802   void         *texture_space;
5803   void         *rgb_space;
5804   void         *cmyk_space;
5805   void         *fish_rgbaf_user_to_device; // dummy padding
5806   void         *fish_rgbaf_texture_to_device; // dummy padding
5807   void         *fish_rgbaf_device_to_user; // dummy padding
5808 #endif
5809 #endif
5810   CtxCompositingMode  compositing_mode; // bitfield refs lead to
5811   CtxBlend                  blend_mode; // non-vectorization
5812 
5813   float dashes[CTX_PARSER_MAX_ARGS];
5814   int n_dashes;
5815 
5816   CtxColorModel    color_model;
5817   /* bitfield-pack small state-parts */
5818   CtxLineCap          line_cap:2;
5819   CtxLineJoin        line_join:2;
5820   CtxFillRule        fill_rule:1;
5821   unsigned int image_smoothing:1;
5822   unsigned int            font:6;
5823   unsigned int            bold:1;
5824   unsigned int          italic:1;
5825 };
5826 
5827 typedef enum
5828 {
5829   CTX_TRANSFORMATION_NONE         = 0,
5830   CTX_TRANSFORMATION_SCREEN_SPACE = 1,
5831   CTX_TRANSFORMATION_RELATIVE     = 2,
5832 #if CTX_BITPACK
5833   CTX_TRANSFORMATION_BITPACK      = 4,
5834 #endif
5835   CTX_TRANSFORMATION_STORE_CLEAR  = 16,
5836 } CtxTransformation;
5837 
5838 #define CTX_DRAWLIST_DOESNT_OWN_ENTRIES   64
5839 #define CTX_DRAWLIST_EDGE_LIST            128
5840 #define CTX_DRAWLIST_CURRENT_PATH         512
5841 // BITPACK
5842 
5843 struct _CtxDrawlist
5844 {
5845   CtxEntry *entries;
5846   int       count;
5847   int       size;
5848   uint32_t  flags;
5849   int       bitpack_pos;  // stream is bitpacked up to this offset
5850 };
5851 
5852 #define CTX_MAX_KEYDB 64 // number of entries in keydb
5853                          // entries are "copy-on-change" between states
5854 
5855 // the keydb consists of keys set to floating point values,
5856 // that might also be interpreted as integers for enums.
5857 //
5858 // the hash
5859 typedef struct _CtxKeyDbEntry CtxKeyDbEntry;
5860 struct _CtxKeyDbEntry
5861 {
5862   uint32_t key;
5863   float value;
5864   //union { float f[1]; uint8_t u8[4]; }value;
5865 };
5866 
5867 struct _CtxState
5868 {
5869   int           has_moved:1;
5870   int           has_clipped:1;
5871   float         x;
5872   float         y;
5873   int           min_x;
5874   int           min_y;
5875   int           max_x;
5876   int           max_y;
5877   int16_t       gstate_no;
5878   CtxGState     gstate;
5879   CtxGState     gstate_stack[CTX_MAX_STATES];//at end, so can be made dynamic
5880 #if CTX_GRADIENTS
5881   CtxGradient   gradient; /* we keep only one gradient,
5882                              this goes icky with multiple
5883                              restores - it should really be part of
5884                              graphics state..
5885                              XXX, with the stringpool gradients
5886                              can be stored there.
5887                            */
5888 #endif
5889   CtxKeyDbEntry keydb[CTX_MAX_KEYDB];
5890   char          stringpool[CTX_STRINGPOOL_SIZE];
5891   int8_t        source; // used for the single-shifting to stroking
5892                 // 0  = fill
5893                 // 1  = start_stroke
5894                 // 2  = in_stroke
5895                 //
5896                 //   if we're at in_stroke at start of a source definition
5897                 //   we do filling
5898 };
5899 
5900 
5901 typedef struct _CtxFont       CtxFont;
5902 typedef struct _CtxFontEngine CtxFontEngine;
5903 
5904 struct _CtxFontEngine
5905 {
5906 #if CTX_FONTS_FROM_FILE
5907   int   (*load_file)   (const char *name, const char *path);
5908 #endif
5909   int   (*load_memory) (const char *name, const void *data, int length);
5910   int   (*glyph)       (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke);
5911   float (*glyph_width) (CtxFont *font, Ctx *ctx, uint32_t unichar);
5912   float (*glyph_kern)  (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unicharB);
5913 };
5914 
5915 struct _CtxFont
5916 {
5917   CtxFontEngine *engine;
5918   const char *name;
5919   int type; // 0 ctx    1 stb    2 monobitmap
5920   union
5921   {
5922     struct
5923     {
5924       CtxEntry *data;
5925       int length;
5926       /* we've got ~110 bytes to fill to cover as
5927          much data as stbtt_fontinfo */
5928       //int16_t glyph_pos[26]; // for a..z
5929       int       glyphs; // number of glyphs
5930       uint32_t *index;
5931     } ctx;
5932     struct
5933     {
5934       char *path;
5935     } ctx_fs;
5936 #if CTX_FONT_ENGINE_STB
5937     struct
5938     {
5939       stbtt_fontinfo ttf_info;
5940       int cache_index;
5941       uint32_t cache_unichar;
5942     } stb;
5943 #endif
5944     struct { int start; int end; int gw; int gh; const uint8_t *data;} monobitmap;
5945   };
5946 };
5947 
5948 
5949 enum _CtxIteratorFlag
5950 {
5951   CTX_ITERATOR_FLAT           = 0,
5952   CTX_ITERATOR_EXPAND_BITPACK = 2,
5953   CTX_ITERATOR_DEFAULTS       = CTX_ITERATOR_EXPAND_BITPACK
5954 };
5955 typedef enum _CtxIteratorFlag CtxIteratorFlag;
5956 
5957 
5958 struct
5959   _CtxIterator
5960 {
5961   int              pos;
5962   int              first_run;
5963   CtxDrawlist *drawlist;
5964   int              end_pos;
5965   int              flags;
5966 
5967   int              bitpack_pos;
5968   int              bitpack_length;     // if non 0 bitpack is active
5969   CtxEntry         bitpack_command[6]; // the command returned to the
5970   // user if unpacking is needed.
5971 };
5972 #define CTX_MAX_DEVICES 16
5973 #define CTX_MAX_KEYBINDINGS         256
5974 
5975 #if CTX_EVENTS
5976 
5977 // include list implementation - since it already is a header+inline online
5978 // implementation?
5979 
5980 typedef struct CtxItemCb {
5981   CtxEventType types;
5982   CtxCb        cb;
5983   void*        data1;
5984   void*        data2;
5985 
5986   void (*finalize) (void *data1, void *data2, void *finalize_data);
5987   void  *finalize_data;
5988 
5989 } CtxItemCb;
5990 
5991 
5992 #define CTX_MAX_CBS              128
5993 
5994 typedef struct CtxItem {
5995   CtxMatrix inv_matrix;  /* for event coordinate transforms */
5996 
5997   /* bounding box */
5998   float          x0;
5999   float          y0;
6000   float          x1;
6001   float          y1;
6002 
6003   void *path;
6004   double          path_hash;
6005 
6006   CtxCursor       cursor; /* if 0 then UNSET and no cursor change is requested
6007                            */
6008 
6009   CtxEventType   types;   /* all cb's ored together */
6010   CtxItemCb cb[CTX_MAX_CBS];
6011   int       cb_count;
6012   int       ref_count;
6013 } CtxItem;
6014 
6015 
6016 typedef struct _CtxEvents CtxEvents;
6017 struct _CtxEvents
6018 {
6019   int             frozen;
6020   int             fullscreen;
6021   CtxList        *grabs; /* could split the grabs per device in the same way,
6022                             to make dispatch overhead smaller,. probably
6023                             not much to win though. */
6024   CtxItem         *prev[CTX_MAX_DEVICES];
6025   float            pointer_x[CTX_MAX_DEVICES];
6026   float            pointer_y[CTX_MAX_DEVICES];
6027   unsigned char    pointer_down[CTX_MAX_DEVICES];
6028   CtxEvent         drag_event[CTX_MAX_DEVICES];
6029   CtxList         *idles;
6030   CtxList         *idles_to_remove;
6031   CtxList         *idles_to_add;
6032   int              in_idle_dispatch;
6033   CtxList         *events; // for ctx_get_event
6034   int              ctx_get_event_enabled;
6035   int              idle_id;
6036   CtxBinding       bindings[CTX_MAX_KEYBINDINGS]; /*< better as list, uses no mem if unused */
6037   int              n_bindings;
6038   int              width;
6039   int              height;
6040   CtxList         *items;
6041   CtxItem         *last_item;
6042   CtxModifierState modifier_state;
6043   int              tap_delay_min;
6044   int              tap_delay_max;
6045   int              tap_delay_hold;
6046   double           tap_hysteresis;
6047 };
6048 
6049 
6050 #endif
6051 
6052 typedef struct _CtxEidInfo
6053 {
6054   char *eid;
6055   int   frame;
6056   int   width;
6057   int   height;
6058 } CtxEidInfo;
6059 
6060 struct _Ctx
6061 {
6062   CtxImplementation *renderer;
6063   CtxDrawlist        drawlist;
6064   int                transformation;
6065   CtxBuffer          texture[CTX_MAX_TEXTURES];
6066   Ctx               *texture_cache;
6067   CtxList           *eid_db;
6068   int                rev;
6069   void              *backend;
6070   CtxState           state;        /**/
6071   int                frame; /* used for texture lifetime */
6072 #if CTX_EVENTS
6073   CtxCursor          cursor;
6074   int                quit;
6075   int                dirty;
6076   CtxEvents          events;
6077   int                mouse_fd;
6078   int                mouse_x;
6079   int                mouse_y;
6080 #endif
6081 #if CTX_CURRENT_PATH
6082   CtxDrawlist    current_path; // possibly transformed coordinates !
6083   CtxIterator        current_path_iterator;
6084 #endif
6085 };
6086 
6087 
6088 static void ctx_process (Ctx *ctx, CtxEntry *entry);
6089 CtxBuffer *ctx_buffer_new (int width, int height,
6090                            CtxPixelFormat pixel_format);
6091 void ctx_buffer_free (CtxBuffer *buffer);
6092 
6093 void
6094 ctx_state_gradient_clear_stops (CtxState *state);
6095 
6096 static inline void ctx_interpret_style         (CtxState *state, CtxEntry *entry, void *data);
6097 static inline void ctx_interpret_transforms    (CtxState *state, CtxEntry *entry, void *data);
6098 static inline void ctx_interpret_pos           (CtxState *state, CtxEntry *entry, void *data);
6099 static inline void ctx_interpret_pos_transform (CtxState *state, CtxEntry *entry, void *data);
6100 
6101 struct _CtxInternalFsEntry
6102 {
6103   char *path;
6104   int   length;
6105   char *data;
6106 };
6107 
6108 struct _CtxPixelFormatInfo
6109 {
6110   CtxPixelFormat pixel_format;
6111   uint8_t        components:4; /* number of components */
6112   uint8_t        bpp; /* bits  per pixel - for doing offset computations
6113                          along with rowstride found elsewhere, if 0 it indicates
6114                          1/8  */
6115   uint8_t        ebpp; /*effective bytes per pixel - for doing offset
6116                          computations, for formats that get converted, the
6117                          ebpp of the working space applied */
6118   uint8_t        dither_red_blue;
6119   uint8_t        dither_green;
6120   CtxPixelFormat composite_format;
6121 
6122   void         (*to_comp) (CtxRasterizer *r,
6123                            int x, const void * __restrict__ src, uint8_t * __restrict__ comp, int count);
6124   void         (*from_comp) (CtxRasterizer *r,
6125                              int x, const uint8_t * __restrict__ comp, void *__restrict__ dst, int count);
6126   void         (*apply_coverage) (CtxRasterizer *r, uint8_t * __restrict__ dst, uint8_t * __restrict__ src, int x, uint8_t *coverage,
6127                           int count);
6128   void         (*setup) (CtxRasterizer *r);
6129 };
6130 
6131 
6132 static inline void
6133 _ctx_user_to_device (CtxState *state, float *x, float *y);
6134 static void
6135 _ctx_user_to_device_distance (CtxState *state, float *x, float *y);
6136 static void ctx_state_init (CtxState *state);
6137 static inline void
6138 ctx_interpret_pos_bare (CtxState *state, CtxEntry *entry, void *data);
6139 static inline void
6140 ctx_drawlist_deinit (CtxDrawlist *drawlist);
6141 
6142 CtxPixelFormatInfo *
6143 ctx_pixel_format_info (CtxPixelFormat format);
6144 
6145 
6146 int ctx_utf8_len (const unsigned char first_byte);
6147 const char *ctx_utf8_skip (const char *s, int utf8_length);
6148 int ctx_utf8_strlen (const char *s);
6149 int
6150 ctx_unichar_to_utf8 (uint32_t  ch,
6151                      uint8_t  *dest);
6152 
6153 uint32_t
6154 ctx_utf8_to_unichar (const char *input);
6155 
6156 
6157 typedef struct _CtxHasher CtxHasher;
6158 
6159 typedef void (*CtxFragment) (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy);
6160 
6161 #define CTX_MAX_GAUSSIAN_KERNEL_DIM    512
6162 
6163 struct _CtxShapeEntry
6164 {
6165   uint32_t hash;
6166   uint16_t width;
6167   uint16_t height;
6168   int      last_frame; // xxx
6169   uint32_t uses;  // instrumented for longer keep-alive
6170   uint8_t  data[];
6171 };
6172 
6173 typedef struct _CtxShapeEntry CtxShapeEntry;
6174 
6175 
6176 struct _CtxShapeCache
6177 {
6178   CtxShapeEntry *entries[CTX_SHAPE_CACHE_ENTRIES];
6179   long size;
6180 };
6181 
6182 typedef struct _CtxShapeCache CtxShapeCache;
6183 
6184 typedef enum {
6185    CTX_COV_PATH_FALLBACK =0,
6186    CTX_COV_PATH_OVER,
6187    CTX_COV_PATH_COPY,
6188    CTX_COV_PATH_COPY_FRAGMENT,
6189    CTX_COV_PATH_OVER_FRAGMENT
6190 } CtxCovPath;
6191 
6192 struct _CtxRasterizer
6193 {
6194   CtxImplementation vfuncs;
6195   /* these should be initialized and used as the bounds for rendering into the
6196      buffer as well XXX: not yet in use, and when in use will only be
6197      correct for axis aligned clips - proper rasterization of a clipping path
6198      would be yet another refinement on top.
6199    */
6200 
6201 
6202 #define CTX_COMPOSITE_ARGUMENTS CtxRasterizer *rasterizer, uint8_t * __restrict__ dst, uint8_t * __restrict__ src, int x0, uint8_t * __restrict__ coverage, int count
6203   void (*comp_op)(CTX_COMPOSITE_ARGUMENTS);
6204   CtxFragment fragment;
6205   Ctx       *ctx;
6206   CtxState  *state;
6207   void      *buf;
6208   int fast_aa;
6209   CtxCovPath  comp;
6210   float      x;  // < redundant? use state instead?
6211   float      y;
6212 
6213   unsigned int aa;          // level of vertical aa
6214   int prev_active_edges;
6215   int active_edges;
6216   int pending_edges;
6217   int ending_edges;
6218   int edge_pos;         // where we're at in iterating all edges
6219   unsigned int needs_aa3; // count of how many edges implies antialiasing
6220   unsigned int needs_aa5; // count of how many edges implies antialiasing
6221   unsigned int needs_aa15; // count of how many edges implies antialiasing
6222   int        horizontal_edges;
6223 
6224   int scanline;
6225   int        scan_min;
6226   int        scan_max;
6227   int        col_min;
6228   int        col_max;
6229 
6230 
6231   int        inner_x;
6232   int        inner_y;
6233 
6234   float      first_x;
6235   float      first_y;
6236   int        uses_transforms;
6237   int        has_shape:2;
6238   int        has_prev:2;
6239   int        preserve:1;
6240 
6241   int16_t    blit_x;
6242   int16_t    blit_y;
6243   int16_t    blit_width;
6244   int16_t    blit_height;
6245   int16_t    blit_stride;
6246 
6247   CtxPixelFormatInfo *format;
6248   Ctx       *texture_source; /* normally same as ctx */
6249 
6250   int edges[CTX_MAX_EDGES]; // integer position in edge array
6251   CtxDrawlist edge_list;
6252 
6253 
6254 
6255 
6256 
6257 #if CTX_ENABLE_SHADOW_BLUR
6258   int in_shadow;
6259 #endif
6260   int in_text;
6261   int shadow_x;
6262   int shadow_y;
6263 
6264   int swap_red_green;
6265   uint8_t             color[4*5];
6266 
6267   int clip_rectangle;
6268 
6269 #if CTX_ENABLE_CLIP
6270   CtxBuffer *clip_buffer;
6271 #endif
6272 
6273 
6274 #if CTX_COMPOSITING_GROUPS
6275   void      *saved_buf; // when group redirected
6276   CtxBuffer *group[CTX_GROUP_MAX];
6277 #endif
6278 #if CTX_ENABLE_SHADOW_BLUR
6279   float      kernel[CTX_MAX_GAUSSIAN_KERNEL_DIM];
6280 #endif
6281 
6282 #if CTX_SHAPE_CACHE
6283   CtxShapeCache shape_cache;
6284 #endif
6285 #if CTX_BRAILLE_TEXT
6286   int        term_glyphs:1; // store appropriate glyphs for redisplay
6287   CtxList   *glyphs;
6288 #endif
6289 };
6290 
6291 struct _CtxSHA1 {
6292     uint64_t length;
6293     uint32_t state[5], curlen;
6294     unsigned char buf[64];
6295 };
6296 
6297 
6298 struct _CtxHasher
6299 {
6300   CtxRasterizer rasterizer;
6301   int           cols;
6302   int           rows;
6303   uint8_t      *hashes;
6304   CtxSHA1       sha1_fill;
6305   CtxSHA1       sha1_stroke;
6306 };
6307 
6308 #if CTX_RASTERIZER
6309 void ctx_rasterizer_deinit (CtxRasterizer *rasterizer);
6310 #endif
6311 
6312 #if CTX_EVENTS
6313 extern int ctx_native_events;
6314 
6315 #if CTX_SDL
6316 extern int ctx_sdl_events;
6317 int ctx_sdl_consume_events (Ctx *ctx);
6318 #endif
6319 
6320 #if CTX_FB
6321 extern int ctx_fb_events;
6322 int ctx_fb_consume_events (Ctx *ctx);
6323 #endif
6324 
6325 
6326 int ctx_nct_consume_events (Ctx *ctx);
6327 int ctx_ctx_consume_events (Ctx *ctx);
6328 
6329 #endif
6330 
6331 enum {
6332   NC_MOUSE_NONE  = 0,
6333   NC_MOUSE_PRESS = 1,  /* "mouse-pressed", "mouse-released" */
6334   NC_MOUSE_DRAG  = 2,  /* + "mouse-drag"   (motion with pressed button) */
6335   NC_MOUSE_ALL   = 3   /* + "mouse-motion" (also delivered for release) */
6336 };
6337 void _ctx_mouse (Ctx *term, int mode);
6338 void nc_at_exit (void);
6339 
6340 int ctx_terminal_width  (void);
6341 int ctx_terminal_height (void);
6342 int ctx_terminal_cols   (void);
6343 int ctx_terminal_rows   (void);
6344 extern int ctx_frame_ack;
6345 
6346 int ctx_nct_consume_events (Ctx *ctx);
6347 
6348 typedef struct _CtxCtx CtxCtx;
6349 struct _CtxCtx
6350 {
6351    void (*render) (void *ctxctx, CtxCommand *command);
6352    void (*reset)  (void *ctxvtx);
6353    void (*flush)  (void *ctxctx);
6354    char *(*get_clipboard) (void *ctxctx);
6355    void (*set_clipboard) (void *ctxctx, const char *text);
6356    void (*free)   (void *ctxctx);
6357    Ctx *ctx;
6358    int  width;
6359    int  height;
6360    int  cols;
6361    int  rows;
6362    int  was_down;
6363 };
6364 
6365 
6366 extern int _ctx_max_threads;
6367 extern int _ctx_enable_hash_cache;
6368 void
6369 ctx_set (Ctx *ctx, uint32_t key_hash, const char *string, int len);
6370 const char *
6371 ctx_get (Ctx *ctx, const char *key);
6372 
6373 int ctx_renderer_is_term (Ctx *ctx);
6374 Ctx *ctx_new_ctx (int width, int height);
6375 Ctx *ctx_new_fb (int width, int height);
6376 Ctx *ctx_new_kms (int width, int height);
6377 Ctx *ctx_new_sdl (int width, int height);
6378 Ctx *ctx_new_term (int width, int height);
6379 Ctx *ctx_new_termimg (int width, int height);
6380 
6381 int ctx_resolve_font (const char *name);
6382 extern float ctx_u8_float[256];
6383 #define ctx_u8_to_float(val_u8) ctx_u8_float[((uint8_t)(val_u8))]
6384 //#define ctx_u8_to_float(val_u8) (val_u8/255.0f)
6385 //
6386 //
6387 
6388 
ctx_float_to_u8(float val_f)6389 static uint8_t ctx_float_to_u8 (float val_f)
6390 {
6391   return val_f < 0.0f ? 0 : val_f > 1.0f ? 0xff : 0xff * val_f +  0.5f;
6392 #if 0
6393   int val_i = val_f * 255.999f;
6394   if (val_i < 0) { return 0; }
6395   else if (val_i > 255) { return 255; }
6396   return val_i;
6397 #endif
6398 }
6399 
6400 
6401 #define CTX_CSS_LUMINANCE_RED   0.3f
6402 #define CTX_CSS_LUMINANCE_GREEN 0.59f
6403 #define CTX_CSS_LUMINANCE_BLUE  0.11f
6404 
6405 /* works on both float and uint8_t */
6406 #define CTX_CSS_RGB_TO_LUMINANCE(rgb)  (\
6407   (rgb[0]) * CTX_CSS_LUMINANCE_RED + \
6408   (rgb[1]) * CTX_CSS_LUMINANCE_GREEN +\
6409   (rgb[2]) * CTX_CSS_LUMINANCE_BLUE)
6410 
6411 const char *ctx_nct_get_event (Ctx *n, int timeoutms, int *x, int *y);
6412 const char *ctx_native_get_event (Ctx *n, int timeoutms);
6413 void
6414 ctx_color_get_rgba8 (CtxState *state, CtxColor *color, uint8_t *out);
6415 void ctx_color_get_graya_u8 (CtxState *state, CtxColor *color, uint8_t *out);
6416 float ctx_float_color_rgb_to_gray (CtxState *state, const float *rgb);
6417 void ctx_color_get_graya (CtxState *state, CtxColor *color, float *out);
6418 void ctx_rgb_to_cmyk (float r, float g, float b,
6419               float *c_out, float *m_out, float *y_out, float *k_out);
6420 uint8_t ctx_u8_color_rgb_to_gray (CtxState *state, const uint8_t *rgb);
6421 #if CTX_ENABLE_CMYK
6422 void ctx_color_get_cmyka (CtxState *state, CtxColor *color, float *out);
6423 #endif
6424 static void ctx_color_set_RGBA8 (CtxState *state, CtxColor *color, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
6425 void ctx_color_set_rgba (CtxState *state, CtxColor *color, float r, float g, float b, float a);
6426 static void ctx_color_set_drgba (CtxState *state, CtxColor *color, float r, float g, float b, float a);
6427 void ctx_color_get_cmyka (CtxState *state, CtxColor *color, float *out);
6428 static void ctx_color_set_cmyka (CtxState *state, CtxColor *color, float c, float m, float y, float k, float a);
6429 static void ctx_color_set_dcmyka (CtxState *state, CtxColor *color, float c, float m, float y, float k, float a);
6430 static void ctx_color_set_graya (CtxState *state, CtxColor *color, float gray, float alpha);
6431 
6432 int ctx_color_model_get_components (CtxColorModel model);
6433 
6434 static void ctx_state_set (CtxState *state, uint32_t key, float value);
6435 static void
6436 ctx_matrix_set (CtxMatrix *matrix, float a, float b, float c, float d, float e, float f);
6437 static void ctx_font_setup ();
6438 static float ctx_state_get (CtxState *state, uint32_t hash);
6439 
6440 #if CTX_RASTERIZER
6441 
6442 static void
6443 ctx_rasterizer_rel_move_to (CtxRasterizer *rasterizer, float x, float y);
6444 static void
6445 ctx_rasterizer_rel_line_to (CtxRasterizer *rasterizer, float x, float y);
6446 
6447 static void
6448 ctx_rasterizer_move_to (CtxRasterizer *rasterizer, float x, float y);
6449 static void
6450 ctx_rasterizer_line_to (CtxRasterizer *rasterizer, float x, float y);
6451 static void
6452 ctx_rasterizer_curve_to (CtxRasterizer *rasterizer,
6453                          float x0, float y0,
6454                          float x1, float y1,
6455                          float x2, float y2);
6456 static void
6457 ctx_rasterizer_rel_curve_to (CtxRasterizer *rasterizer,
6458                          float x0, float y0,
6459                          float x1, float y1,
6460                          float x2, float y2);
6461 
6462 static void
6463 ctx_rasterizer_reset (CtxRasterizer *rasterizer);
6464 static uint32_t ctx_rasterizer_poly_to_hash (CtxRasterizer *rasterizer);
6465 static void
6466 ctx_rasterizer_arc (CtxRasterizer *rasterizer,
6467                     float        x,
6468                     float        y,
6469                     float        radius,
6470                     float        start_angle,
6471                     float        end_angle,
6472                     int          anticlockwise);
6473 
6474 static void
6475 ctx_rasterizer_quad_to (CtxRasterizer *rasterizer,
6476                         float        cx,
6477                         float        cy,
6478                         float        x,
6479                         float        y);
6480 
6481 static void
6482 ctx_rasterizer_rel_quad_to (CtxRasterizer *rasterizer,
6483                         float        cx,
6484                         float        cy,
6485                         float        x,
6486                         float        y);
6487 
6488 static void
6489 ctx_rasterizer_rectangle (CtxRasterizer *rasterizer,
6490                           float x,
6491                           float y,
6492                           float width,
6493                           float height);
6494 
6495 static void ctx_rasterizer_finish_shape (CtxRasterizer *rasterizer);
6496 static void ctx_rasterizer_clip (CtxRasterizer *rasterizer);
6497 static void
6498 ctx_rasterizer_set_font (CtxRasterizer *rasterizer, const char *font_name);
6499 
6500 static void
6501 ctx_rasterizer_gradient_add_stop (CtxRasterizer *rasterizer, float pos, float *rgba);
6502 static void
6503 ctx_rasterizer_set_pixel (CtxRasterizer *rasterizer,
6504                           uint16_t x,
6505                           uint16_t y,
6506                           uint8_t r,
6507                           uint8_t g,
6508                           uint8_t b,
6509                           uint8_t a);
6510 static void
6511 ctx_rasterizer_round_rectangle (CtxRasterizer *rasterizer, float x, float y, float width, float height, float corner_radius);
6512 
6513 #endif
6514 
6515 #if CTX_ENABLE_CM // XXX to be moved to ctx.h
6516 void
6517 ctx_set_drgb_space (Ctx *ctx, int device_space);
6518 void
6519 ctx_set_dcmyk_space (Ctx *ctx, int device_space);
6520 void
6521 ctx_rgb_space (Ctx *ctx, int device_space);
6522 void
6523 ctx_set_cmyk_space (Ctx *ctx, int device_space);
6524 #endif
6525 
6526 #endif
6527 
6528 CtxRasterizer *
6529 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);
6530 
6531 
ctx_lerp_u8(uint8_t v0,uint8_t v1,uint8_t dx)6532 CTX_INLINE static uint8_t ctx_lerp_u8 (uint8_t v0, uint8_t v1, uint8_t dx)
6533 {
6534 #if 0
6535   return v0 + ((v1-v0) * dx)/255;
6536 #else
6537   return ( ( ( ( (v0) <<8) + (dx) * ( (v1) - (v0) ) ) ) >>8);
6538 #endif
6539 }
6540 
ctx_lerp_RGBA8(const uint32_t v0,const uint32_t v1,const uint8_t dx)6541 CTX_INLINE static uint32_t ctx_lerp_RGBA8 (const uint32_t v0, const uint32_t v1, const uint8_t dx)
6542 {
6543 #if 0
6544   char bv0[4];
6545   char bv1[4];
6546   char res[4];
6547   memcpy (&bv0[0], &v0, 4);
6548   memcpy (&bv1[0], &v1, 4);
6549   for (int c = 0; c < 4; c++)
6550     res [c] = ctx_lerp_u8 (bv0[c], bv1[c], dx);
6551   return ((uint32_t*)(&res[0]))[0];
6552 #else
6553   const uint32_t cov = dx;
6554   const uint32_t si_ga = (v1 & 0xff00ff00);
6555   const uint32_t si_rb = v1 & 0x00ff00ff;
6556   const uint32_t di_rb = v0 & 0x00ff00ff;
6557   const uint32_t d_rb = si_rb - di_rb;
6558   const uint32_t di_ga = v0 & 0xff00ff00;
6559   const uint32_t d_ga = (si_ga >>8) - (di_ga>>8);
6560   return
6561      (((di_rb + ((0xff00ff + d_rb * cov)>>8)) & 0x00ff00ff)) |
6562      (((di_ga + (0xff00ff + d_ga * cov))      & 0xff00ff00));
6563 
6564 #endif
6565 }
6566 
ctx_lerp_RGBA8_split(const uint32_t v0,const uint32_t v1,const uint8_t dx,uint32_t * dest_ga,uint32_t * dest_rb)6567 CTX_INLINE static void ctx_lerp_RGBA8_split (const uint32_t v0, const uint32_t v1, const uint8_t dx,
6568                                              uint32_t *dest_ga, uint32_t *dest_rb)
6569 {
6570   const uint32_t cov = dx;
6571   const uint32_t si_ga = v1 & 0xff00ff00;
6572   const uint32_t si_rb = v1 & 0x00ff00ff;
6573   const uint32_t di_ga = v0 & 0xff00ff00;
6574   const uint32_t di_rb = v0 & 0x00ff00ff;
6575   const uint32_t d_rb = si_rb - di_rb;
6576   const uint32_t d_ga = (si_ga >>8) - (di_ga >> 8);
6577   *dest_rb = (((di_rb + ((0xff00ff + d_rb * cov)>>8)) & 0x00ff00ff));
6578   *dest_ga = (((di_ga + (0xff00ff + d_ga * cov))      & 0xff00ff00));
6579 }
6580 
ctx_lerp_RGBA8_merge(uint32_t di_ga,uint32_t di_rb,uint32_t si_ga,uint32_t si_rb,const uint8_t dx)6581 CTX_INLINE static uint32_t ctx_lerp_RGBA8_merge (uint32_t di_ga, uint32_t di_rb, uint32_t si_ga, uint32_t si_rb, const uint8_t dx)
6582 {
6583   const uint32_t cov = dx;
6584   const uint32_t d_rb = si_rb - di_rb;
6585   const uint32_t d_ga = (si_ga >> 8) - (di_ga >> 8);
6586   return
6587      (((di_rb + ((0xff00ff + d_rb * cov)>>8)) & 0x00ff00ff))  |
6588       ((di_ga + ((0xff00ff + d_ga * cov)      & 0xff00ff00)));
6589 }
6590 
ctx_lerp_RGBA8_2(const uint32_t v0,uint32_t si_ga,uint32_t si_rb,const uint8_t dx)6591 CTX_INLINE static uint32_t ctx_lerp_RGBA8_2 (const uint32_t v0, uint32_t si_ga, uint32_t si_rb, const uint8_t dx)
6592 {
6593   const uint32_t cov = dx;
6594   const uint32_t di_ga = ( v0 & 0xff00ff00);
6595   const uint32_t di_rb = v0 & 0x00ff00ff;
6596   const uint32_t d_rb = si_rb - di_rb;
6597   const uint32_t d_ga = si_ga - (di_ga>>8);
6598   return
6599      (((di_rb + ((0xff00ff + d_rb * cov)>>8)) & 0x00ff00ff)) |
6600      (((di_ga + (0xff00ff + d_ga * cov))      & 0xff00ff00));
6601 }
6602 
6603 
6604 
6605 CTX_INLINE static float
ctx_lerpf(float v0,float v1,float dx)6606 ctx_lerpf (float v0, float v1, float dx)
6607 {
6608   return v0 + (v1-v0) * dx;
6609 }
6610 
6611 
6612 #ifndef CTX_MIN
6613 #define CTX_MIN(a,b)  (((a)<(b))?(a):(b))
6614 #endif
6615 #ifndef CTX_MAX
6616 #define CTX_MAX(a,b)  (((a)>(b))?(a):(b))
6617 #endif
6618 
6619 static inline void *ctx_calloc (size_t size, size_t count);
6620 
6621 void ctx_screenshot (Ctx *ctx, const char *output_path);
6622 
6623 
6624 CtxSHA1 *ctx_sha1_new (void);
6625 void ctx_sha1_free (CtxSHA1 *sha1);
6626 int ctx_sha1_process(CtxSHA1 *sha1, const unsigned char * msg, unsigned long len);
6627 int ctx_sha1_done(CtxSHA1 * sha1, unsigned char *out);
6628 
6629 void _ctx_texture_lock (void);
6630 void _ctx_texture_unlock (void);
6631 uint8_t *ctx_define_texture_pixel_data (CtxEntry *entry);
6632 void ctx_buffer_pixels_free (void *pixels, void *userdata);
6633 
6634 /*ctx_texture_init:
6635  * return value: eid, as passed in or if NULL generated by hashing pixels and width/height
6636  * XXX  this is low-level and not to be used directly use define_texture instead.  XXX
6637  */
6638 const char *ctx_texture_init (
6639                       Ctx        *ctx,
6640                       const char *eid,
6641                       int         width,
6642                       int         height,
6643                       int         stride,
6644                       CtxPixelFormat format,
6645                       void       *space,
6646                       uint8_t    *pixels,
6647                       void (*freefunc) (void *pixels, void *user_data),
6648                       void *user_data);
6649 
6650 #if CTX_TILED
6651 #if !__COSMOPOLITAN__
6652 //#include <threads.h>
6653 #endif
6654 #endif
6655 typedef struct _CtxTiled CtxTiled;
6656 
6657 
6658 typedef struct _EvSource EvSource;
6659 struct _EvSource
6660 {
6661   void   *priv; /* private storage  */
6662 
6663   /* returns non 0 if there is events waiting */
6664   int   (*has_event) (EvSource *ev_source);
6665 
6666   /* get an event, the returned event should be freed by the caller  */
6667   char *(*get_event) (EvSource *ev_source);
6668 
6669   /* destroy/unref this instance */
6670   void  (*destroy)   (EvSource *ev_source);
6671 
6672   /* get the underlying fd, useful for using select on  */
6673   int   (*get_fd)    (EvSource *ev_source);
6674 
6675 
6676   void  (*set_coord) (EvSource *ev_source, double x, double y);
6677   /* set_coord is needed to warp relative cursors into normalized range,
6678    * like normal mice/trackpads/nipples - to obey edges and more.
6679    */
6680 
6681   /* if this returns non-0 select can be used for non-blocking.. */
6682 };
6683 
6684 struct _CtxTiled
6685 {
6686    void (*render)    (void *term, CtxCommand *command);
6687    void (*reset)     (void *term);
6688    void (*flush)     (void *term);
6689    char *(*get_clipboard) (void *ctxctx);
6690    void (*set_clipboard) (void *ctxctx, const char *text);
6691    void (*free)      (void *term);
6692    Ctx          *ctx;
6693    int           width;
6694    int           height;
6695    int           cols;
6696    int           rows;
6697    int           was_down;
6698    uint8_t      *pixels;
6699    Ctx          *ctx_copy;
6700    Ctx          *host[CTX_MAX_THREADS];
6701    CtxAntialias  antialias;
6702    int           quit;
6703 #if CTX_TILED
6704    _Atomic int   thread_quit;
6705 #endif
6706    int           shown_frame;
6707    int           render_frame;
6708    int           rendered_frame[CTX_MAX_THREADS];
6709    int           frame;
6710    int       min_col; // hasher cols and rows
6711    int       min_row;
6712    int       max_col;
6713    int       max_row;
6714    uint8_t  hashes[CTX_HASH_ROWS * CTX_HASH_COLS *  20];
6715    int8_t    tile_affinity[CTX_HASH_ROWS * CTX_HASH_COLS]; // which render thread no is
6716                                                            // responsible for a tile
6717                                                            //
6718 
6719    int           pointer_down[3];
6720 
6721    CtxCursor     shown_cursor;
6722    int          vt_active;
6723    EvSource    *evsource[4];
6724    int          evsource_count;
6725    uint8_t      *fb;
6726 #if CTX_TILED
6727    cnd_t  cond;
6728    mtx_t  mtx;
6729 #endif
6730 };
6731 
6732 static void
6733 _ctx_texture_prepare_color_management (CtxRasterizer *rasterizer,
6734                                       CtxBuffer     *buffer);
6735 
6736 int ctx_is_set (Ctx *ctx, uint32_t hash);
6737 
6738 #endif
6739 
6740 
6741 uint32_t    ctx_strhash        (const char *str);
6742 CtxColor   *ctx_color_new      (void);
6743 int         ctx_get_int        (Ctx *ctx, uint32_t hash);
6744 int         ctx_get_is_set     (Ctx *ctx, uint32_t hash);
6745 Ctx        *ctx_new_for_buffer (CtxBuffer *buffer);
6746 
6747 #if CTX_IMPLEMENTATION
6748 
6749 #define SHA1_IMPLEMENTATION
6750 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
6751  *
6752  * LibTomCrypt is a library that provides various cryptographic
6753  * algorithms in a highly modular and flexible manner.
6754  *
6755  * The library is free for all purposes without any express
6756  * guarantee it works.
6757  *
6758  * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
6759  *
6760  * The plain ANSIC sha1 functionality has been extracted from libtomcrypt,
6761  * and is included directly in the sources. /Øyvind K. - since libtomcrypt
6762  * is public domain the adaptations done here to make the sha1 self contained
6763  * also is public domain.
6764  */
6765 #ifndef __SHA1_H
6766 #define __SHA1_H
6767 #if !__COSMOPOLITAN__
6768 #include <inttypes.h>
6769 #endif
6770 
6771 
6772 int ctx_sha1_init(CtxSHA1 * sha1);
ctx_sha1_new(void)6773 CtxSHA1 *ctx_sha1_new (void)
6774 {
6775   CtxSHA1 *state = (CtxSHA1*)calloc (sizeof (CtxSHA1), 1);
6776   ctx_sha1_init (state);
6777   return state;
6778 }
ctx_sha1_free(CtxSHA1 * sha1)6779 void ctx_sha1_free (CtxSHA1 *sha1)
6780 {
6781   free (sha1);
6782 }
6783 
6784 #if 0
6785           CtxSHA1 sha1;
6786           ctx_sha1_init (&sha1);
6787           ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxIntRectangle));
6788           ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
6789 #endif
6790 
6791 #ifdef SHA1_FF0
6792 #undef SHA1_FF0
6793 #endif
6794 #ifdef SHA1_FF1
6795 #undef SHA1_FF1
6796 #endif
6797 
6798 #ifdef SHA1_IMPLEMENTATION
6799 #if !__COSMOPOLITAN__
6800 #include <stdlib.h>
6801 #include <string.h>
6802 #endif
6803 
6804 #define STORE64H(x,                                                             y)                                                                     \
6805    { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned                char)(((x)>>48)&255);     \
6806      (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned                char)(((x)>>32)&255);     \
6807      (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned                char)(((x)>>16)&255);     \
6808      (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
6809 
6810 #define STORE32H(x,                                                             y)                                                                     \
6811      { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned              char)(((x)>>16)&255);   \
6812        (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned               char)((x)&255); }
6813 
6814 #define LOAD32H(x, y)                            \
6815      { x = ((unsigned long)((y)[0] & 255)<<24) | \
6816            ((unsigned long)((y)[1] & 255)<<16) | \
6817            ((unsigned long)((y)[2] & 255)<<8)  | \
6818            ((unsigned long)((y)[3] & 255)); }
6819 
6820 /* rotates the hard way */
6821 #define ROL(x, y)  ((((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
6822 #define ROLc(x, y) ROL(x,y)
6823 
6824 #define CRYPT_OK     0
6825 #define CRYPT_ERROR  1
6826 #define CRYPT_NOP    2
6827 
6828 #ifndef MAX
6829    #define MAX(x, y) ( ((x)>(y))?(x):(y) )
6830 #endif
6831 #ifndef MIN
6832    #define MIN(x, y) ( ((x)<(y))?(x):(y) )
6833 #endif
6834 
6835 /* a simple macro for making hash "process" functions */
6836 #define HASH_PROCESS(func_name, compress_name, state_var, block_size)               \
6837 int func_name (CtxSHA1 *sha1, const unsigned char *in, unsigned long inlen)      \
6838 {                                                                                   \
6839     unsigned long n;                                                                \
6840     int           err;                                                              \
6841     assert (sha1 != NULL);                                                          \
6842     assert (in != NULL);                                                            \
6843     if (sha1->curlen > sizeof(sha1->buf)) {                                         \
6844        return -1;                                                                   \
6845     }                                                                               \
6846     while (inlen > 0) {                                                             \
6847         if (sha1->curlen == 0 && inlen >= block_size) {                             \
6848            if ((err = compress_name (sha1, (unsigned char *)in)) != CRYPT_OK) {     \
6849               return err;                                                           \
6850            }                                                                        \
6851            sha1->length += block_size * 8;                                          \
6852            in             += block_size;                                            \
6853            inlen          -= block_size;                                            \
6854         } else {                                                                    \
6855            n = MIN(inlen, (block_size - sha1->curlen));                             \
6856            memcpy(sha1->buf + sha1->curlen, in, (size_t)n);                         \
6857            sha1->curlen += n;                                                       \
6858            in             += n;                                                     \
6859            inlen          -= n;                                                     \
6860            if (sha1->curlen == block_size) {                                        \
6861               if ((err = compress_name (sha1, sha1->buf)) != CRYPT_OK) {            \
6862                  return err;                                                        \
6863               }                                                                     \
6864               sha1->length += 8*block_size;                                         \
6865               sha1->curlen = 0;                                                     \
6866            }                                                                        \
6867        }                                                                            \
6868     }                                                                               \
6869     return CRYPT_OK;                                                                \
6870 }
6871 
6872 /**********************/
6873 
6874 #define F0(x,y,z)  (z ^ (x & (y ^ z)))
6875 #define F1(x,y,z)  (x ^ y ^ z)
6876 #define F2(x,y,z)  ((x & y) | (z & (x | y)))
6877 #define F3(x,y,z)  (x ^ y ^ z)
6878 
ctx_sha1_compress(CtxSHA1 * sha1,unsigned char * buf)6879 static int  ctx_sha1_compress(CtxSHA1 *sha1, unsigned char *buf)
6880 {
6881     uint32_t a,b,c,d,e,W[80],i;
6882 
6883     /* copy the state into 512-bits into W[0..15] */
6884     for (i = 0; i < 16; i++) {
6885         LOAD32H(W[i], buf + (4*i));
6886     }
6887 
6888     /* copy state */
6889     a = sha1->state[0];
6890     b = sha1->state[1];
6891     c = sha1->state[2];
6892     d = sha1->state[3];
6893     e = sha1->state[4];
6894 
6895     /* expand it */
6896     for (i = 16; i < 80; i++) {
6897         W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
6898     }
6899 
6900     /* compress */
6901     /* round one */
6902     #define SHA1_FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
6903     #define SHA1_FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
6904     #define SHA1_FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
6905     #define SHA1_FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
6906 
6907     for (i = 0; i < 20; ) {
6908        SHA1_FF0(a,b,c,d,e,i++);
6909        SHA1_FF0(e,a,b,c,d,i++);
6910        SHA1_FF0(d,e,a,b,c,i++);
6911        SHA1_FF0(c,d,e,a,b,i++);
6912        SHA1_FF0(b,c,d,e,a,i++);
6913     }
6914 
6915     /* round two */
6916     for (; i < 40; )  {
6917        SHA1_FF1(a,b,c,d,e,i++);
6918        SHA1_FF1(e,a,b,c,d,i++);
6919        SHA1_FF1(d,e,a,b,c,i++);
6920        SHA1_FF1(c,d,e,a,b,i++);
6921        SHA1_FF1(b,c,d,e,a,i++);
6922     }
6923 
6924     /* round three */
6925     for (; i < 60; )  {
6926        SHA1_FF2(a,b,c,d,e,i++);
6927        SHA1_FF2(e,a,b,c,d,i++);
6928        SHA1_FF2(d,e,a,b,c,i++);
6929        SHA1_FF2(c,d,e,a,b,i++);
6930        SHA1_FF2(b,c,d,e,a,i++);
6931     }
6932 
6933     /* round four */
6934     for (; i < 80; )  {
6935        SHA1_FF3(a,b,c,d,e,i++);
6936        SHA1_FF3(e,a,b,c,d,i++);
6937        SHA1_FF3(d,e,a,b,c,i++);
6938        SHA1_FF3(c,d,e,a,b,i++);
6939        SHA1_FF3(b,c,d,e,a,i++);
6940     }
6941 
6942     #undef SHA1_FF0
6943     #undef SHA1_FF1
6944     #undef SHA1_FF2
6945     #undef SHA1_FF3
6946 
6947     /* store */
6948     sha1->state[0] = sha1->state[0] + a;
6949     sha1->state[1] = sha1->state[1] + b;
6950     sha1->state[2] = sha1->state[2] + c;
6951     sha1->state[3] = sha1->state[3] + d;
6952     sha1->state[4] = sha1->state[4] + e;
6953 
6954     return CRYPT_OK;
6955 }
6956 
6957 /**
6958    Initialize the hash state
6959    @param md   The hash state you wish to initialize
6960    @return CRYPT_OK if successful
6961 */
ctx_sha1_init(CtxSHA1 * sha1)6962 int ctx_sha1_init(CtxSHA1 * sha1)
6963 {
6964    assert(sha1 != NULL);
6965    sha1->state[0] = 0x67452301UL;
6966    sha1->state[1] = 0xefcdab89UL;
6967    sha1->state[2] = 0x98badcfeUL;
6968    sha1->state[3] = 0x10325476UL;
6969    sha1->state[4] = 0xc3d2e1f0UL;
6970    sha1->curlen = 0;
6971    sha1->length = 0;
6972    return CRYPT_OK;
6973 }
6974 
6975 /**
6976    Process a block of memory though the hash
6977    @param md     The hash state
6978    @param in     The data to hash
6979    @param inlen  The length of the data (octets)
6980    @return CRYPT_OK if successful
6981 */
6982 HASH_PROCESS(ctx_sha1_process, ctx_sha1_compress, sha1, 64)
6983 
6984 /**
6985    Terminate the hash to get the digest
6986    @param md  The hash state
6987    @param out [out] The destination of the hash (20 bytes)
6988    @return CRYPT_OK if successful
6989 */
ctx_sha1_done(CtxSHA1 * sha1,unsigned char * out)6990 int ctx_sha1_done(CtxSHA1 * sha1, unsigned char *out)
6991 {
6992     int i;
6993 
6994     assert(sha1 != NULL);
6995     assert(out != NULL);
6996 
6997     if (sha1->curlen >= sizeof(sha1->buf)) {
6998        return -1;
6999     }
7000 
7001     /* increase the length of the message */
7002     sha1->length += sha1->curlen * 8;
7003 
7004     /* append the '1' bit */
7005     sha1->buf[sha1->curlen++] = (unsigned char)0x80;
7006 
7007     /* if the length is currently above 56 bytes we append zeros
7008      * then compress.  Then we can fall back to padding zeros and length
7009      * encoding like normal.
7010      */
7011     if (sha1->curlen > 56) {
7012         while (sha1->curlen < 64) {
7013             sha1->buf[sha1->curlen++] = (unsigned char)0;
7014         }
7015         ctx_sha1_compress(sha1, sha1->buf);
7016         sha1->curlen = 0;
7017     }
7018 
7019     /* pad upto 56 bytes of zeroes */
7020     while (sha1->curlen < 56) {
7021         sha1->buf[sha1->curlen++] = (unsigned char)0;
7022     }
7023 
7024     /* store length */
7025     STORE64H(sha1->length, sha1->buf+56);
7026     ctx_sha1_compress(sha1, sha1->buf);
7027 
7028     /* copy output */
7029     for (i = 0; i < 5; i++) {
7030         STORE32H(sha1->state[i], out+(4*i));
7031     }
7032     return CRYPT_OK;
7033 }
7034 #endif
7035 
7036 #endif
7037 #endif
7038 #ifndef CTX_AUDIO_H
7039 #define CTX_AUDIO_H
7040 
7041 #if !__COSMOPOLITAN__
7042 #include <stdint.h>
7043 #endif
7044 
7045 /* This enum should be kept in sync with the corresponding mmm enum.
7046  */
7047 typedef enum {
7048   CTX_f32,
7049   CTX_f32S,
7050   CTX_s16,
7051   CTX_s16S
7052 } CtxPCM;
7053 
7054 void   ctx_pcm_set_format        (Ctx *ctx, CtxPCM format);
7055 CtxPCM ctx_pcm_get_format        (Ctx *ctx);
7056 int    ctx_pcm_get_sample_rate   (Ctx *ctx);
7057 void   ctx_pcm_set_sample_rate   (Ctx *ctx, int sample_rate);
7058 int    ctx_pcm_get_frame_chunk   (Ctx *ctx);
7059 int    ctx_pcm_get_queued        (Ctx *ctx);
7060 float  ctx_pcm_get_queued_length (Ctx *ctx);
7061 int    ctx_pcm_queue             (Ctx *ctx, const int8_t *data, int frames);
7062 
7063 #endif
7064 
7065 #if CTX_IMPLEMENTATION
7066 #if CTX_AUDIO
7067 
7068 //#include <string.h>
7069 //#include "ctx-internal.h"
7070 //#include "mmm.h"
7071 
7072 #if !__COSMOPOLITAN__
7073 
7074 #include <pthread.h>
7075 #if CTX_ALSA_AUDIO
7076 #include <alsa/asoundlib.h>
7077 #endif
7078 
7079 
7080 
7081 //#include <alloca.h>
7082 
7083 #endif
7084 
7085 #define DESIRED_PERIOD_SIZE 1000
7086 
ctx_pcm_bytes_per_frame(CtxPCM format)7087 int ctx_pcm_bytes_per_frame (CtxPCM format)
7088 {
7089   switch (format)
7090   {
7091     case CTX_f32:  return 4;
7092     case CTX_f32S: return 8;
7093     case CTX_s16:  return 2;
7094     case CTX_s16S: return 4;
7095     default: return 1;
7096   }
7097 }
7098 
7099 static float    ctx_host_freq     = 48000;
7100 static CtxPCM   ctx_host_format   = CTX_s16S;
7101 static float    client_freq   = 48000;
7102 static CtxPCM   ctx_client_format = CTX_s16S;
7103 static int      ctx_pcm_queued    = 0;
7104 static int      ctx_pcm_cur_left  = 0;
7105 static CtxList *ctx_pcm_list;                 /* data is a blob a 32bit uint first, followed by pcm-data */
7106 
7107 
7108 //static long int ctx_pcm_queued_ticks = 0;  /*  the number of ticks into the future
7109   //                                      *  we've queued audio for
7110 
7111 
7112 
7113 int
ctx_pcm_channels(CtxPCM format)7114 ctx_pcm_channels (CtxPCM format)
7115 {
7116   switch (format)
7117   {
7118     case CTX_s16:
7119     case CTX_f32:
7120       return 1;
7121     case CTX_s16S:
7122     case CTX_f32S:
7123       return 2;
7124   }
7125   return 0;
7126 }
7127 
7128 /* todo: only start audio thread on first write - enabling dynamic choice
7129  * of sample-rate? or is it better to keep to opening 48000 as a standard
7130  * and do better internal resampling for others?
7131  */
7132 
7133 #if CTX_ALSA_AUDIO
alsa_open(char * dev,int rate,int channels)7134 static snd_pcm_t *alsa_open (char *dev, int rate, int channels)
7135 {
7136    snd_pcm_hw_params_t *hwp;
7137    snd_pcm_sw_params_t *swp;
7138    snd_pcm_t *h;
7139    int r;
7140    int dir;
7141    snd_pcm_uframes_t period_size_min;
7142    snd_pcm_uframes_t period_size_max;
7143    snd_pcm_uframes_t period_size;
7144    snd_pcm_uframes_t buffer_size;
7145 
7146    if ((r = snd_pcm_open(&h, dev, SND_PCM_STREAM_PLAYBACK, 0) < 0))
7147            return NULL;
7148 
7149    hwp = alloca(snd_pcm_hw_params_sizeof());
7150    memset(hwp, 0, snd_pcm_hw_params_sizeof());
7151    snd_pcm_hw_params_any(h, hwp);
7152 
7153    snd_pcm_hw_params_set_access(h, hwp, SND_PCM_ACCESS_RW_INTERLEAVED);
7154    snd_pcm_hw_params_set_format(h, hwp, SND_PCM_FORMAT_S16_LE);
7155    snd_pcm_hw_params_set_rate(h, hwp, rate, 0);
7156    snd_pcm_hw_params_set_channels(h, hwp, channels);
7157    dir = 0;
7158    snd_pcm_hw_params_get_period_size_min(hwp, &period_size_min, &dir);
7159    dir = 0;
7160    snd_pcm_hw_params_get_period_size_max(hwp, &period_size_max, &dir);
7161 
7162    period_size = DESIRED_PERIOD_SIZE;
7163 
7164    dir = 0;
7165    r = snd_pcm_hw_params_set_period_size_near(h, hwp, &period_size, &dir);
7166    r = snd_pcm_hw_params_get_period_size(hwp, &period_size, &dir);
7167    buffer_size = period_size * 4;
7168    r = snd_pcm_hw_params_set_buffer_size_near(h, hwp, &buffer_size);
7169    r = snd_pcm_hw_params(h, hwp);
7170    swp = alloca(snd_pcm_sw_params_sizeof());
7171    memset(hwp, 0, snd_pcm_sw_params_sizeof());
7172    snd_pcm_sw_params_current(h, swp);
7173    r = snd_pcm_sw_params_set_avail_min(h, swp, period_size);
7174    snd_pcm_sw_params_set_start_threshold(h, swp, 0);
7175    r = snd_pcm_sw_params(h, swp);
7176    r = snd_pcm_prepare(h);
7177 
7178    return h;
7179 }
7180 
7181 static  snd_pcm_t *h = NULL;
ctx_alsa_audio_start(Ctx * ctx)7182 static void *ctx_alsa_audio_start(Ctx *ctx)
7183 {
7184 //  Lyd *lyd = aux;
7185   int c;
7186 
7187   /* The audio handler is implemented as a mixer that adds data on top
7188    * of 0s, XXX: it should be ensured that minimal work is there is
7189    * no data available.
7190    */
7191   for (;;)
7192   {
7193     int client_channels = ctx_pcm_channels (ctx_client_format);
7194     int is_float = 0;
7195     int16_t data[81920*8]={0,};
7196 
7197     if (ctx_client_format == CTX_f32 ||
7198         ctx_client_format == CTX_f32S)
7199       is_float = 1;
7200 
7201     c = snd_pcm_wait(h, 1000);
7202 
7203     if (c >= 0)
7204        c = snd_pcm_avail_update(h);
7205 
7206     if (c > 1000) c = 1000; // should use max mmm buffer sizes
7207 
7208     if (c == -EPIPE)
7209       snd_pcm_prepare(h);
7210 
7211     if (c > 0)
7212     {
7213       int i;
7214       for (i = 0; i < c && ctx_pcm_cur_left; i ++)
7215       {
7216         if (ctx_pcm_cur_left)  //  XXX  this line can be removed
7217         {
7218           uint32_t *packet_sizep = (ctx_pcm_list->data);
7219           uint32_t packet_size = *packet_sizep;
7220           uint16_t left = 0, right = 0;
7221 
7222           if (is_float)
7223           {
7224             float *packet = (ctx_pcm_list->data);
7225             packet += 4;
7226             packet += (packet_size - ctx_pcm_cur_left) * client_channels;
7227             left = right = packet[0] * (1<<15);
7228             if (client_channels > 1)
7229               right = packet[0] * (1<<15);
7230           }
7231           else // s16
7232           {
7233             uint16_t *packet = (ctx_pcm_list->data);
7234             packet += 8;
7235             packet += (packet_size - ctx_pcm_cur_left) * client_channels;
7236 
7237             left = right = packet[0];
7238             if (client_channels > 1)
7239               right = packet[1];
7240           }
7241           data[i * 2 + 0] = left;
7242           data[i * 2 + 1] = right;
7243 
7244           ctx_pcm_cur_left--;
7245           ctx_pcm_queued --;
7246           if (ctx_pcm_cur_left == 0)
7247           {
7248             void *old = ctx_pcm_list->data;
7249             ctx_list_remove (&ctx_pcm_list, ctx_pcm_list->data);
7250             free (old);
7251             ctx_pcm_cur_left = 0;
7252             if (ctx_pcm_list)
7253             {
7254               uint32_t *packet_sizep = (ctx_pcm_list->data);
7255               uint32_t packet_size = *packet_sizep;
7256               ctx_pcm_cur_left = packet_size;
7257             }
7258           }
7259         }
7260       }
7261 
7262     c = snd_pcm_writei(h, data, c);
7263     if (c < 0)
7264       c = snd_pcm_recover (h, c, 0);
7265      }else{
7266       if (getenv("LYD_FATAL_UNDERRUNS"))
7267         {
7268           printf ("dying XXxx need to add API for this debug\n");
7269           //printf ("%i", lyd->active);
7270           exit(0);
7271         }
7272       fprintf (stderr, "ctx alsa underun\n");
7273       //exit(0);
7274     }
7275   }
7276 }
7277 #endif
7278 
7279 static char MuLawCompressTable[256] =
7280 {
7281    0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
7282    4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
7283    5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
7284    5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
7285    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7286    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7287    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7288    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7289    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7290    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7291    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7292    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7293    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7294    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7295    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7296    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
7297 };
7298 
LinearToMuLawSample(int16_t sample)7299 static unsigned char LinearToMuLawSample(int16_t sample)
7300 {
7301   const int cBias = 0x84;
7302   const int cClip = 32635;
7303   int sign = (sample >> 8) & 0x80;
7304 
7305   if (sign)
7306     sample = (int16_t)-sample;
7307 
7308   if (sample > cClip)
7309     sample = cClip;
7310 
7311   sample = (int16_t)(sample + cBias);
7312 
7313   int exponent = (int)MuLawCompressTable[(sample>>7) & 0xFF];
7314   int mantissa = (sample >> (exponent+3)) & 0x0F;
7315 
7316   int compressedByte = ~ (sign | (exponent << 4) | mantissa);
7317 
7318   return (unsigned char)compressedByte;
7319 }
7320 
ctx_ctx_pcm(Ctx * ctx)7321 void ctx_ctx_pcm (Ctx *ctx)
7322 {
7323     int client_channels = ctx_pcm_channels (ctx_client_format);
7324     int is_float = 0;
7325     uint8_t data[81920*8]={0,};
7326     int c;
7327 
7328     if (ctx_client_format == CTX_f32 ||
7329         ctx_client_format == CTX_f32S)
7330       is_float = 1;
7331 
7332     c = 2000;
7333 
7334     if (c > 0)
7335     {
7336       int i;
7337       for (i = 0; i < c && ctx_pcm_cur_left; i ++)
7338       {
7339         if (ctx_pcm_cur_left)  //  XXX  this line can be removed
7340         {
7341           uint32_t *packet_sizep = (ctx_pcm_list->data);
7342           uint32_t packet_size = *packet_sizep;
7343           int left = 0, right = 0;
7344 
7345           if (is_float)
7346           {
7347             float *packet = (ctx_pcm_list->data);
7348             packet += 4;
7349             packet += (packet_size - ctx_pcm_cur_left) * client_channels;
7350             left = right = packet[0] * (1<<15);
7351             if (client_channels > 1)
7352               right = packet[1] * (1<<15);
7353           }
7354           else // s16
7355           {
7356             uint16_t *packet = (ctx_pcm_list->data);
7357             packet += 8;
7358             packet += (packet_size - ctx_pcm_cur_left) * client_channels;
7359 
7360             left = right = packet[0];
7361             if (client_channels > 1)
7362               right = packet[1];
7363           }
7364           data[i] = LinearToMuLawSample((left+right)/2);
7365 
7366           ctx_pcm_cur_left--;
7367           ctx_pcm_queued --;
7368           if (ctx_pcm_cur_left == 0)
7369           {
7370             void *old = ctx_pcm_list->data;
7371             ctx_list_remove (&ctx_pcm_list, ctx_pcm_list->data);
7372             free (old);
7373             ctx_pcm_cur_left = 0;
7374             if (ctx_pcm_list)
7375             {
7376               uint32_t *packet_sizep = (ctx_pcm_list->data);
7377               uint32_t packet_size = *packet_sizep;
7378               ctx_pcm_cur_left = packet_size;
7379             }
7380           }
7381         }
7382       }
7383 
7384     char encoded[81920*8]="";
7385 
7386     int encoded_len = ctx_a85enc (data, encoded, i);
7387     fprintf (stdout, "\033_Af=%i;", i);
7388     fwrite (encoded, 1, encoded_len, stdout);
7389     fwrite ("\e\\", 1, 2, stdout);
7390     fflush (stdout);
7391     }
7392 }
7393 
ctx_pcm_init(Ctx * ctx)7394 int ctx_pcm_init (Ctx *ctx)
7395 {
7396 #if 0
7397   if (!strcmp (ctx->backend->name, "mmm") ||
7398       !strcmp (ctx->backend->name, "mmm-client"))
7399   {
7400     return 0;
7401   }
7402   else
7403 #endif
7404   if (ctx_renderer_is_ctx (ctx))
7405   {
7406      ctx_host_freq = 8000;
7407      ctx_host_format = CTX_s16;
7408 #if 0
7409      pthread_t tid;
7410      pthread_create(&tid, NULL, (void*)ctx_audio_start, ctx);
7411 #endif
7412   }
7413   else
7414   {
7415 #if CTX_ALSA_AUDIO
7416      pthread_t tid;
7417      h = alsa_open("default", ctx_host_freq, ctx_pcm_channels (ctx_host_format));
7418   if (!h) {
7419     fprintf(stderr, "ctx unable to open ALSA device (%d channels, %f Hz), dying\n",
7420             ctx_pcm_channels (ctx_host_format), ctx_host_freq);
7421     return -1;
7422   }
7423   pthread_create(&tid, NULL, (void*)ctx_alsa_audio_start, ctx);
7424 #endif
7425   }
7426   return 0;
7427 }
7428 
ctx_pcm_queue(Ctx * ctx,const int8_t * data,int frames)7429 int ctx_pcm_queue (Ctx *ctx, const int8_t *data, int frames)
7430 {
7431   static int inited = 0;
7432 #if 0
7433   if (!strcmp (ctx->backend->name, "mmm") ||
7434       !strcmp (ctx->backend->name, "mmm-client"))
7435   {
7436     return mmm_pcm_queue (ctx->backend_data, data, frames);
7437   }
7438   else
7439 #endif
7440   {
7441     if (!inited)
7442     {
7443       ctx_pcm_init (ctx);
7444       inited = 1;
7445     }
7446     float factor = client_freq * 1.0 / ctx_host_freq;
7447     int   scaled_frames = frames / factor;
7448     int   bpf = ctx_pcm_bytes_per_frame (ctx_client_format);
7449 
7450     uint8_t *packet = malloc (scaled_frames * ctx_pcm_bytes_per_frame (ctx_client_format) + 16);
7451     *((uint32_t *)packet) = scaled_frames;
7452 
7453     if (factor > 0.999 && factor < 1.0001)
7454     {
7455        memcpy (packet + 16, data, frames * bpf);
7456     }
7457     else
7458     {
7459       /* a crude nearest / sample-and hold resampler */
7460       int i;
7461       for (i = 0; i < scaled_frames; i++)
7462       {
7463         int source_frame = i * factor;
7464         memcpy (packet + 16 + bpf * i, data + source_frame * bpf, bpf);
7465       }
7466     }
7467     if (ctx_pcm_list == NULL)     // otherwise it is another frame at front
7468       ctx_pcm_cur_left = scaled_frames;  // and current cur_left is valid
7469 
7470     ctx_list_append (&ctx_pcm_list, packet);
7471     ctx_pcm_queued += scaled_frames;
7472 
7473     return frames;
7474   }
7475   return 0;
7476 }
7477 
ctx_pcm_get_queued_frames(Ctx * ctx)7478 static int ctx_pcm_get_queued_frames (Ctx *ctx)
7479 {
7480 #if 0
7481   if (!strcmp (ctx->backend->name, "mmm") ||
7482       !strcmp (ctx->backend->name, "mmm-client"))
7483   {
7484     return mmm_pcm_get_queued_frames (ctx->backend_data);
7485   }
7486 #endif
7487   return ctx_pcm_queued;
7488 }
7489 
ctx_pcm_get_queued(Ctx * ctx)7490 int ctx_pcm_get_queued (Ctx *ctx)
7491 {
7492   return ctx_pcm_get_queued_frames (ctx);
7493 }
7494 
ctx_pcm_get_queued_length(Ctx * ctx)7495 float ctx_pcm_get_queued_length (Ctx *ctx)
7496 {
7497   return 1.0 * ctx_pcm_get_queued_frames (ctx) / ctx_host_freq;
7498 }
7499 
ctx_pcm_get_frame_chunk(Ctx * ctx)7500 int ctx_pcm_get_frame_chunk (Ctx *ctx)
7501 {
7502 #if 0
7503   if (!strcmp (ctx->backend->name, "mmm") ||
7504       !strcmp (ctx->backend->name, "mmm-client"))
7505   {
7506     return mmm_pcm_get_frame_chunk (ctx->backend_data);
7507   }
7508 #endif
7509   if (ctx_renderer_is_ctx (ctx))
7510   {
7511     // 300 stuttering
7512     // 350 nothing
7513     // 380 slight buzz
7514     // 390  buzzing
7515     // 400 ok - but sometimes falling out
7516     // 410 buzzing
7517     // 420 ok - but odd latency
7518     // 450 buzzing
7519 
7520     if (ctx_pcm_get_queued_frames (ctx) > 400)
7521       return 0;
7522     else
7523       return 400 - ctx_pcm_get_queued_frames (ctx);
7524 
7525   }
7526 
7527   if (ctx_pcm_get_queued_frames (ctx) > 1000)
7528     return 0;
7529   else
7530     return 1000 - ctx_pcm_get_queued_frames (ctx);
7531 }
7532 
ctx_pcm_set_sample_rate(Ctx * ctx,int sample_rate)7533 void ctx_pcm_set_sample_rate (Ctx *ctx, int sample_rate)
7534 {
7535 #if 0
7536   if (!strcmp (ctx->backend->name, "mmm") ||
7537       !strcmp (ctx->backend->name, "mmm-client"))
7538   {
7539     mmm_pcm_set_sample_rate (ctx->backend_data, sample_rate);
7540   }
7541   else
7542 #endif
7543     client_freq = sample_rate;
7544 }
7545 
ctx_pcm_set_format(Ctx * ctx,CtxPCM format)7546 void ctx_pcm_set_format (Ctx *ctx, CtxPCM format)
7547 {
7548 #if 0
7549   if (!strcmp (ctx->backend->name, "mmm") ||
7550       !strcmp (ctx->backend->name, "mmm-client"))
7551   {
7552     mmm_pcm_set_format (ctx->backend_data, format);
7553   }
7554   else
7555 #endif
7556     ctx_client_format = format;
7557 }
7558 
ctx_pcm_get_format(Ctx * ctx)7559 CtxPCM ctx_pcm_get_format (Ctx *ctx)
7560 {
7561 #if 0
7562   if (!strcmp (ctx->backend->name, "mmm") ||
7563       !strcmp (ctx->backend->name, "mmm-client"))
7564   {
7565     return mmm_pcm_get_format (ctx->backend_data);
7566   }
7567 #endif
7568   return ctx_client_format;
7569 }
7570 
ctx_pcm_get_sample_rate(Ctx * ctx)7571 int ctx_pcm_get_sample_rate (Ctx *ctx)
7572 {
7573 #if 0
7574   if (!strcmp (ctx->backend->name, "mmm") ||
7575       !strcmp (ctx->backend->name, "mmm-client"))
7576   {
7577     return mmm_pcm_get_sample_rate (ctx->backend_data);
7578   }
7579 #endif
7580   return client_freq;
7581 }
7582 
7583 #endif
7584  /* Copyright (C) 2020 Øyvind Kolås <pippin@gimp.org>
7585  */
7586 
7587 #if CTX_FORMATTER
7588 
7589 /* returns the maximum string length including terminating \0 */
ctx_a85enc_len(int input_length)7590 int ctx_a85enc_len (int input_length)
7591 {
7592   return (input_length / 4 + 1) * 5;
7593 }
7594 
ctx_a85enc(const void * srcp,char * dst,int count)7595 int ctx_a85enc (const void *srcp, char *dst, int count)
7596 {
7597   const uint8_t *src = (uint8_t*)srcp;
7598   int out_len = 0;
7599 
7600   int padding = 4-(count % 4);
7601   if (padding == 4) padding = 0;
7602 
7603   for (int i = 0; i < (count+3)/4; i ++)
7604   {
7605     uint32_t input = 0;
7606     for (int j = 0; j < 4; j++)
7607     {
7608       input = (input << 8);
7609       if (i*4+j<=count)
7610         input += src[i*4+j];
7611     }
7612 
7613     int divisor = 85 * 85 * 85 * 85;
7614 #if 0
7615     if (input == 0)
7616     {
7617         dst[out_len++] = 'z';
7618     }
7619     /* todo: encode 4 spaces as 'y' */
7620     else
7621 #endif
7622     {
7623       for (int j = 0; j < 5; j++)
7624       {
7625         dst[out_len++] = ((input / divisor) % 85) + '!';
7626         divisor /= 85;
7627       }
7628     }
7629   }
7630   out_len -= padding;
7631   dst[out_len]=0;
7632   return out_len;
7633 }
7634 #endif
7635 
7636 #if CTX_PARSER
7637 
ctx_a85dec(const char * src,char * dst,int count)7638 int ctx_a85dec (const char *src, char *dst, int count)
7639 {
7640   int out_len = 0;
7641   uint32_t val = 0;
7642   int k = 0;
7643   int i = 0;
7644   int p = 0;
7645   for (i = 0; i < count; i ++)
7646   {
7647     p = src[i];
7648     val *= 85;
7649     if (CTX_UNLIKELY(p == '~'))
7650     {
7651       break;
7652     }
7653 #if 0
7654     else if (p == 'z')
7655     {
7656       for (int j = 0; j < 4; j++)
7657         dst[out_len++] = 0;
7658       k = 0;
7659     }
7660     else if (p == 'y') /* lets support this extension */
7661     {
7662       for (int j = 0; j < 4; j++)
7663         dst[out_len++] = 32;
7664       k = 0;
7665     }
7666 #endif
7667     else if (CTX_LIKELY(p >= '!' && p <= 'u'))
7668     {
7669       val += p-'!';
7670       if (CTX_UNLIKELY (k % 5 == 4))
7671       {
7672          for (int j = 0; j < 4; j++)
7673          {
7674            dst[out_len++] = (val & (0xff << 24)) >> 24;
7675            val <<= 8;
7676          }
7677          val = 0;
7678       }
7679       k++;
7680     }
7681     // we treat all other chars as whitespace
7682   }
7683   if (CTX_LIKELY (p != '~'))
7684   {
7685     val *= 85;
7686   }
7687   k = k % 5;
7688   if (k)
7689   {
7690     val += 84;
7691     for (int j = k; j < 4; j++)
7692     {
7693       val *= 85;
7694       val += 84;
7695     }
7696 
7697     for (int j = 0; j < k-1; j++)
7698     {
7699       dst[out_len++] = (val & (0xff << 24)) >> 24;
7700       val <<= 8;
7701     }
7702     val = 0;
7703   }
7704   dst[out_len] = 0;
7705   return out_len;
7706 }
7707 
7708 #if 1
ctx_a85len(const char * src,int count)7709 int ctx_a85len (const char *src, int count)
7710 {
7711   int out_len = 0;
7712   int k = 0;
7713   for (int i = 0; i < count; i ++)
7714   {
7715     if (src[i] == '~')
7716       break;
7717     else if (src[i] == 'z')
7718     {
7719       for (int j = 0; j < 4; j++)
7720         out_len++;
7721       k = 0;
7722     }
7723     else if (src[i] >= '!' && src[i] <= 'u')
7724     {
7725       if (k % 5 == 4)
7726         out_len += 4;
7727       k++;
7728     }
7729     // we treat all other chars as whitespace
7730   }
7731   k = k % 5;
7732   if (k)
7733     out_len += k-1;
7734   return out_len;
7735 }
7736 #endif
7737 
7738 #endif
7739 #ifndef SQUOZE_H
7740 #define SQUOZE_H
7741 
7742 #include <stdio.h>
7743 #include <stdlib.h>
7744 #include <stdint.h>
7745 #include <string.h>
7746 #include <assert.h>
7747 
7748 uint32_t squoze6 (const char *utf8);
7749 uint64_t squoze10 (const char *utf8);
7750 uint64_t squoze12 (const char *utf8);
7751 const char *squoze6_decode (uint32_t hash);
7752 const char *squoze10_decode (uint64_t hash);
7753 const char *squoze12_decode (uint64_t hash);
7754 
7755 //#define SQUOZE_NO_INTERNING  // this disables the interning - providing only a hash (and decode for non-overflowed hashes)
7756 
7757 #define SQUOZE_ENTER_SQUEEZE    16
7758 
7759 #define SQUOZE_SPACE            0
7760 #define SQUOZE_DEC_OFFSET_A     27
7761 #define SQUOZE_INC_OFFSET_A     28
7762 #define SQUOZE_DEC_OFFSET_B     29
7763 #define SQUOZE_INC_OFFSET_B     30
7764 #define SQUOZE_ENTER_UTF5       31
7765 
7766 #define SQUOZE_JUMP_STRIDE      26
7767 #define SQUOZE_JUMP_OFFSET      19
7768 
7769 static inline uint32_t squoze_utf8_to_unichar (const char *input);
7770 static inline int      squoze_unichar_to_utf8 (uint32_t  ch, uint8_t  *dest);
7771 static inline int      squoze_utf8_len        (const unsigned char first_byte);
7772 
7773 
7774 /* returns the base-offset of the segment this unichar belongs to,
7775  *
7776  * segments are 26 items long and are offset so that the 'a'-'z' is
7777  * one segment.
7778  */
squoze_new_offset(uint32_t unichar)7779 static inline int squoze_new_offset (uint32_t unichar)
7780 {
7781   uint32_t ret = unichar - (unichar % SQUOZE_JUMP_STRIDE) + SQUOZE_JUMP_OFFSET;
7782   if (ret > unichar) ret -= SQUOZE_JUMP_STRIDE;
7783   return ret;
7784 }
7785 
squoze_needed_jump(uint32_t off,uint32_t unicha)7786 static int squoze_needed_jump (uint32_t off, uint32_t unicha)
7787 {
7788   int count = 0;
7789   int unichar = unicha;
7790   int offset = off;
7791 
7792   if (unichar == 32) // space is always in range
7793     return 0;
7794 
7795   /* TODO: replace this with direct computation of values instead of loops */
7796 
7797   while (unichar < offset)
7798   {
7799     offset -= SQUOZE_JUMP_STRIDE;
7800     count ++;
7801   }
7802   if (count)
7803   {
7804     return -count;
7805   }
7806   while (unichar - offset >= SQUOZE_JUMP_STRIDE)
7807   {
7808     offset += SQUOZE_JUMP_STRIDE;
7809     count ++;
7810   }
7811   return count;
7812 }
7813 
7814 static inline int
squoze_utf5_length(uint32_t unichar)7815 squoze_utf5_length (uint32_t unichar)
7816 {
7817   int octets = 0;
7818   if (unichar == 0)
7819     return 1;
7820   while (unichar)
7821   {
7822     octets ++;
7823     unichar /= 16;
7824   }
7825   return octets;
7826 }
7827 
7828 typedef struct EncodeUtf5 {
7829   int      is_utf5;
7830   int      offset;
7831   int      length;
7832   void    *write_data;
7833   uint32_t current;
7834 } EncodeUtf5;
7835 
7836 static inline uint64_t
squoze_overflow_mask_for_dim(int squoze_dim)7837 squoze_overflow_mask_for_dim (int squoze_dim)
7838 {
7839   return ((uint64_t)1<<(squoze_dim * 5 + 1));
7840 }
7841 
squoze_compute_cost_utf5(int offset,int val,int next_val)7842 static int squoze_compute_cost_utf5 (int offset, int val, int next_val)
7843 {
7844   int cost = 0;
7845   cost += squoze_utf5_length (val);
7846   if (next_val)
7847   {
7848     int no_change_cost = squoze_utf5_length (next_val);
7849 #if 0 // not hit in test-corpus, it is easier to specify and
7850       // port the hash consistently without it
7851     offset = squoze_new_offset (val);
7852     int change_cost = 1;
7853     int needed_jump = squoze_needed_jump (offset, next_val);
7854 
7855     if (needed_jump == 0)
7856     {
7857       change_cost += 1;
7858     } else if (needed_jump >= -2 && needed_jump <= 2)
7859     {
7860       change_cost += 2;
7861     }
7862     else if (needed_jump >= -10 && needed_jump <= -10)
7863     {
7864       change_cost += 3;
7865     }
7866     else
7867     {
7868       change_cost += 100;
7869     }
7870 
7871     if (change_cost < no_change_cost)
7872     {
7873       cost += change_cost;
7874     }
7875     else
7876 #endif
7877     {
7878       cost += no_change_cost;
7879     }
7880 
7881   }
7882 
7883 
7884 
7885   return cost;
7886 }
7887 
squoze_compute_cost_squeezed(int offset,int val,int next_val)7888 static int squoze_compute_cost_squeezed (int offset, int val, int next_val)
7889 {
7890   int needed_jump = squoze_needed_jump (offset, val);
7891   int cost = 0;
7892   if (needed_jump == 0)
7893   {
7894     cost += 1;
7895   }
7896   else if (needed_jump >= -2 && needed_jump <= 2)
7897   {
7898     cost += 2;
7899     offset += SQUOZE_JUMP_STRIDE * needed_jump;
7900   }
7901   else if (needed_jump >= -10 && needed_jump <= 10)
7902   {
7903     cost += 3;
7904     offset += SQUOZE_JUMP_STRIDE * needed_jump;
7905   }
7906   else
7907   {
7908     cost += 100; // very expensive, makes the other choice win
7909   }
7910 
7911   if (next_val)
7912   {
7913     int change_cost = 1 + squoze_utf5_length (next_val);
7914     int no_change_cost = 0;
7915     needed_jump = squoze_needed_jump (offset, next_val);
7916 
7917     if (needed_jump == 0)
7918     {
7919       no_change_cost += 1;
7920     }
7921     else if (needed_jump >= -2 && needed_jump <= 2)
7922     {
7923       no_change_cost += 2;
7924     }
7925     else if (needed_jump >= -10 && needed_jump <= 10)
7926     {
7927       no_change_cost += 3;
7928       offset += SQUOZE_JUMP_STRIDE * needed_jump;
7929     }
7930     else
7931     {
7932       no_change_cost = change_cost;
7933     }
7934     if (change_cost < no_change_cost)
7935       cost += change_cost;
7936     else
7937       cost += no_change_cost;
7938   }
7939 
7940   return cost;
7941 }
7942 
7943 
squoze5_encode(const char * input,int inlen,char * output,int * r_outlen,int permit_squeezed,int escape_endzero)7944 static void squoze5_encode (const char *input, int inlen,
7945                             char *output, int *r_outlen,
7946                             int permit_squeezed,
7947                             int escape_endzero)
7948 {
7949   int offset  = squoze_new_offset('a');
7950   int is_utf5 = 1;
7951   int len     = 0;
7952 
7953   for (int i = 0; i < inlen; i+= squoze_utf8_len (input[i]))
7954   {
7955     int val = squoze_utf8_to_unichar (&input[i]);
7956     int next_val = 0;
7957     int first_len = squoze_utf8_len (input[i]);
7958     if (i + first_len < inlen)
7959       next_val = squoze_utf8_to_unichar (&input[i+first_len]);
7960 
7961     if (is_utf5)
7962     {
7963       int change_cost    = squoze_compute_cost_squeezed (offset, val, next_val);
7964       int no_change_cost = squoze_compute_cost_utf5 (offset, val, next_val);
7965 
7966       if (i != 0)          /* ignore cost of initial 'G' */
7967         change_cost += 1;
7968 
7969       if (permit_squeezed && change_cost <= no_change_cost)
7970       {
7971         output[len++] = SQUOZE_ENTER_SQUEEZE;
7972         is_utf5 = 0;
7973       }
7974     }
7975     else
7976     {
7977       int change_cost    = 1 + squoze_compute_cost_utf5 (offset, val, next_val);
7978       int no_change_cost = squoze_compute_cost_squeezed (offset, val, next_val);
7979 
7980       if (change_cost < no_change_cost)
7981       {
7982         output[len++] = SQUOZE_ENTER_UTF5;
7983         is_utf5 = 1;
7984       }
7985     }
7986 
7987     if (!is_utf5)
7988     {
7989       int needed_jump = squoze_needed_jump (offset, val);
7990       if (needed_jump)
7991       {
7992         if (needed_jump >= -2 && needed_jump <= 2)
7993         {
7994           switch (needed_jump)
7995           {
7996             case -1: output[len++] = SQUOZE_DEC_OFFSET_B; break;
7997             case  1: output[len++] = SQUOZE_INC_OFFSET_B; break;
7998             case -2: output[len++] = SQUOZE_DEC_OFFSET_A; break;
7999             case  2: output[len++] = SQUOZE_INC_OFFSET_A; break;
8000           }
8001           offset += SQUOZE_JUMP_STRIDE * needed_jump;
8002         }
8003         else if (needed_jump >= -10 && needed_jump <= 10) {
8004               int encoded_val;
8005               if (needed_jump < -2)
8006                 encoded_val = 5 - needed_jump;
8007               else
8008                 encoded_val = needed_jump - 3;
8009 
8010               output[len++] = (encoded_val / 4) + SQUOZE_DEC_OFFSET_A;
8011               output[len++] = (encoded_val % 4) + SQUOZE_DEC_OFFSET_A;
8012 
8013               offset += SQUOZE_JUMP_STRIDE * needed_jump;
8014         }
8015         else
8016         {
8017           assert(0); // should not be reached
8018           output[len++] = SQUOZE_ENTER_UTF5;
8019           is_utf5 = 1;
8020         }
8021       }
8022     }
8023 
8024     if (is_utf5)
8025     {
8026       int octets = 0;
8027       offset = squoze_new_offset (val);
8028       while (val)
8029       {
8030         int oval = val % 16;
8031         int hi = 16;
8032         if (val / 16) hi = 0;
8033         output[len+ (octets++)] = oval + hi;
8034         val /= 16;
8035       }
8036       for (int j = 0; j < octets/2; j++) // mirror in-place
8037       {                                  // TODO refactor to be single pass
8038         int tmp = output[len+j];
8039         output[len+j] = output[len+octets-1-j];
8040         output[len+octets-1-j] = tmp;
8041       }
8042       len += octets;
8043     }
8044     else
8045     {
8046        if (val == ' ')
8047        {
8048          output[len++] = SQUOZE_SPACE;
8049        }
8050        else
8051        {
8052          output[len++] = val-offset+1;
8053        }
8054     }
8055   }
8056 
8057   if (escape_endzero && len && output[len-1]==0)
8058   {
8059     if (is_utf5)
8060       output[len++] = 16;
8061     else
8062       output[len++] = SQUOZE_ENTER_UTF5;
8063   }
8064   output[len]=0;
8065   if (r_outlen)
8066     *r_outlen = len;
8067 }
8068 
_squoze(int squoze_dim,const char * utf8)8069 static inline uint64_t _squoze (int squoze_dim, const char *utf8)
8070 {
8071   char encoded[4096]="";
8072   int  encoded_len=0;
8073   squoze5_encode (utf8, strlen (utf8), encoded, &encoded_len, 1, 1);
8074   uint64_t hash = 0;
8075   int  utf5 = (encoded[0] != SQUOZE_ENTER_SQUEEZE);
8076   uint64_t multiplier = ((squoze_dim == 6) ? 0x25bd1e975
8077                                            : 0x98173415bd1e975);
8078 
8079   uint64_t overflowed_mask = squoze_overflow_mask_for_dim (squoze_dim);
8080   uint64_t all_bits        = overflowed_mask - 1;
8081 
8082   int rshift = (squoze_dim == 6) ? 8 : 16;
8083 
8084 
8085   if (encoded_len - (!utf5) <= squoze_dim)
8086   {
8087     for (int i = !utf5; i < encoded_len; i++)
8088     {
8089       uint64_t val = encoded[i];
8090       hash = hash | (val << (5*(i-(!utf5))));
8091     }
8092     hash <<= 1; // make room for the bit that encodes utf5 or squeeze
8093   }
8094   else
8095   {
8096     for (int i = 0; i < encoded_len; i++)
8097     {
8098       uint64_t val = encoded[i];
8099       hash = hash ^ val;
8100       hash = hash * multiplier;
8101       hash = hash & all_bits;
8102       hash = hash ^ ((hash >> rshift));
8103     }
8104     hash |= overflowed_mask;
8105   }
8106   return hash | utf5;
8107 }
8108 
8109 typedef struct _CashInterned CashInterned;
8110 
8111 struct _CashInterned {
8112     uint64_t   hash;
8113     char      *string;
8114 };
8115 
8116 static CashInterned *interned = NULL;
8117 static int n_interned = 0;
8118 static int s_interned = 0;
8119 
squoze_interned_find(uint64_t hash)8120 static int squoze_interned_find (uint64_t hash)
8121 {
8122 #if 1
8123   int min = 0;
8124   int max = n_interned - 1;
8125   if (max <= 0)
8126     return 0;
8127   do
8128   {
8129      int pos = (min + max)/2;
8130      if (interned[pos].hash == hash)
8131        return pos;
8132      else if (min == max - 1)
8133        return max;
8134      else if (interned[pos].hash < hash)
8135        min = pos;
8136      else
8137        max = pos;
8138   } while (min != max);
8139   return max;
8140 #else
8141   for (int i = 0; i < n_interned; i++)
8142     if (interned[i].hash > hash)
8143       return i;
8144   return 0;
8145 #endif
8146 }
8147 
squoze(int squoze_dim,const char * utf8)8148 static inline uint64_t squoze (int squoze_dim, const char *utf8)
8149 {
8150   uint64_t hash = _squoze (squoze_dim, utf8);
8151 #ifdef SQUOZE_NO_INTERNING
8152   return hash;
8153 #endif
8154   uint64_t overflowed_mask = squoze_overflow_mask_for_dim (squoze_dim);
8155   if (hash & overflowed_mask)
8156   {
8157     int pos = squoze_interned_find (hash);
8158     if (interned && interned[pos].hash == hash)
8159       return hash;
8160 
8161     if (n_interned + 1 >= s_interned)
8162     {
8163        s_interned = (s_interned + 128)*2;
8164        interned = (CashInterned*)realloc (interned, s_interned * sizeof (CashInterned));
8165     }
8166 
8167     n_interned++;
8168 #if 1
8169     if (n_interned-pos)
8170       memmove (&interned[pos+1], &interned[pos], (n_interned-pos) * sizeof (CashInterned));
8171     // the memmove is the expensive part of testing for collisions
8172     // insertions should be cheaper! at least looking up strings
8173     // is cheap
8174 #else
8175     pos = n_interned-1;
8176 #endif
8177     {
8178       CashInterned *entry = &interned[pos];
8179       entry->hash = hash;
8180       entry->string = strdup (utf8);
8181     }
8182 
8183   }
8184   return hash;
8185 }
8186 
squoze6(const char * utf8)8187 uint32_t squoze6 (const char *utf8)
8188 {
8189   return squoze (6, utf8);
8190 }
8191 
squoze10(const char * utf8)8192 uint64_t squoze10 (const char *utf8)
8193 {
8194   return squoze (10, utf8);
8195 }
8196 
squoze12(const char * utf8)8197 uint64_t squoze12 (const char *utf8)
8198 {
8199   return squoze (12, utf8);
8200 }
8201 
ctx_strhash(const char * str)8202 uint32_t ctx_strhash(const char *str) {
8203   return squoze (6, str);
8204 }
8205 
8206 typedef struct CashUtf5Dec {
8207   int       is_utf5;
8208   int       offset;
8209   void     *write_data;
8210   uint32_t  current;
8211   void    (*append_unichar) (uint32_t unichar, void *write_data);
8212   int       jumped_amount;
8213   int       jump_mode;
8214 } CashUtf5Dec;
8215 
8216 typedef struct CashUtf5DecDefaultData {
8217   uint8_t *buf;
8218   int      length;
8219 } CashUtf5DecDefaultData;
8220 
squoze_decode_utf5_append_unichar_as_utf8(uint32_t unichar,void * write_data)8221 static void squoze_decode_utf5_append_unichar_as_utf8 (uint32_t unichar, void *write_data)
8222 {
8223   CashUtf5DecDefaultData *data = (CashUtf5DecDefaultData*)write_data;
8224   int length = squoze_unichar_to_utf8 (unichar, &data->buf[data->length]);
8225   data->buf[data->length += length] = 0;
8226 }
8227 
squoze_decode_jump(CashUtf5Dec * dec,uint8_t in)8228 static void squoze_decode_jump (CashUtf5Dec *dec, uint8_t in)
8229 {
8230   dec->offset -= SQUOZE_JUMP_STRIDE * dec->jumped_amount;
8231   int jump_len = (dec->jump_mode - SQUOZE_DEC_OFFSET_A) * 4 +
8232                  (in - SQUOZE_DEC_OFFSET_A);
8233   if (jump_len > 7)
8234     jump_len = 5 - jump_len;
8235   else
8236     jump_len += 3;
8237   dec->offset += jump_len * SQUOZE_JUMP_STRIDE;
8238   dec->jumped_amount = 0;
8239 }
8240 
squoze_decode_utf5(CashUtf5Dec * dec,uint8_t in)8241 static void squoze_decode_utf5 (CashUtf5Dec *dec, uint8_t in)
8242 {
8243   if (dec->is_utf5)
8244   {
8245     if (in >= 16)
8246     {
8247       if (dec->current)
8248       {
8249         dec->offset = squoze_new_offset (dec->current);
8250         dec->append_unichar (dec->current, dec->write_data);
8251         dec->current = 0;
8252       }
8253     }
8254     if (in == SQUOZE_ENTER_SQUEEZE)
8255     {
8256       if (dec->current)
8257       {
8258         dec->offset = squoze_new_offset (dec->current);
8259         dec->append_unichar (dec->current, dec->write_data);
8260         dec->current = 0;
8261       }
8262       dec->is_utf5 = 0;
8263     }
8264     else
8265     {
8266       dec->current = dec->current * 16 + (in % 16);
8267     }
8268   }
8269   else
8270   {
8271     if (dec->jumped_amount)
8272     {
8273       switch (in)
8274       {
8275         case SQUOZE_DEC_OFFSET_A:
8276         case SQUOZE_DEC_OFFSET_B:
8277         case SQUOZE_INC_OFFSET_A:
8278         case SQUOZE_INC_OFFSET_B:
8279           squoze_decode_jump (dec, in);
8280           break;
8281         default:
8282           dec->append_unichar (dec->offset + (in - 1), dec->write_data);
8283           dec->jumped_amount = 0;
8284           dec->jump_mode = 0;
8285           break;
8286       }
8287     }
8288     else
8289     {
8290       switch (in)
8291       {
8292         case SQUOZE_ENTER_UTF5:
8293           dec->is_utf5 = 1;
8294           dec->jumped_amount = 0;
8295           dec->jump_mode = 0;
8296           break;
8297         case SQUOZE_SPACE:
8298           dec->append_unichar (' ', dec->write_data);
8299           dec->jumped_amount = 0;
8300           dec->jump_mode = 0;
8301           break;
8302         case SQUOZE_DEC_OFFSET_A:
8303           dec->jumped_amount = -2;
8304           dec->jump_mode = in;
8305           dec->offset += dec->jumped_amount * SQUOZE_JUMP_STRIDE;
8306           break;
8307         case SQUOZE_INC_OFFSET_A:
8308           dec->jumped_amount = 2;
8309           dec->jump_mode = in;
8310           dec->offset += dec->jumped_amount * SQUOZE_JUMP_STRIDE;
8311           break;
8312         case SQUOZE_DEC_OFFSET_B:
8313           dec->jumped_amount = -1;
8314           dec->jump_mode = in;
8315           dec->offset += dec->jumped_amount * SQUOZE_JUMP_STRIDE;
8316           break;
8317         case SQUOZE_INC_OFFSET_B:
8318           dec->jumped_amount = 1;
8319           dec->jump_mode = in;
8320           dec->offset += dec->jumped_amount * SQUOZE_JUMP_STRIDE;
8321           break;
8322         default:
8323           dec->append_unichar (dec->offset + (in - 1), dec->write_data);
8324           dec->jumped_amount = 0;
8325           dec->jump_mode = 0;
8326       }
8327     }
8328   }
8329 }
8330 
squoze_decode_utf5_bytes(int is_utf5,const unsigned char * input,int inlen,char * output,int * r_outlen)8331 static void squoze_decode_utf5_bytes (int is_utf5,
8332                         const unsigned char *input, int inlen,
8333                         char *output, int *r_outlen)
8334 {
8335   CashUtf5DecDefaultData append_data = {(unsigned char*)output, };
8336   CashUtf5Dec dec = {is_utf5,
8337                      squoze_new_offset('a'),
8338                      &append_data,
8339                      0,
8340                      squoze_decode_utf5_append_unichar_as_utf8,
8341                      0
8342                     };
8343   for (int i = 0; i < inlen; i++)
8344     squoze_decode_utf5 (&dec, input[i]);
8345   if (dec.current)
8346     dec.append_unichar (dec.current, dec.write_data);
8347   if (r_outlen)
8348     *r_outlen = append_data.length;
8349 }
8350 
squoze_decode_r(int squoze_dim,uint64_t hash,char * ret,int retlen)8351 static const char *squoze_decode_r (int squoze_dim, uint64_t hash, char *ret, int retlen)
8352 {
8353   uint64_t overflowed_mask = ((uint64_t)1<<(squoze_dim * 5 + 1));
8354 
8355   if (hash & overflowed_mask)
8356   {
8357 #if 0
8358     for (int i = 0; i < n_interned; i++)
8359     {
8360       CashInterned *entry = &interned[i];
8361       if (entry->hash == hash)
8362         return entry->string;
8363     }
8364 #else
8365     int pos = squoze_interned_find (hash);
8366     if (!interned || (interned[pos].hash!=hash))
8367       return NULL;
8368     return interned[pos].string;
8369 #endif
8370     return NULL;
8371   }
8372 
8373   uint8_t utf5[140]=""; // we newer go really high since there isnt room
8374                         // in the integers
8375   uint64_t tmp = hash & (overflowed_mask-1);
8376   int len = 0;
8377   int is_utf5 = tmp & 1;
8378   tmp /= 2;
8379   int in_utf5 = is_utf5;
8380   while (tmp > 0)
8381   {
8382     uint64_t remnant = tmp % 32;
8383     uint64_t val = remnant;
8384 
8385     if      ( in_utf5 && val == SQUOZE_ENTER_SQUEEZE) in_utf5 = 0;
8386     else if (!in_utf5 && val == SQUOZE_ENTER_UTF5) in_utf5 = 1;
8387 
8388     utf5[len++] = val;
8389     tmp -= remnant;
8390     tmp /= 32;
8391   }
8392   utf5[len]=0;
8393   squoze_decode_utf5_bytes (is_utf5, utf5, len, ret, &retlen);
8394   //ret[retlen]=0;
8395   return ret;
8396 }
8397 
8398 /* copy the value as soon as possible, some mitigation is in place
8399  * for more than one value in use and cross-thread interactions.
8400  */
squoze_decode(int squoze_dim,uint64_t hash)8401 static const char *squoze_decode (int squoze_dim, uint64_t hash)
8402 {
8403 #define THREAD __thread  // use thread local storage
8404   static THREAD int no = 0;
8405   static THREAD char ret[8][256];
8406   no ++;
8407   if (no > 7) no = 0;
8408   return squoze_decode_r (squoze_dim, hash, ret[no], 256);
8409 #undef THREAD
8410 }
8411 
squoze6_decode(uint32_t hash)8412 const char *squoze6_decode (uint32_t hash)
8413 {
8414   return squoze_decode (6, hash);
8415 }
8416 
squoze10_decode(uint64_t hash)8417 const char *squoze10_decode (uint64_t hash)
8418 {
8419   return squoze_decode (10, hash);
8420 }
8421 
squoze12_decode(uint64_t hash)8422 const char *squoze12_decode (uint64_t hash)
8423 {
8424   return squoze_decode (12, hash);
8425 }
8426 
8427 static inline uint32_t
squoze_utf8_to_unichar(const char * input)8428 squoze_utf8_to_unichar (const char *input)
8429 {
8430   const uint8_t *utf8 = (const uint8_t *) input;
8431   uint8_t c = utf8[0];
8432   if ( (c & 0x80) == 0)
8433     { return c; }
8434   else if ( (c & 0xE0) == 0xC0)
8435     return ( (utf8[0] & 0x1F) << 6) |
8436            (utf8[1] & 0x3F);
8437   else if ( (c & 0xF0) == 0xE0)
8438     return ( (utf8[0] & 0xF)  << 12) |
8439            ( (utf8[1] & 0x3F) << 6) |
8440            (utf8[2] & 0x3F);
8441   else if ( (c & 0xF8) == 0xF0)
8442     return ( (utf8[0] & 0x7)  << 18) |
8443            ( (utf8[1] & 0x3F) << 12) |
8444            ( (utf8[2] & 0x3F) << 6) |
8445            (utf8[3] & 0x3F);
8446   else if ( (c & 0xFC) == 0xF8)
8447     return ( (utf8[0] & 0x3)  << 24) |
8448            ( (utf8[1] & 0x3F) << 18) |
8449            ( (utf8[2] & 0x3F) << 12) |
8450            ( (utf8[3] & 0x3F) << 6) |
8451            (utf8[4] & 0x3F);
8452   else if ( (c & 0xFE) == 0xFC)
8453     return ( (utf8[0] & 0x1)  << 30) |
8454            ( (utf8[1] & 0x3F) << 24) |
8455            ( (utf8[2] & 0x3F) << 18) |
8456            ( (utf8[3] & 0x3F) << 12) |
8457            ( (utf8[4] & 0x3F) << 6) |
8458            (utf8[5] & 0x3F);
8459   return 0;
8460 }
8461 static inline int
squoze_unichar_to_utf8(uint32_t ch,uint8_t * dest)8462 squoze_unichar_to_utf8 (uint32_t  ch,
8463                       uint8_t  *dest)
8464 {
8465   /* http://www.cprogramming.com/tutorial/utf8.c  */
8466   /*  Basic UTF-8 manipulation routines
8467     by Jeff Bezanson
8468     placed in the public domain Fall 2005 ... */
8469   if (ch < 0x80)
8470     {
8471       dest[0] = (char) ch;
8472       return 1;
8473     }
8474   if (ch < 0x800)
8475     {
8476       dest[0] = (ch>>6) | 0xC0;
8477       dest[1] = (ch & 0x3F) | 0x80;
8478       return 2;
8479     }
8480   if (ch < 0x10000)
8481     {
8482       dest[0] = (ch>>12) | 0xE0;
8483       dest[1] = ( (ch>>6) & 0x3F) | 0x80;
8484       dest[2] = (ch & 0x3F) | 0x80;
8485       return 3;
8486     }
8487   if (ch < 0x110000)
8488     {
8489       dest[0] = (ch>>18) | 0xF0;
8490       dest[1] = ( (ch>>12) & 0x3F) | 0x80;
8491       dest[2] = ( (ch>>6) & 0x3F) | 0x80;
8492       dest[3] = (ch & 0x3F) | 0x80;
8493       return 4;
8494     }
8495   return 0;
8496 }
8497 
8498 static inline int
squoze_utf8_len(const unsigned char first_byte)8499 squoze_utf8_len (const unsigned char first_byte)
8500 {
8501   if      ( (first_byte & 0x80) == 0)
8502     { return 1; } /* ASCII */
8503   else if ( (first_byte & 0xE0) == 0xC0)
8504     { return 2; }
8505   else if ( (first_byte & 0xF0) == 0xE0)
8506     { return 3; }
8507   else if ( (first_byte & 0xF8) == 0xF0)
8508     { return 4; }
8509   return 1;
8510 }
8511 
8512 #endif
8513 /* atty - audio interface and driver for terminals
8514  * Copyright (C) 2020 Øyvind Kolås <pippin@gimp.org>
8515  *
8516  * This library is free software; you can redistribute it and/or
8517  * modify it under the terms of the GNU Lesser General Public
8518  * License as published by the Free Software Foundation; either
8519  * version 2 of the License, or (at your option) any later version.
8520  *
8521  * This library is distributed in the hope that it will be useful,
8522  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8523  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
8524  * Lesser General Public License for more details.
8525  *
8526  * You should have received a copy of the GNU Lesser General Public
8527  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
8528  */
8529 
8530 static const char *base64_map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
bin2base64_group(const unsigned char * in,int remaining,char * out)8531 static void bin2base64_group (const unsigned char *in, int remaining, char *out)
8532 {
8533   unsigned char digit[4] = {0,0,64,64};
8534   int i;
8535   digit[0] = in[0] >> 2;
8536   digit[1] = ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4);
8537   if (remaining > 1)
8538     {
8539       digit[2] = ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6);
8540       if (remaining > 2)
8541         digit[3] = ((in[2] & 0x3f));
8542     }
8543   for (i = 0; i < 4; i++)
8544     out[i] = base64_map[digit[i]];
8545 }
8546 
8547 void
ctx_bin2base64(const void * bin,int bin_length,char * ascii)8548 ctx_bin2base64 (const void *bin,
8549                 int         bin_length,
8550                 char       *ascii)
8551 {
8552   /* this allocation is a hack to ensure we always produce the same result,
8553    * regardless of padding data accidentally taken into account.
8554    */
8555   unsigned char *bin2 = (unsigned char*)calloc (bin_length + 4, 1);
8556   unsigned const char *p = bin2;
8557   int i;
8558   memcpy (bin2, bin, bin_length);
8559   for (i=0; i*3 < bin_length; i++)
8560    {
8561      int remaining = bin_length - i*3;
8562      bin2base64_group (&p[i*3], remaining, &ascii[i*4]);
8563    }
8564   free (bin2);
8565   ascii[i*4]=0;
8566 }
8567 
8568 static unsigned char base64_revmap[255];
base64_revmap_init(void)8569 static void base64_revmap_init (void)
8570 {
8571   static int done = 0;
8572   if (done)
8573     return;
8574 
8575   for (int i = 0; i < 255; i ++)
8576     base64_revmap[i]=255;
8577   for (int i = 0; i < 64; i ++)
8578     base64_revmap[((const unsigned char*)base64_map)[i]]=i;
8579   /* include variants used in URI encodings for decoder,
8580    * even if that is not how we encode
8581   */
8582   base64_revmap['-']=62;
8583   base64_revmap['_']=63;
8584   base64_revmap['+']=62;
8585   base64_revmap['/']=63;
8586 
8587   done = 1;
8588 }
8589 
8590 
8591 int
ctx_base642bin(const char * ascii,int * length,unsigned char * bin)8592 ctx_base642bin (const char    *ascii,
8593                 int           *length,
8594                 unsigned char *bin)
8595 {
8596   int i;
8597   int charno = 0;
8598   int outputno = 0;
8599   int carry = 0;
8600   base64_revmap_init ();
8601   for (i = 0; ascii[i]; i++)
8602     {
8603       int bits = base64_revmap[((const unsigned char*)ascii)[i]];
8604       if (length && outputno > *length)
8605         {
8606           *length = -1;
8607           return -1;
8608         }
8609       if (bits != 255)
8610         {
8611           switch (charno % 4)
8612             {
8613               case 0:
8614                 carry = bits;
8615                 break;
8616               case 1:
8617                 bin[outputno] = (carry << 2) | (bits >> 4);
8618                 outputno++;
8619                 carry = bits & 15;
8620                 break;
8621               case 2:
8622                 bin[outputno] = (carry << 4) | (bits >> 2);
8623                 outputno++;
8624                 carry = bits & 3;
8625                 break;
8626               case 3:
8627                 bin[outputno] = (carry << 6) | bits;
8628                 outputno++;
8629                 carry = 0;
8630                 break;
8631             }
8632           charno++;
8633         }
8634     }
8635   bin[outputno]=0;
8636   if (length)
8637     *length= outputno;
8638   return outputno;
8639 }
8640 #include <stdio.h>
8641 #include <string.h>
8642 
8643 #if CTX_FORMATTER
8644 
ctx_yenc(const char * src,char * dst,int count)8645 static int ctx_yenc (const char *src, char *dst, int count)
8646 {
8647   int out_len = 0;
8648   for (int i = 0; i < count; i ++)
8649   {
8650     int o = (src[i] + 42) % 256;
8651     switch (o)
8652     {
8653       case 0x00: //null
8654       case 0x20: //space// but better safe
8655       case 0x0A: //lf   // than sorry
8656       case 0x0D: //cr
8657       case 0x09: //tab  // not really needed
8658       case 0x10: //datalink escape (used by ctx)
8659       case 0x11: //xoff
8660       case 0x13: //xon
8661       case 0x1b: //
8662       case 0xff: //
8663       case 0x3D: //=
8664         dst[out_len++] = '=';
8665         o = (o + 64) % 256;
8666         /* FALLTHROUGH */
8667       default:
8668         dst[out_len++] = o;
8669         break;
8670     }
8671   }
8672   dst[out_len]=0;
8673   return out_len;
8674 }
8675 #endif
8676 
8677 #if CTX_PARSER
ctx_ydec(const char * tmp_src,char * dst,int count)8678 static int ctx_ydec (const char *tmp_src, char *dst, int count)
8679 {
8680   const char *src = tmp_src;
8681 #if 0
8682   if (tmp_src == dst)
8683   {
8684     src = malloc (count);
8685     memcpy (src, tmp_src, count);
8686   }
8687 #endif
8688   int out_len = 0;
8689   for (int i = 0; i < count; i ++)
8690   {
8691     int o = src[i];
8692     switch (o)
8693     {
8694       case '=':
8695         i++;
8696         o = src[i];
8697         if (o == 'y')
8698         {
8699           dst[out_len]=0;
8700 #if 0
8701           if (tmp_src == dst) free (src);
8702 #endif
8703           return out_len;
8704         }
8705         o = (o-42-64) % 256;
8706         dst[out_len++] = o;
8707         break;
8708       case '\n':
8709       case '\e':
8710       case '\r':
8711       case '\0':
8712         break;
8713       default:
8714         o = (o-42) % 256;
8715         dst[out_len++] = o;
8716         break;
8717     }
8718   }
8719   dst[out_len]=0;
8720 #if 0
8721   if (tmp_src == dst) free (src);
8722 #endif
8723   return out_len;
8724 }
8725 #endif
8726 
8727 #if 0
8728 int main (){
8729   char *input="this is a testæøåÅØ'''\"!:_asdac\n\r";
8730   char  encoded[256]="";
8731   char  decoded[256]="";
8732   int   in_len = strlen (input);
8733   int   out_len;
8734   int   dec_len;
8735 
8736   printf ("input: %s\n", input);
8737 
8738   out_len = ctx_yenc (input, encoded, in_len);
8739   printf ("encoded: %s\n", encoded);
8740 
8741   dec_len = ydec (encoded, encoded, out_len);
8742 
8743   printf ("decoded: %s\n", encoded);
8744 
8745   return 0;
8746 }
8747 #endif
8748 #ifndef CTX_DRAWLIST_H
8749 #define CTX_DRAWLIST_H
8750 
8751 static int
8752 ctx_conts_for_entry (CtxEntry *entry);
8753 static void
8754 ctx_iterator_init (CtxIterator      *iterator,
8755                    CtxDrawlist  *drawlist,
8756                    int               start_pos,
8757                    int               flags);
8758 
8759 int ctx_iterator_pos (CtxIterator *iterator);
8760 
8761 static void
8762 ctx_drawlist_resize (CtxDrawlist *drawlist, int desired_size);
8763 static int
8764 ctx_drawlist_add_single (CtxDrawlist *drawlist, CtxEntry *entry);
8765 static int ctx_drawlist_add_entry (CtxDrawlist *drawlist, CtxEntry *entry);
8766 int
8767 ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry);
8768 int
8769 ctx_add_data (Ctx *ctx, void *data, int length);
8770 
8771 int ctx_drawlist_add_u32 (CtxDrawlist *drawlist, CtxCode code, uint32_t u32[2]);
8772 int ctx_drawlist_add_data (CtxDrawlist *drawlist, const void *data, int length);
8773 
8774 static CtxEntry
8775 ctx_void (CtxCode code);
8776 static inline CtxEntry
8777 ctx_f (CtxCode code, float x, float y);
8778 static CtxEntry
8779 ctx_u32 (CtxCode code, uint32_t x, uint32_t y);
8780 #if 0
8781 static CtxEntry
8782 ctx_s32 (CtxCode code, int32_t x, int32_t y);
8783 #endif
8784 
8785 static inline CtxEntry
8786 ctx_s16 (CtxCode code, int x0, int y0, int x1, int y1);
8787 static CtxEntry
8788 ctx_u8 (CtxCode code,
8789         uint8_t a, uint8_t b, uint8_t c, uint8_t d,
8790         uint8_t e, uint8_t f, uint8_t g, uint8_t h);
8791 
8792 #define CTX_PROCESS_VOID(cmd) do {\
8793   CtxEntry commands[4] = {{cmd}};\
8794   ctx_process (ctx, &commands[0]);}while(0) \
8795 
8796 #define CTX_PROCESS_F(cmd,x,y) do {\
8797   CtxEntry commands[4] = {ctx_f(cmd,x,y),};\
8798   ctx_process (ctx, &commands[0]);}while(0) \
8799 
8800 #define CTX_PROCESS_F1(cmd,x) do {\
8801   CtxEntry commands[4] = {ctx_f(cmd,x,0),};\
8802   ctx_process (ctx, &commands[0]);}while(0) \
8803 
8804 #define CTX_PROCESS_U32(cmd, x, y) do {\
8805   CtxEntry commands[4] = {ctx_u32(cmd, x, y)};\
8806   ctx_process (ctx, &commands[0]);}while(0)
8807 
8808 #define CTX_PROCESS_U8(cmd, x) do {\
8809   CtxEntry commands[4] = {ctx_u8(cmd, x,0,0,0,0,0,0,0)};\
8810   ctx_process (ctx, &commands[0]);}while(0)
8811 
8812 
8813 #if CTX_BITPACK_PACKER
8814 static int
8815 ctx_last_history (CtxDrawlist *drawlist);
8816 #endif
8817 
8818 #if CTX_BITPACK_PACKER
8819 static void
8820 ctx_drawlist_remove_tiny_curves (CtxDrawlist *drawlist, int start_pos);
8821 
8822 static void
8823 ctx_drawlist_bitpack (CtxDrawlist *drawlist, int start_pos);
8824 #endif
8825 
8826 static void
8827 ctx_process_cmd_str (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1);
8828 static void
8829 ctx_process_cmd_str_float (Ctx *ctx, CtxCode code, const char *string, float arg0, float arg1);
8830 static void
8831 ctx_process_cmd_str_with_len (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1, int len);
8832 
8833 #pragma pack(push,1)
8834 typedef struct
8835 CtxSegment {
8836   uint16_t code;
8837   union {
8838    int16_t s16[4];
8839    uint32_t u32[2];
8840   } data;
8841   int32_t val;
8842   int32_t delta;
8843 } CtxSegment;
8844 #pragma pack(pop)
8845 
8846 #endif
8847 
8848 #ifndef __CTX_UTIL_H
8849 #define __CTX_UTIL_H
8850 
ctx_fast_hypotf(float x,float y)8851 inline static float ctx_fast_hypotf (float x, float y)
8852 {
8853   if (x < 0) { x = -x; }
8854   if (y < 0) { y = -y; }
8855   if (x < y)
8856     { return 0.96f * y + 0.4f * x; }
8857   else
8858     { return 0.96f * x + 0.4f * y; }
8859 }
8860 
ctx_str_is_number(const char * str)8861 static int ctx_str_is_number (const char *str)
8862 {
8863   int got_digit = 0;
8864   for (int i = 0; str[i]; i++)
8865   {
8866     if (str[i] >= '0' && str[i] <= '9')
8867     {
8868        got_digit ++;
8869     }
8870     else if (str[i] == '.')
8871     {
8872     }
8873     else
8874       return 0;
8875   }
8876   if (got_digit)
8877     return 1;
8878   return 0;
8879 }
8880 
8881 #if CTX_GET_CONTENTS
8882 
8883 typedef struct CtxFileContent
8884 {
8885   char *path;
8886   unsigned char *contents;
8887   long  length;
8888   int   free_data;
8889 } CtxFileContent;
8890 
8891 CtxList *registered_contents = NULL;
8892 
8893 void
ctx_register_contents(const char * path,const unsigned char * contents,long length,int free_data)8894 ctx_register_contents (const char *path,
8895                        const unsigned char *contents,
8896                        long length,
8897                        int  free_data)
8898 {
8899   // if (path[0] != '/') && strchr(path, ':'))
8900   //   with this check regular use is faster, but we lose
8901   //   generic filesystem overrides..
8902   for (CtxList *l = registered_contents; l; l = l->next)
8903   {
8904     CtxFileContent *c = (CtxFileContent*)l->data;
8905     if (!strcmp (c->path, path))
8906     {
8907        if (c->free_data)
8908        {
8909          free (c->contents);
8910        }
8911        c->free_data = free_data;
8912        c->contents = (unsigned char*)contents;
8913        c->length = length;
8914        return;
8915     }
8916   }
8917   CtxFileContent *c = (CtxFileContent*)calloc (sizeof (CtxFileContent), 1);
8918   c->free_data = free_data;
8919   c->contents = (unsigned char*)contents;
8920   c->length    = length;
8921   ctx_list_append (&registered_contents, c);
8922 }
8923 
8924 void
_ctx_file_set_contents(const char * path,const unsigned char * contents,long length)8925 _ctx_file_set_contents (const char     *path,
8926                         const unsigned char  *contents,
8927                         long            length)
8928 {
8929   FILE *file;
8930   file = fopen (path, "wb");
8931   if (!file)
8932     { return; }
8933   if (length < 0) length = strlen ((const char*)contents);
8934   fwrite (contents, 1, length, file);
8935   fclose (file);
8936 }
8937 
8938 static int
___ctx_file_get_contents(const char * path,unsigned char ** contents,long * length,long max_len)8939 ___ctx_file_get_contents (const char     *path,
8940                           unsigned char **contents,
8941                           long           *length,
8942                           long            max_len)
8943 {
8944   FILE *file;
8945   long  size;
8946   long  remaining;
8947   char *buffer;
8948   file = fopen (path, "rb");
8949   if (!file)
8950     { return -1; }
8951   fseek (file, 0, SEEK_END);
8952   size = remaining = ftell (file);
8953 
8954   if (size > max_len)
8955   {
8956      size = remaining = max_len;
8957   }
8958 
8959   if (length)
8960     { *length =size; }
8961   rewind (file);
8962   buffer = (char*)malloc (size + 8);
8963   if (!buffer)
8964     {
8965       fclose (file);
8966       return -1;
8967     }
8968   remaining -= fread (buffer, 1, remaining, file);
8969   if (remaining)
8970     {
8971       fclose (file);
8972       free (buffer);
8973       return -1;
8974     }
8975   fclose (file);
8976   *contents = (unsigned char*) buffer;
8977   buffer[size] = 0;
8978   return 0;
8979 }
8980 
8981 static int
__ctx_file_get_contents(const char * path,unsigned char ** contents,long * length)8982 __ctx_file_get_contents (const char     *path,
8983                         unsigned char **contents,
8984                         long           *length)
8985 {
8986   return ___ctx_file_get_contents (path, contents, length, 1024*1024*1024);
8987 }
8988 
8989 #if !__COSMOPOLITAN__
8990 #include <limits.h>
8991 #endif
8992 
8993 
8994 
8995 
8996 #endif
8997 
8998 
8999 #endif
9000 
9001 
9002 
9003 static CTX_INLINE int
ctx_conts_for_entry(CtxEntry * entry)9004 ctx_conts_for_entry (CtxEntry *entry)
9005 {
9006     switch (entry->code)
9007     {
9008       case CTX_DATA:
9009         return entry->data.u32[1];
9010       case CTX_LINEAR_GRADIENT:
9011       //case CTX_DEFINE_TEXTURE:
9012         return 1;
9013       case CTX_RADIAL_GRADIENT:
9014       case CTX_ARC:
9015       case CTX_ARC_TO:
9016       case CTX_REL_ARC_TO:
9017       case CTX_CURVE_TO:
9018       case CTX_REL_CURVE_TO:
9019       case CTX_APPLY_TRANSFORM:
9020       case CTX_SOURCE_TRANSFORM:
9021       case CTX_COLOR:
9022       case CTX_ROUND_RECTANGLE:
9023       case CTX_SHADOW_COLOR:
9024         return 2;
9025       case CTX_FILL_RECT:
9026       case CTX_STROKE_RECT:
9027       case CTX_RECTANGLE:
9028       case CTX_VIEW_BOX:
9029       case CTX_REL_QUAD_TO:
9030       case CTX_QUAD_TO:
9031         return 1;
9032 
9033       case CTX_TEXT:
9034       case CTX_LINE_DASH:
9035       case CTX_COLOR_SPACE:
9036       case CTX_STROKE_TEXT:
9037       case CTX_FONT:
9038       case CTX_TEXTURE:
9039         {
9040           int eid_len = entry[1].data.u32[1];
9041           return eid_len + 1;
9042         }
9043       case CTX_DEFINE_TEXTURE:
9044         {
9045           int eid_len = entry[2].data.u32[1];
9046           int pix_len = entry[2 + eid_len + 1].data.u32[1];
9047           return eid_len + pix_len + 2 + 1;
9048         }
9049       default:
9050         return 0;
9051     }
9052 }
9053 
9054 // expanding arc_to to arc can be the job
9055 // of a layer in front of renderer?
9056 //   doing:
9057 //     rectangle
9058 //     arc
9059 //     ... etc reduction to beziers
9060 //     or even do the reduction to
9061 //     polylines directly here...
9062 //     making the rasterizer able to
9063 //     only do poly-lines? will that be faster?
9064 
9065 /* the iterator - should decode bitpacked data as well -
9066  * making the rasterizers simpler, possibly do unpacking
9067  * all the way to absolute coordinates.. unless mixed
9068  * relative/not are wanted.
9069  */
9070 
9071 
9072 static void
ctx_iterator_init(CtxIterator * iterator,CtxDrawlist * drawlist,int start_pos,int flags)9073 ctx_iterator_init (CtxIterator      *iterator,
9074                    CtxDrawlist  *drawlist,
9075                    int               start_pos,
9076                    int               flags)
9077 {
9078   iterator->drawlist   = drawlist;
9079   iterator->flags          = flags;
9080   iterator->bitpack_pos    = 0;
9081   iterator->bitpack_length = 0;
9082   iterator->pos            = start_pos;
9083   iterator->end_pos        = drawlist->count;
9084   iterator->first_run      = 1; // -1 is a marker used for first run
9085   ctx_memset (iterator->bitpack_command, 0, sizeof (iterator->bitpack_command) );
9086 }
9087 
ctx_iterator_pos(CtxIterator * iterator)9088 int ctx_iterator_pos (CtxIterator *iterator)
9089 {
9090   return iterator->pos;
9091 }
9092 
_ctx_iterator_next(CtxIterator * iterator)9093 static CtxEntry *_ctx_iterator_next (CtxIterator *iterator)
9094 {
9095   int ret = iterator->pos;
9096   CtxEntry *entry = &iterator->drawlist->entries[ret];
9097   if (CTX_UNLIKELY(ret >= iterator->end_pos))
9098     { return NULL; }
9099 
9100   if (CTX_UNLIKELY(iterator->first_run))
9101       iterator->first_run = 0;
9102   else
9103      iterator->pos += (ctx_conts_for_entry (entry) + 1);
9104 
9105   if (CTX_UNLIKELY(iterator->pos >= iterator->end_pos))
9106     { return NULL; }
9107   return &iterator->drawlist->entries[iterator->pos];
9108 }
9109 
9110 // 6024x4008
9111 #if CTX_BITPACK
9112 static void
ctx_iterator_expand_s8_args(CtxIterator * iterator,CtxEntry * entry)9113 ctx_iterator_expand_s8_args (CtxIterator *iterator, CtxEntry *entry)
9114 {
9115   int no = 0;
9116   for (int cno = 0; cno < 4; cno++)
9117     for (int d = 0; d < 2; d++, no++)
9118       iterator->bitpack_command[cno].data.f[d] =
9119         entry->data.s8[no] * 1.0f / CTX_SUBDIV;
9120   iterator->bitpack_command[0].code =
9121     iterator->bitpack_command[1].code =
9122       iterator->bitpack_command[2].code =
9123         iterator->bitpack_command[3].code = CTX_CONT;
9124   iterator->bitpack_length = 4;
9125   iterator->bitpack_pos = 0;
9126 }
9127 
9128 static void
ctx_iterator_expand_s16_args(CtxIterator * iterator,CtxEntry * entry)9129 ctx_iterator_expand_s16_args (CtxIterator *iterator, CtxEntry *entry)
9130 {
9131   int no = 0;
9132   for (int cno = 0; cno < 2; cno++)
9133     for (int d = 0; d < 2; d++, no++)
9134       iterator->bitpack_command[cno].data.f[d] = entry->data.s16[no] * 1.0f /
9135           CTX_SUBDIV;
9136   iterator->bitpack_command[0].code =
9137     iterator->bitpack_command[1].code = CTX_CONT;
9138   iterator->bitpack_length = 2;
9139   iterator->bitpack_pos    = 0;
9140 }
9141 #endif
9142 
9143 CtxCommand *
ctx_iterator_next(CtxIterator * iterator)9144 ctx_iterator_next (CtxIterator *iterator)
9145 {
9146   CtxEntry *ret;
9147 #if CTX_BITPACK
9148   int expand_bitpack = iterator->flags & CTX_ITERATOR_EXPAND_BITPACK;
9149 again:
9150   if (CTX_UNLIKELY(iterator->bitpack_length))
9151     {
9152       ret = &iterator->bitpack_command[iterator->bitpack_pos];
9153       iterator->bitpack_pos += (ctx_conts_for_entry (ret) + 1);
9154       if (iterator->bitpack_pos >= iterator->bitpack_length)
9155         {
9156           iterator->bitpack_length = 0;
9157         }
9158       return (CtxCommand *) ret;
9159     }
9160 #endif
9161   ret = _ctx_iterator_next (iterator);
9162 #if CTX_BITPACK
9163   if (CTX_UNLIKELY(ret && expand_bitpack))
9164     switch ((CtxCode)(ret->code))
9165       {
9166         case CTX_REL_CURVE_TO_REL_LINE_TO:
9167           ctx_iterator_expand_s8_args (iterator, ret);
9168           iterator->bitpack_command[0].code = CTX_REL_CURVE_TO;
9169           iterator->bitpack_command[1].code =
9170           iterator->bitpack_command[2].code = CTX_CONT;
9171           iterator->bitpack_command[3].code = CTX_REL_LINE_TO;
9172           // 0.0 here is a common optimization - so check for it
9173           if (ret->data.s8[6]== 0 && ret->data.s8[7] == 0)
9174             { iterator->bitpack_length = 3; }
9175           else
9176             iterator->bitpack_length          = 4;
9177           goto again;
9178         case CTX_REL_LINE_TO_REL_CURVE_TO:
9179           ctx_iterator_expand_s8_args (iterator, ret);
9180           iterator->bitpack_command[0].code = CTX_REL_LINE_TO;
9181           iterator->bitpack_command[1].code = CTX_REL_CURVE_TO;
9182           iterator->bitpack_length          = 2;
9183           goto again;
9184         case CTX_REL_CURVE_TO_REL_MOVE_TO:
9185           ctx_iterator_expand_s8_args (iterator, ret);
9186           iterator->bitpack_command[0].code = CTX_REL_CURVE_TO;
9187           iterator->bitpack_command[3].code = CTX_REL_MOVE_TO;
9188           iterator->bitpack_length          = 4;
9189           goto again;
9190         case CTX_REL_LINE_TO_X4:
9191           ctx_iterator_expand_s8_args (iterator, ret);
9192           iterator->bitpack_command[0].code =
9193           iterator->bitpack_command[1].code =
9194           iterator->bitpack_command[2].code =
9195           iterator->bitpack_command[3].code = CTX_REL_LINE_TO;
9196           iterator->bitpack_length          = 4;
9197           goto again;
9198         case CTX_REL_QUAD_TO_S16:
9199           ctx_iterator_expand_s16_args (iterator, ret);
9200           iterator->bitpack_command[0].code = CTX_REL_QUAD_TO;
9201           iterator->bitpack_length          = 1;
9202           goto again;
9203         case CTX_REL_QUAD_TO_REL_QUAD_TO:
9204           ctx_iterator_expand_s8_args (iterator, ret);
9205           iterator->bitpack_command[0].code =
9206           iterator->bitpack_command[2].code = CTX_REL_QUAD_TO;
9207           iterator->bitpack_length          = 3;
9208           goto again;
9209         case CTX_REL_LINE_TO_X2:
9210           ctx_iterator_expand_s16_args (iterator, ret);
9211           iterator->bitpack_command[0].code =
9212           iterator->bitpack_command[1].code = CTX_REL_LINE_TO;
9213           iterator->bitpack_length          = 2;
9214           goto again;
9215         case CTX_REL_LINE_TO_REL_MOVE_TO:
9216           ctx_iterator_expand_s16_args (iterator, ret);
9217           iterator->bitpack_command[0].code = CTX_REL_LINE_TO;
9218           iterator->bitpack_command[1].code = CTX_REL_MOVE_TO;
9219           iterator->bitpack_length          = 2;
9220           goto again;
9221         case CTX_MOVE_TO_REL_LINE_TO:
9222           ctx_iterator_expand_s16_args (iterator, ret);
9223           iterator->bitpack_command[0].code = CTX_MOVE_TO;
9224           iterator->bitpack_command[1].code = CTX_REL_MOVE_TO;
9225           iterator->bitpack_length          = 2;
9226           goto again;
9227         case CTX_FILL_MOVE_TO:
9228           iterator->bitpack_command[1]      = *ret;
9229           iterator->bitpack_command[0].code = CTX_FILL;
9230           iterator->bitpack_command[1].code = CTX_MOVE_TO;
9231           iterator->bitpack_pos             = 0;
9232           iterator->bitpack_length          = 2;
9233           goto again;
9234         case CTX_LINEAR_GRADIENT:
9235         case CTX_QUAD_TO:
9236         case CTX_REL_QUAD_TO:
9237         case CTX_TEXTURE:
9238         case CTX_RECTANGLE:
9239         case CTX_VIEW_BOX:
9240         case CTX_ARC:
9241         case CTX_ARC_TO:
9242         case CTX_REL_ARC_TO:
9243         case CTX_COLOR:
9244         case CTX_SHADOW_COLOR:
9245         case CTX_RADIAL_GRADIENT:
9246         case CTX_CURVE_TO:
9247         case CTX_REL_CURVE_TO:
9248         case CTX_APPLY_TRANSFORM:
9249         case CTX_SOURCE_TRANSFORM:
9250         case CTX_ROUND_RECTANGLE:
9251         case CTX_TEXT:
9252         case CTX_STROKE_TEXT:
9253         case CTX_FONT:
9254         case CTX_LINE_DASH:
9255         case CTX_FILL:
9256         case CTX_NOP:
9257         case CTX_MOVE_TO:
9258         case CTX_LINE_TO:
9259         case CTX_REL_MOVE_TO:
9260         case CTX_REL_LINE_TO:
9261         case CTX_VER_LINE_TO:
9262         case CTX_REL_VER_LINE_TO:
9263         case CTX_HOR_LINE_TO:
9264         case CTX_REL_HOR_LINE_TO:
9265         case CTX_ROTATE:
9266         case CTX_FLUSH:
9267         case CTX_TEXT_ALIGN:
9268         case CTX_TEXT_BASELINE:
9269         case CTX_TEXT_DIRECTION:
9270         case CTX_MITER_LIMIT:
9271         case CTX_GLOBAL_ALPHA:
9272         case CTX_COMPOSITING_MODE:
9273         case CTX_BLEND_MODE:
9274         case CTX_SHADOW_BLUR:
9275         case CTX_SHADOW_OFFSET_X:
9276         case CTX_SHADOW_OFFSET_Y:
9277         case CTX_RESET:
9278         case CTX_EXIT:
9279         case CTX_BEGIN_PATH:
9280         case CTX_CLOSE_PATH:
9281         case CTX_SAVE:
9282         case CTX_CLIP:
9283         case CTX_PRESERVE:
9284         case CTX_DEFINE_GLYPH:
9285         case CTX_IDENTITY:
9286         case CTX_FONT_SIZE:
9287         case CTX_START_GROUP:
9288         case CTX_END_GROUP:
9289         case CTX_RESTORE:
9290         case CTX_LINE_WIDTH:
9291         case CTX_LINE_DASH_OFFSET:
9292         case CTX_STROKE:
9293         case CTX_KERNING_PAIR:
9294         case CTX_SCALE:
9295         case CTX_GLYPH:
9296         case CTX_SET_PIXEL:
9297         case CTX_FILL_RULE:
9298         case CTX_LINE_CAP:
9299         case CTX_LINE_JOIN:
9300         case CTX_NEW_PAGE:
9301         case CTX_SET_KEY:
9302         case CTX_TRANSLATE:
9303         case CTX_DEFINE_TEXTURE:
9304         case CTX_GRADIENT_STOP:
9305         case CTX_DATA: // XXX : would be better if we hide the DATAs
9306         case CTX_CONT: // shouldnt happen
9307         default:
9308           iterator->bitpack_length = 0;
9309           return (CtxCommand *) ret;
9310 #if 0
9311         default: // XXX remove - and get better warnings
9312           iterator->bitpack_command[0] = ret[0];
9313           iterator->bitpack_command[1] = ret[1];
9314           iterator->bitpack_command[2] = ret[2];
9315           iterator->bitpack_command[3] = ret[3];
9316           iterator->bitpack_command[4] = ret[4];
9317           iterator->bitpack_pos = 0;
9318           iterator->bitpack_length = 1;
9319           goto again;
9320 #endif
9321       }
9322 #endif
9323   return (CtxCommand *) ret;
9324 }
9325 
9326 static void ctx_drawlist_compact (CtxDrawlist *drawlist);
9327 static void
ctx_drawlist_resize(CtxDrawlist * drawlist,int desired_size)9328 ctx_drawlist_resize (CtxDrawlist *drawlist, int desired_size)
9329 {
9330   int flags=drawlist->flags;
9331 #if CTX_DRAWLIST_STATIC
9332   if (flags & CTX_DRAWLIST_EDGE_LIST)
9333     {
9334       static CtxSegment sbuf[CTX_MAX_EDGE_LIST_SIZE];
9335       drawlist->entries = (CtxEntry*)&sbuf[0];
9336       drawlist->size = CTX_MAX_EDGE_LIST_SIZE;
9337     }
9338   else if (flags & CTX_DRAWLIST_CURRENT_PATH)
9339     {
9340       static CtxEntry sbuf[CTX_MAX_EDGE_LIST_SIZE];
9341       drawlist->entries = &sbuf[0];
9342       drawlist->size = CTX_MAX_EDGE_LIST_SIZE;
9343     }
9344   else
9345     {
9346       static CtxEntry sbuf[CTX_MAX_JOURNAL_SIZE];
9347       drawlist->entries = &sbuf[0];
9348       drawlist->size = CTX_MAX_JOURNAL_SIZE;
9349       if(0)ctx_drawlist_compact (drawlist);
9350     }
9351 #else
9352   int new_size = desired_size;
9353   int min_size = CTX_MIN_JOURNAL_SIZE;
9354   int max_size = CTX_MAX_JOURNAL_SIZE;
9355   if ((flags & CTX_DRAWLIST_EDGE_LIST))
9356     {
9357       min_size = CTX_MIN_EDGE_LIST_SIZE;
9358       max_size = CTX_MAX_EDGE_LIST_SIZE;
9359     }
9360   else if (flags & CTX_DRAWLIST_CURRENT_PATH)
9361     {
9362       min_size = CTX_MIN_EDGE_LIST_SIZE;
9363       max_size = CTX_MAX_EDGE_LIST_SIZE;
9364     }
9365   else
9366     {
9367 #if 0
9368       ctx_drawlist_compact (drawlist);
9369 #endif
9370     }
9371 
9372   if (CTX_UNLIKELY(new_size < drawlist->size))
9373     { return; }
9374   if (CTX_UNLIKELY(drawlist->size == max_size))
9375     { return; }
9376   new_size = ctx_maxi (new_size, min_size);
9377   //if (new_size < drawlist->count)
9378   //  { new_size = drawlist->count + 4; }
9379   new_size = ctx_mini (new_size, max_size);
9380   if (new_size != drawlist->size)
9381     {
9382       int item_size = sizeof (CtxEntry);
9383       if (flags & CTX_DRAWLIST_EDGE_LIST) item_size = sizeof (CtxSegment);
9384       //fprintf (stderr, "growing drawlist %p %i to %d from %d\n", drawlist, flags, new_size, drawlist->size);
9385   if (drawlist->entries)
9386     {
9387       //printf ("grow %p to %d from %d\n", drawlist, new_size, drawlist->size);
9388       CtxEntry *ne =  (CtxEntry *) malloc (item_size * new_size);
9389       memcpy (ne, drawlist->entries, drawlist->size * item_size );
9390       free (drawlist->entries);
9391       drawlist->entries = ne;
9392       //drawlist->entries = (CtxEntry*)malloc (drawlist->entries, item_size * new_size);
9393     }
9394   else
9395     {
9396       //fprintf (stderr, "allocating for %p %d\n", drawlist, new_size);
9397       drawlist->entries = (CtxEntry *) malloc (item_size * new_size);
9398     }
9399   drawlist->size = new_size;
9400     }
9401   //fprintf (stderr, "drawlist %p is %d\n", drawlist, drawlist->size);
9402 #endif
9403 }
9404 
9405 static void
ctx_edgelist_resize(CtxDrawlist * drawlist,int desired_size)9406 ctx_edgelist_resize (CtxDrawlist *drawlist, int desired_size)
9407 {
9408 #if CTX_DRAWLIST_STATIC
9409     {
9410       static CtxSegment sbuf[CTX_MAX_EDGE_LIST_SIZE];
9411       drawlist->entries = (CtxEntry*)&sbuf[0];
9412       drawlist->size = CTX_MAX_EDGE_LIST_SIZE;
9413     }
9414 #else
9415   int new_size = desired_size;
9416   int min_size = CTX_MIN_JOURNAL_SIZE;
9417   int max_size = CTX_MAX_JOURNAL_SIZE;
9418     {
9419       min_size = CTX_MIN_EDGE_LIST_SIZE;
9420       max_size = CTX_MAX_EDGE_LIST_SIZE;
9421     }
9422 
9423   if (CTX_UNLIKELY(drawlist->size == max_size))
9424     { return; }
9425   new_size = ctx_maxi (new_size, min_size);
9426   //if (new_size < drawlist->count)
9427   //  { new_size = drawlist->count + 4; }
9428   new_size = ctx_mini (new_size, max_size);
9429   if (new_size != drawlist->size)
9430     {
9431       int item_size = item_size = sizeof (CtxSegment);
9432       //fprintf (stderr, "growing drawlist %p %i to %d from %d\n", drawlist, flags, new_size, drawlist->size);
9433   if (drawlist->entries)
9434     {
9435       //printf ("grow %p to %d from %d\n", drawlist, new_size, drawlist->size);
9436       CtxEntry *ne =  (CtxEntry *) malloc (item_size * new_size);
9437       memcpy (ne, drawlist->entries, drawlist->size * item_size );
9438       free (drawlist->entries);
9439       drawlist->entries = ne;
9440       //drawlist->entries = (CtxEntry*)malloc (drawlist->entries, item_size * new_size);
9441     }
9442   else
9443     {
9444       //fprintf (stderr, "allocating for %p %d\n", drawlist, new_size);
9445       drawlist->entries = (CtxEntry *) malloc (item_size * new_size);
9446     }
9447   drawlist->size = new_size;
9448     }
9449   //fprintf (stderr, "drawlist %p is %d\n", drawlist, drawlist->size);
9450 #endif
9451 }
9452 
9453 
9454 static inline int
ctx_drawlist_add_single(CtxDrawlist * drawlist,CtxEntry * entry)9455 ctx_drawlist_add_single (CtxDrawlist *drawlist, CtxEntry *entry)
9456 {
9457   int max_size = CTX_MAX_JOURNAL_SIZE;
9458   int ret = drawlist->count;
9459   int flags = drawlist->flags;
9460   if (CTX_LIKELY((flags & CTX_DRAWLIST_EDGE_LIST ||
9461        flags & CTX_DRAWLIST_CURRENT_PATH)))
9462     {
9463       max_size = CTX_MAX_EDGE_LIST_SIZE;
9464     }
9465   if (CTX_UNLIKELY(flags & CTX_DRAWLIST_DOESNT_OWN_ENTRIES))
9466     {
9467       return ret;
9468     }
9469   if (CTX_UNLIKELY(ret + 64 >= drawlist->size - 40))
9470     {
9471       int new_ = CTX_MAX (drawlist->size * 2, ret + 1024);
9472       ctx_drawlist_resize (drawlist, new_);
9473     }
9474 
9475   if (CTX_UNLIKELY(drawlist->count >= max_size - 20))
9476     {
9477       return 0;
9478     }
9479   if ((flags & CTX_DRAWLIST_EDGE_LIST))
9480     ((CtxSegment*)(drawlist->entries))[drawlist->count] = *(CtxSegment*)entry;
9481   else
9482     drawlist->entries[drawlist->count] = *entry;
9483   ret = drawlist->count;
9484   drawlist->count++;
9485   return ret;
9486 }
9487 
9488 static inline int
ctx_edgelist_add_single(CtxDrawlist * drawlist,CtxEntry * entry)9489 ctx_edgelist_add_single (CtxDrawlist *drawlist, CtxEntry *entry)
9490 {
9491   int max_size = CTX_MAX_EDGE_LIST_SIZE;
9492   int ret = drawlist->count;
9493   if ((ret + 64 >= drawlist->size - 40))
9494     {
9495       int new_ = CTX_MAX (drawlist->size * 2, ret + 1024);
9496       ctx_edgelist_resize (drawlist, new_);
9497     }
9498 
9499   if (CTX_UNLIKELY(drawlist->count >= max_size - 20))
9500     {
9501       return 0;
9502     }
9503   ((CtxSegment*)(drawlist->entries))[drawlist->count] = *(CtxSegment*)entry;
9504   ret = drawlist->count;
9505   drawlist->count++;
9506   return ret;
9507 }
9508 
9509 int
ctx_add_single(Ctx * ctx,void * entry)9510 ctx_add_single (Ctx *ctx, void *entry)
9511 {
9512   return ctx_drawlist_add_single (&ctx->drawlist, (CtxEntry *) entry);
9513 }
9514 
9515 static inline int
ctx_drawlist_add_entry(CtxDrawlist * drawlist,CtxEntry * entry)9516 ctx_drawlist_add_entry (CtxDrawlist *drawlist, CtxEntry *entry)
9517 {
9518   int length = ctx_conts_for_entry (entry) + 1;
9519   int ret = 0;
9520   for (int i = 0; i < length; i ++)
9521     {
9522       ret = ctx_drawlist_add_single (drawlist, &entry[i]);
9523     }
9524   return ret;
9525 }
9526 
9527 #if 0
9528 int
9529 ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry)
9530 {
9531   int length = ctx_conts_for_entry (entry) + 1;
9532   int tmp_pos = ctx_drawlist_add_entry (drawlist, entry);
9533   for (int i = 0; i < length; i++)
9534   {
9535     for (int j = pos + i + 1; j < tmp_pos; j++)
9536       drawlist->entries[j] = entry[j-1];
9537     drawlist->entries[pos + i] = entry[i];
9538   }
9539   return pos;
9540 }
9541 #endif
9542 int
ctx_drawlist_insert_entry(CtxDrawlist * drawlist,int pos,CtxEntry * entry)9543 ctx_drawlist_insert_entry (CtxDrawlist *drawlist, int pos, CtxEntry *entry)
9544 {
9545   int length = ctx_conts_for_entry (entry) + 1;
9546   int tmp_pos = ctx_drawlist_add_entry (drawlist, entry);
9547 #if 1
9548   for (int i = 0; i < length; i++)
9549   {
9550     for (int j = tmp_pos; j > pos + i; j--)
9551       drawlist->entries[j] = drawlist->entries[j-1];
9552     drawlist->entries[pos + i] = entry[i];
9553   }
9554   return pos;
9555 #endif
9556   return tmp_pos;
9557 }
9558 
ctx_append_drawlist(Ctx * ctx,void * data,int length)9559 int ctx_append_drawlist (Ctx *ctx, void *data, int length)
9560 {
9561   CtxEntry *entries = (CtxEntry *) data;
9562   if (length % sizeof (CtxEntry) )
9563     {
9564       ctx_log("drawlist not multiple of 9\n");
9565       return -1;
9566     }
9567   for (unsigned int i = 0; i < length / sizeof (CtxEntry); i++)
9568     {
9569       ctx_drawlist_add_single (&ctx->drawlist, &entries[i]);
9570     }
9571   return 0;
9572 }
9573 
ctx_set_drawlist(Ctx * ctx,void * data,int length)9574 int ctx_set_drawlist (Ctx *ctx, void *data, int length)
9575 {
9576   CtxDrawlist *drawlist = &ctx->drawlist;
9577   if (drawlist->flags & CTX_DRAWLIST_DOESNT_OWN_ENTRIES)
9578     {
9579       return -1;
9580     }
9581   ctx->drawlist.count = 0;
9582   if (!data || length == 0)
9583     return 0;
9584   if (CTX_UNLIKELY(length % 9)) return -1;
9585   ctx_drawlist_resize (drawlist, length/9);
9586   memcpy (drawlist->entries, data, length);
9587   drawlist->count = length / 9;
9588   return length;
9589 }
9590 
ctx_get_drawlist_count(Ctx * ctx)9591 int ctx_get_drawlist_count (Ctx *ctx)
9592 {
9593   return ctx->drawlist.count;
9594 }
9595 
ctx_get_drawlist(Ctx * ctx)9596 const CtxEntry *ctx_get_drawlist (Ctx *ctx)
9597 {
9598   return ctx->drawlist.entries;
9599 }
9600 
9601 int
ctx_add_data(Ctx * ctx,void * data,int length)9602 ctx_add_data (Ctx *ctx, void *data, int length)
9603 {
9604   if (CTX_UNLIKELY(length % sizeof (CtxEntry) ))
9605     {
9606       //ctx_log("err\n");
9607       return -1;
9608     }
9609   /* some more input verification might be in order.. like
9610    * verify that it is well-formed up to length?
9611    *
9612    * also - it would be very useful to stop processing
9613    * upon flush - and do drawlist resizing.
9614    */
9615   return ctx_drawlist_add_entry (&ctx->drawlist, (CtxEntry *) data);
9616 }
9617 
ctx_drawlist_add_u32(CtxDrawlist * drawlist,CtxCode code,uint32_t u32[2])9618 int ctx_drawlist_add_u32 (CtxDrawlist *drawlist, CtxCode code, uint32_t u32[2])
9619 {
9620   CtxEntry entry[3] = {{code, {{0},}},};
9621   entry[0].data.u32[0] = u32[0];
9622   entry[0].data.u32[1] = u32[1];
9623   return ctx_drawlist_add_single (drawlist, &entry[0]);
9624 }
9625 
ctx_drawlist_add_data(CtxDrawlist * drawlist,const void * data,int length)9626 int ctx_drawlist_add_data (CtxDrawlist *drawlist, const void *data, int length)
9627 {
9628   CtxEntry entry[3] = {{CTX_DATA, {{0},}}};
9629   entry[0].data.u32[0] = 0;
9630   entry[0].data.u32[1] = 0;
9631   int ret = ctx_drawlist_add_single (drawlist, &entry[0]);
9632   if (CTX_UNLIKELY(!data)) { return -1; }
9633   int length_in_blocks;
9634   if (length <= 0) { length = strlen ( (char *) data) + 1; }
9635   length_in_blocks = length / sizeof (CtxEntry);
9636   length_in_blocks += (length % sizeof (CtxEntry) ) ?1:0;
9637   if (drawlist->count + length_in_blocks + 4 > drawlist->size)
9638     { ctx_drawlist_resize (drawlist, drawlist->count * 1.2 + length_in_blocks + 32); }
9639   if (CTX_UNLIKELY(drawlist->count >= drawlist->size))
9640     { return -1; }
9641   drawlist->count += length_in_blocks;
9642   drawlist->entries[ret].data.u32[0] = length;
9643   drawlist->entries[ret].data.u32[1] = length_in_blocks;
9644   memcpy (&drawlist->entries[ret+1], data, length);
9645   {
9646     //int reverse = ctx_drawlist_add (drawlist, CTX_DATA_REV);
9647     CtxEntry entry[3] = {{CTX_DATA_REV, {{0},}}};
9648     entry[0].data.u32[0] = length;
9649     entry[0].data.u32[1] = length_in_blocks;
9650     ctx_drawlist_add_single (drawlist, &entry[0]);
9651 
9652     /* this reverse marker exist to enable more efficient
9653        front to back traversal, can be ignored in other
9654        direction, is this needed after string setters as well?
9655      */
9656   }
9657   return ret;
9658 }
9659 
9660 static inline CtxEntry
ctx_void(CtxCode code)9661 ctx_void (CtxCode code)
9662 {
9663   CtxEntry command;
9664   command.code = code;
9665   return command;
9666 }
9667 
9668 static inline CtxEntry
ctx_f(CtxCode code,float x,float y)9669 ctx_f (CtxCode code, float x, float y)
9670 {
9671   CtxEntry command;
9672   command.code = code;
9673   command.data.f[0] = x;
9674   command.data.f[1] = y;
9675   return command;
9676 }
9677 
9678 static CtxEntry
ctx_u32(CtxCode code,uint32_t x,uint32_t y)9679 ctx_u32 (CtxCode code, uint32_t x, uint32_t y)
9680 {
9681   CtxEntry command = ctx_void (code);
9682   command.data.u32[0] = x;
9683   command.data.u32[1] = y;
9684   return command;
9685 }
9686 
9687 #if 0
9688 static CtxEntry
9689 ctx_s32 (CtxCode code, int32_t x, int32_t y)
9690 {
9691   CtxEntry command = ctx_void (code);
9692   command.data.s32[0] = x;
9693   command.data.s32[1] = y;
9694   return command;
9695 }
9696 #endif
9697 
9698 static inline CtxEntry
ctx_s16(CtxCode code,int x0,int y0,int x1,int y1)9699 ctx_s16 (CtxCode code, int x0, int y0, int x1, int y1)
9700 {
9701   CtxEntry command;
9702   command.code = code;
9703   command.data.s16[0] = x0;
9704   command.data.s16[1] = y0;
9705   command.data.s16[2] = x1;
9706   command.data.s16[3] = y1;
9707   return command;
9708 }
9709 
9710 static inline CtxSegment
ctx_segment_s16(CtxCode code,int x0,int y0,int x1,int y1)9711 ctx_segment_s16 (CtxCode code, int x0, int y0, int x1, int y1)
9712 {
9713   CtxSegment command;
9714   command.code = code;
9715   command.data.s16[0] = x0;
9716   command.data.s16[1] = y0;
9717   command.data.s16[2] = x1;
9718   command.data.s16[3] = y1;
9719   return command;
9720 }
9721 
9722 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)9723 ctx_u8 (CtxCode code,
9724         uint8_t a, uint8_t b, uint8_t c, uint8_t d,
9725         uint8_t e, uint8_t f, uint8_t g, uint8_t h)
9726 {
9727   CtxEntry command;
9728   command.code = code;
9729   command.data.u8[0] = a;
9730   command.data.u8[1] = b;
9731   command.data.u8[2] = c;
9732   command.data.u8[3] = d;
9733   command.data.u8[4] = e;
9734   command.data.u8[5] = f;
9735   command.data.u8[6] = g;
9736   command.data.u8[7] = h;
9737   return command;
9738 }
9739 
9740 #define CTX_PROCESS_VOID(cmd) do {\
9741   CtxEntry commands[4] = {{cmd}};\
9742   ctx_process (ctx, &commands[0]);}while(0) \
9743 
9744 #define CTX_PROCESS_F(cmd,x,y) do {\
9745   CtxEntry commands[4] = {ctx_f(cmd,x,y),};\
9746   ctx_process (ctx, &commands[0]);}while(0) \
9747 
9748 #define CTX_PROCESS_F1(cmd,x) do {\
9749   CtxEntry commands[4] = {ctx_f(cmd,x,0),};\
9750   ctx_process (ctx, &commands[0]);}while(0) \
9751 
9752 #define CTX_PROCESS_U32(cmd, x, y) do {\
9753   CtxEntry commands[4] = {ctx_u32(cmd, x, y)};\
9754   ctx_process (ctx, &commands[0]);}while(0)
9755 
9756 #define CTX_PROCESS_U8(cmd, x) do {\
9757   CtxEntry commands[4] = {ctx_u8(cmd, x,0,0,0,0,0,0,0)};\
9758   ctx_process (ctx, &commands[0]);}while(0)
9759 
9760 
9761 static void
ctx_process_cmd_str_with_len(Ctx * ctx,CtxCode code,const char * string,uint32_t arg0,uint32_t arg1,int len)9762 ctx_process_cmd_str_with_len (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1, int len)
9763 {
9764   CtxEntry commands[1 + 2 + (len+1+1)/9];
9765   ctx_memset (commands, 0, sizeof (commands) );
9766   commands[0] = ctx_u32 (code, arg0, arg1);
9767   commands[1].code = CTX_DATA;
9768   commands[1].data.u32[0] = len;
9769   commands[1].data.u32[1] = (len+1+1)/9 + 1;
9770   memcpy( (char *) &commands[2].data.u8[0], string, len);
9771   ( (char *) (&commands[2].data.u8[0]) ) [len]=0;
9772   ctx_process (ctx, commands);
9773 }
9774 
9775 static void
ctx_process_cmd_str(Ctx * ctx,CtxCode code,const char * string,uint32_t arg0,uint32_t arg1)9776 ctx_process_cmd_str (Ctx *ctx, CtxCode code, const char *string, uint32_t arg0, uint32_t arg1)
9777 {
9778   ctx_process_cmd_str_with_len (ctx, code, string, arg0, arg1, strlen (string));
9779 }
9780 
9781 static void
ctx_process_cmd_str_float(Ctx * ctx,CtxCode code,const char * string,float arg0,float arg1)9782 ctx_process_cmd_str_float (Ctx *ctx, CtxCode code, const char *string, float arg0, float arg1)
9783 {
9784   uint32_t iarg0;
9785   uint32_t iarg1;
9786   memcpy (&iarg0, &arg0, sizeof (iarg0));
9787   memcpy (&iarg1, &arg1, sizeof (iarg1));
9788   ctx_process_cmd_str_with_len (ctx, code, string, iarg0, iarg1, strlen (string));
9789 }
9790 
9791 #if CTX_BITPACK_PACKER
9792 static int
ctx_last_history(CtxDrawlist * drawlist)9793 ctx_last_history (CtxDrawlist *drawlist)
9794 {
9795   int last_history = 0;
9796   int i = 0;
9797   while (i < drawlist->count)
9798     {
9799       CtxEntry *entry = &drawlist->entries[i];
9800       i += (ctx_conts_for_entry (entry) + 1);
9801     }
9802   return last_history;
9803 }
9804 #endif
9805 
9806 #if CTX_BITPACK_PACKER
9807 
9808 static float
find_max_dev(CtxEntry * entry,int nentrys)9809 find_max_dev (CtxEntry *entry, int nentrys)
9810 {
9811   float max_dev = 0.0;
9812   for (int c = 0; c < nentrys; c++)
9813     {
9814       for (int d = 0; d < 2; d++)
9815         {
9816           if (entry[c].data.f[d] > max_dev)
9817             { max_dev = entry[c].data.f[d]; }
9818           if (entry[c].data.f[d] < -max_dev)
9819             { max_dev = -entry[c].data.f[d]; }
9820         }
9821     }
9822   return max_dev;
9823 }
9824 
9825 static void
pack_s8_args(CtxEntry * entry,int npairs)9826 pack_s8_args (CtxEntry *entry, int npairs)
9827 {
9828   for (int c = 0; c < npairs; c++)
9829     for (int d = 0; d < 2; d++)
9830       { entry[0].data.s8[c*2+d]=entry[c].data.f[d] * CTX_SUBDIV; }
9831 }
9832 
9833 static void
pack_s16_args(CtxEntry * entry,int npairs)9834 pack_s16_args (CtxEntry *entry, int npairs)
9835 {
9836   for (int c = 0; c < npairs; c++)
9837     for (int d = 0; d < 2; d++)
9838       { entry[0].data.s16[c*2+d]=entry[c].data.f[d] * CTX_SUBDIV; }
9839 }
9840 #endif
9841 
9842 #if CTX_BITPACK_PACKER
9843 static void
ctx_drawlist_remove_tiny_curves(CtxDrawlist * drawlist,int start_pos)9844 ctx_drawlist_remove_tiny_curves (CtxDrawlist *drawlist, int start_pos)
9845 {
9846   CtxIterator iterator;
9847   if ( (drawlist->flags & CTX_TRANSFORMATION_BITPACK) == 0)
9848     { return; }
9849   ctx_iterator_init (&iterator, drawlist, start_pos, CTX_ITERATOR_FLAT);
9850   iterator.end_pos = drawlist->count - 5;
9851   CtxCommand *command = NULL;
9852   while ( (command = ctx_iterator_next (&iterator) ) )
9853     {
9854       CtxEntry *entry = &command->entry;
9855       /* things smaller than this have probably been scaled down
9856          beyond recognition, bailing for both better packing and less rasterization work
9857        */
9858       if (command[0].code == CTX_REL_CURVE_TO)
9859         {
9860           float max_dev = find_max_dev (entry, 3);
9861           if (max_dev < 1.0)
9862             {
9863               entry[0].code = CTX_REL_LINE_TO;
9864               entry[0].data.f[0] = entry[2].data.f[0];
9865               entry[0].data.f[1] = entry[2].data.f[1];
9866               entry[1].code = CTX_NOP;
9867               entry[2].code = CTX_NOP;
9868             }
9869         }
9870     }
9871 }
9872 #endif
9873 
9874 #if CTX_BITPACK_PACKER
9875 static void
ctx_drawlist_bitpack(CtxDrawlist * drawlist,int start_pos)9876 ctx_drawlist_bitpack (CtxDrawlist *drawlist, int start_pos)
9877 {
9878 #if CTX_BITPACK
9879   int i = 0;
9880   if ( (drawlist->flags & CTX_TRANSFORMATION_BITPACK) == 0)
9881     { return; }
9882   ctx_drawlist_remove_tiny_curves (drawlist, drawlist->bitpack_pos);
9883   i = drawlist->bitpack_pos;
9884   if (start_pos > i)
9885     { i = start_pos; }
9886   while (i < drawlist->count - 4) /* the -4 is to avoid looking past
9887                                     initialized data we're not ready
9888                                     to bitpack yet*/
9889     {
9890       CtxEntry *entry = &drawlist->entries[i];
9891       if (entry[0].code == CTX_SET_RGBA_U8 &&
9892           entry[1].code == CTX_MOVE_TO &&
9893           entry[2].code == CTX_REL_LINE_TO &&
9894           entry[3].code == CTX_REL_LINE_TO &&
9895           entry[4].code == CTX_REL_LINE_TO &&
9896           entry[5].code == CTX_REL_LINE_TO &&
9897           entry[6].code == CTX_FILL &&
9898           ctx_fabsf (entry[2].data.f[0] - 1.0f) < 0.02f &&
9899           ctx_fabsf (entry[3].data.f[1] - 1.0f) < 0.02f)
9900         {
9901           entry[0].code = CTX_SET_PIXEL;
9902           entry[0].data.u16[2] = entry[1].data.f[0];
9903           entry[0].data.u16[3] = entry[1].data.f[1];
9904           entry[1].code = CTX_NOP;
9905           entry[2].code = CTX_NOP;
9906           entry[3].code = CTX_NOP;
9907           entry[4].code = CTX_NOP;
9908           entry[5].code = CTX_NOP;
9909           entry[6].code = CTX_NOP;
9910         }
9911 #if 1
9912       else if (entry[0].code == CTX_REL_LINE_TO)
9913         {
9914           if (entry[1].code == CTX_REL_LINE_TO &&
9915               entry[2].code == CTX_REL_LINE_TO &&
9916               entry[3].code == CTX_REL_LINE_TO)
9917             {
9918               float max_dev = find_max_dev (entry, 4);
9919               if (max_dev < 114 / CTX_SUBDIV)
9920                 {
9921                   pack_s8_args (entry, 4);
9922                   entry[0].code = CTX_REL_LINE_TO_X4;
9923                   entry[1].code = CTX_NOP;
9924                   entry[2].code = CTX_NOP;
9925                   entry[3].code = CTX_NOP;
9926                 }
9927             }
9928           else if (entry[1].code == CTX_REL_CURVE_TO)
9929             {
9930               float max_dev = find_max_dev (entry, 4);
9931               if (max_dev < 114 / CTX_SUBDIV)
9932                 {
9933                   pack_s8_args (entry, 4);
9934                   entry[0].code = CTX_REL_LINE_TO_REL_CURVE_TO;
9935                   entry[1].code = CTX_NOP;
9936                   entry[2].code = CTX_NOP;
9937                   entry[3].code = CTX_NOP;
9938                 }
9939             }
9940           else if (entry[1].code == CTX_REL_LINE_TO &&
9941                    entry[2].code == CTX_REL_LINE_TO &&
9942                    entry[3].code == CTX_REL_LINE_TO)
9943             {
9944               float max_dev = find_max_dev (entry, 4);
9945               if (max_dev < 114 / CTX_SUBDIV)
9946                 {
9947                   pack_s8_args (entry, 4);
9948                   entry[0].code = CTX_REL_LINE_TO_X4;
9949                   entry[1].code = CTX_NOP;
9950                   entry[2].code = CTX_NOP;
9951                   entry[3].code = CTX_NOP;
9952                 }
9953             }
9954           else if (entry[1].code == CTX_REL_MOVE_TO)
9955             {
9956               float max_dev = find_max_dev (entry, 2);
9957               if (max_dev < 31000 / CTX_SUBDIV)
9958                 {
9959                   pack_s16_args (entry, 2);
9960                   entry[0].code = CTX_REL_LINE_TO_REL_MOVE_TO;
9961                   entry[1].code = CTX_NOP;
9962                 }
9963             }
9964           else if (entry[1].code == CTX_REL_LINE_TO)
9965             {
9966               float max_dev = find_max_dev (entry, 2);
9967               if (max_dev < 31000 / CTX_SUBDIV)
9968                 {
9969                   pack_s16_args (entry, 2);
9970                   entry[0].code = CTX_REL_LINE_TO_X2;
9971                   entry[1].code = CTX_NOP;
9972                 }
9973             }
9974         }
9975 #endif
9976 #if 1
9977       else if (entry[0].code == CTX_REL_CURVE_TO)
9978         {
9979           if (entry[3].code == CTX_REL_LINE_TO)
9980             {
9981               float max_dev = find_max_dev (entry, 4);
9982               if (max_dev < 114 / CTX_SUBDIV)
9983                 {
9984                   pack_s8_args (entry, 4);
9985                   entry[0].code = CTX_REL_CURVE_TO_REL_LINE_TO;
9986                   entry[1].code = CTX_NOP;
9987                   entry[2].code = CTX_NOP;
9988                   entry[3].code = CTX_NOP;
9989                 }
9990             }
9991           else if (entry[3].code == CTX_REL_MOVE_TO)
9992             {
9993               float max_dev = find_max_dev (entry, 4);
9994               if (max_dev < 114 / CTX_SUBDIV)
9995                 {
9996                   pack_s8_args (entry, 4);
9997                   entry[0].code = CTX_REL_CURVE_TO_REL_MOVE_TO;
9998                   entry[1].code = CTX_NOP;
9999                   entry[2].code = CTX_NOP;
10000                   entry[3].code = CTX_NOP;
10001                 }
10002             }
10003           else
10004             {
10005               float max_dev = find_max_dev (entry, 3);
10006               if (max_dev < 114 / CTX_SUBDIV)
10007                 {
10008                   pack_s8_args (entry, 3);
10009                   ctx_arg_s8 (6) =
10010                     ctx_arg_s8 (7) = 0;
10011                   entry[0].code = CTX_REL_CURVE_TO_REL_LINE_TO;
10012                   entry[1].code = CTX_NOP;
10013                   entry[2].code = CTX_NOP;
10014                 }
10015             }
10016         }
10017 #endif
10018 #if 1
10019       else if (entry[0].code == CTX_REL_QUAD_TO)
10020         {
10021           if (entry[2].code == CTX_REL_QUAD_TO)
10022             {
10023               float max_dev = find_max_dev (entry, 4);
10024               if (max_dev < 114 / CTX_SUBDIV)
10025                 {
10026                   pack_s8_args (entry, 4);
10027                   entry[0].code = CTX_REL_QUAD_TO_REL_QUAD_TO;
10028                   entry[1].code = CTX_NOP;
10029                   entry[2].code = CTX_NOP;
10030                   entry[3].code = CTX_NOP;
10031                 }
10032             }
10033           else
10034             {
10035               float max_dev = find_max_dev (entry, 2);
10036               if (max_dev < 3100 / CTX_SUBDIV)
10037                 {
10038                   pack_s16_args (entry, 2);
10039                   entry[0].code = CTX_REL_QUAD_TO_S16;
10040                   entry[1].code = CTX_NOP;
10041                 }
10042             }
10043         }
10044 #endif
10045 #if 1
10046       else if (entry[0].code == CTX_FILL &&
10047                entry[1].code == CTX_MOVE_TO)
10048         {
10049           entry[0] = entry[1];
10050           entry[0].code = CTX_FILL_MOVE_TO;
10051           entry[1].code = CTX_NOP;
10052         }
10053 #endif
10054 #if 1
10055       else if (entry[0].code == CTX_MOVE_TO &&
10056                entry[1].code == CTX_MOVE_TO &&
10057                entry[2].code == CTX_MOVE_TO)
10058         {
10059           entry[0]      = entry[2];
10060           entry[0].code = CTX_MOVE_TO;
10061           entry[1].code = CTX_NOP;
10062           entry[2].code = CTX_NOP;
10063         }
10064 #endif
10065 #if 1
10066       else if ( (entry[0].code == CTX_MOVE_TO &&
10067                  entry[1].code == CTX_MOVE_TO) ||
10068                 (entry[0].code == CTX_REL_MOVE_TO &&
10069                  entry[1].code == CTX_MOVE_TO) )
10070         {
10071           entry[0]      = entry[1];
10072           entry[0].code = CTX_MOVE_TO;
10073           entry[1].code = CTX_NOP;
10074         }
10075 #endif
10076       i += (ctx_conts_for_entry (entry) + 1);
10077     }
10078   int source = drawlist->bitpack_pos;
10079   int target = drawlist->bitpack_pos;
10080   int removed = 0;
10081   /* remove nops that have been inserted as part of shortenings
10082    */
10083   while (source < drawlist->count)
10084     {
10085       CtxEntry *sentry = &drawlist->entries[source];
10086       CtxEntry *tentry = &drawlist->entries[target];
10087       while (sentry->code == CTX_NOP && source < drawlist->count)
10088         {
10089           source++;
10090           sentry = &drawlist->entries[source];
10091           removed++;
10092         }
10093       if (sentry != tentry)
10094         { *tentry = *sentry; }
10095       source ++;
10096       target ++;
10097     }
10098   drawlist->count -= removed;
10099   drawlist->bitpack_pos = drawlist->count;
10100 #endif
10101 }
10102 
10103 #endif
10104 
10105 static inline void
ctx_drawlist_compact(CtxDrawlist * drawlist)10106 ctx_drawlist_compact (CtxDrawlist *drawlist)
10107 {
10108 #if CTX_BITPACK_PACKER
10109   int last_history;
10110   last_history = ctx_last_history (drawlist);
10111 #else
10112   if (drawlist) {};
10113 #endif
10114 #if CTX_BITPACK_PACKER
10115   ctx_drawlist_bitpack (drawlist, last_history);
10116 #endif
10117 }
10118 
ctx_define_texture_pixel_data(CtxEntry * entry)10119 uint8_t *ctx_define_texture_pixel_data (CtxEntry *entry)
10120 {
10121   return &entry[2 + 1 + 1 + ctx_conts_for_entry (&entry[2])].data.u8[0];
10122 }
10123 
10124 #ifndef __CTX_TRANSFORM
10125 #define __CTX_TRANSFORM
10126 
10127 static inline void
_ctx_matrix_apply_transform(const CtxMatrix * m,float * x,float * y)10128 _ctx_matrix_apply_transform (const CtxMatrix *m, float *x, float *y)
10129 {
10130   float x_in = *x;
10131   float y_in = *y;
10132   *x = ( (x_in * m->m[0][0]) + (y_in * m->m[1][0]) + m->m[2][0]);
10133   *y = ( (y_in * m->m[1][1]) + (x_in * m->m[0][1]) + m->m[2][1]);
10134 }
10135 
10136 void
ctx_matrix_apply_transform(const CtxMatrix * m,float * x,float * y)10137 ctx_matrix_apply_transform (const CtxMatrix *m, float *x, float *y)
10138 {
10139   _ctx_matrix_apply_transform (m, x, y);
10140 }
10141 
10142 static inline void
_ctx_user_to_device(CtxState * state,float * x,float * y)10143 _ctx_user_to_device (CtxState *state, float *x, float *y)
10144 {
10145   _ctx_matrix_apply_transform (&state->gstate.transform, x, y);
10146 }
10147 
10148 static void
_ctx_user_to_device_distance(CtxState * state,float * x,float * y)10149 _ctx_user_to_device_distance (CtxState *state, float *x, float *y)
10150 {
10151   const CtxMatrix *m = &state->gstate.transform;
10152   _ctx_matrix_apply_transform (m, x, y);
10153   *x -= m->m[2][0];
10154   *y -= m->m[2][1];
10155 }
10156 
ctx_user_to_device(Ctx * ctx,float * x,float * y)10157 void ctx_user_to_device          (Ctx *ctx, float *x, float *y)
10158 {
10159   _ctx_user_to_device (&ctx->state, x, y);
10160 }
ctx_user_to_device_distance(Ctx * ctx,float * x,float * y)10161 void ctx_user_to_device_distance (Ctx *ctx, float *x, float *y)
10162 {
10163   _ctx_user_to_device_distance (&ctx->state, x, y);
10164 }
10165 
10166 static void
ctx_matrix_set(CtxMatrix * matrix,float a,float b,float c,float d,float e,float f)10167 ctx_matrix_set (CtxMatrix *matrix, float a, float b, float c, float d, float e, float f)
10168 {
10169   matrix->m[0][0] = a;
10170   matrix->m[0][1] = b;
10171   matrix->m[1][0] = c;
10172   matrix->m[1][1] = d;
10173   matrix->m[2][0] = e;
10174   matrix->m[2][1] = f;
10175 }
10176 
10177 static inline void
_ctx_matrix_identity(CtxMatrix * matrix)10178 _ctx_matrix_identity (CtxMatrix *matrix)
10179 {
10180   matrix->m[0][0] = 1.0f;
10181   matrix->m[0][1] = 0.0f;
10182   matrix->m[1][0] = 0.0f;
10183   matrix->m[1][1] = 1.0f;
10184   matrix->m[2][0] = 0.0f;
10185   matrix->m[2][1] = 0.0f;
10186 }
10187 
10188 void
ctx_matrix_identity(CtxMatrix * matrix)10189 ctx_matrix_identity (CtxMatrix *matrix)
10190 {
10191   _ctx_matrix_identity (matrix);
10192 }
10193 
10194 static void
_ctx_matrix_multiply(CtxMatrix * result,const CtxMatrix * t,const CtxMatrix * s)10195 _ctx_matrix_multiply (CtxMatrix       *result,
10196                       const CtxMatrix *t,
10197                       const CtxMatrix *s)
10198 {
10199   CtxMatrix r;
10200   r.m[0][0] = t->m[0][0] * s->m[0][0] + t->m[0][1] * s->m[1][0];
10201   r.m[0][1] = t->m[0][0] * s->m[0][1] + t->m[0][1] * s->m[1][1];
10202   r.m[1][0] = t->m[1][0] * s->m[0][0] + t->m[1][1] * s->m[1][0];
10203   r.m[1][1] = t->m[1][0] * s->m[0][1] + t->m[1][1] * s->m[1][1];
10204   r.m[2][0] = t->m[2][0] * s->m[0][0] + t->m[2][1] * s->m[1][0] + s->m[2][0];
10205   r.m[2][1] = t->m[2][0] * s->m[0][1] + t->m[2][1] * s->m[1][1] + s->m[2][1];
10206   *result = r;
10207 }
10208 
10209 void
ctx_matrix_multiply(CtxMatrix * result,const CtxMatrix * t,const CtxMatrix * s)10210 ctx_matrix_multiply (CtxMatrix       *result,
10211                      const CtxMatrix *t,
10212                      const CtxMatrix *s)
10213 {
10214   _ctx_matrix_multiply (result, t, s);
10215 }
10216 
10217 void
ctx_matrix_translate(CtxMatrix * matrix,float x,float y)10218 ctx_matrix_translate (CtxMatrix *matrix, float x, float y)
10219 {
10220   CtxMatrix transform;
10221   transform.m[0][0] = 1.0f;
10222   transform.m[0][1] = 0.0f;
10223   transform.m[1][0] = 0.0f;
10224   transform.m[1][1] = 1.0f;
10225   transform.m[2][0] = x;
10226   transform.m[2][1] = y;
10227   _ctx_matrix_multiply (matrix, &transform, matrix);
10228 }
10229 
10230 void
ctx_matrix_scale(CtxMatrix * matrix,float x,float y)10231 ctx_matrix_scale (CtxMatrix *matrix, float x, float y)
10232 {
10233   CtxMatrix transform;
10234   transform.m[0][0] = x;
10235   transform.m[0][1] = 0.0f;
10236   transform.m[1][0] = 0.0f;
10237   transform.m[1][1] = y;
10238   transform.m[2][0] = 0.0f;
10239   transform.m[2][1] = 0.0f;
10240   _ctx_matrix_multiply (matrix, &transform, matrix);
10241 }
10242 
10243 void
ctx_matrix_rotate(CtxMatrix * matrix,float angle)10244 ctx_matrix_rotate (CtxMatrix *matrix, float angle)
10245 {
10246   CtxMatrix transform;
10247   float val_sin = ctx_sinf (angle);
10248   float val_cos = ctx_cosf (angle);
10249   transform.m[0][0] =  val_cos;
10250   transform.m[0][1] = val_sin;
10251   transform.m[1][0] = -val_sin;
10252   transform.m[1][1] = val_cos;
10253   transform.m[2][0] =     0.0f;
10254   transform.m[2][1] = 0.0f;
10255   _ctx_matrix_multiply (matrix, &transform, matrix);
10256 }
10257 
10258 #if 0
10259 static void
10260 ctx_matrix_skew_x (CtxMatrix *matrix, float angle)
10261 {
10262   CtxMatrix transform;
10263   float val_tan = ctx_tanf (angle);
10264   transform.m[0][0] =    1.0f;
10265   transform.m[0][1] = 0.0f;
10266   transform.m[1][0] = val_tan;
10267   transform.m[1][1] = 1.0f;
10268   transform.m[2][0] =    0.0f;
10269   transform.m[2][1] = 0.0f;
10270   _ctx_matrix_multiply (matrix, &transform, matrix);
10271 }
10272 
10273 static void
10274 ctx_matrix_skew_y (CtxMatrix *matrix, float angle)
10275 {
10276   CtxMatrix transform;
10277   float val_tan = ctx_tanf (angle);
10278   transform.m[0][0] =    1.0f;
10279   transform.m[0][1] = val_tan;
10280   transform.m[1][0] =    0.0f;
10281   transform.m[1][1] = 1.0f;
10282   transform.m[2][0] =    0.0f;
10283   transform.m[2][1] = 0.0f;
10284   _ctx_matrix_multiply (matrix, &transform, matrix);
10285 }
10286 #endif
10287 
10288 
10289 void
ctx_identity(Ctx * ctx)10290 ctx_identity (Ctx *ctx)
10291 {
10292   CTX_PROCESS_VOID (CTX_IDENTITY);
10293 }
10294 
10295 
10296 
10297 void
ctx_apply_transform(Ctx * ctx,float a,float b,float c,float d,float e,float f)10298 ctx_apply_transform (Ctx *ctx, float a, float b,  // hscale, hskew
10299                      float c, float d,  // vskew,  vscale
10300                      float e, float f)  // htran,  vtran
10301 {
10302   CtxEntry command[3]=
10303   {
10304     ctx_f (CTX_APPLY_TRANSFORM, a, b),
10305     ctx_f (CTX_CONT,            c, d),
10306     ctx_f (CTX_CONT,            e, f)
10307   };
10308   ctx_process (ctx, command);
10309 }
10310 
10311 void
ctx_get_transform(Ctx * ctx,float * a,float * b,float * c,float * d,float * e,float * f)10312 ctx_get_transform  (Ctx *ctx, float *a, float *b,
10313                     float *c, float *d,
10314                     float *e, float *f)
10315 {
10316   if (a) { *a = ctx->state.gstate.transform.m[0][0]; }
10317   if (b) { *b = ctx->state.gstate.transform.m[0][1]; }
10318   if (c) { *c = ctx->state.gstate.transform.m[1][0]; }
10319   if (d) { *d = ctx->state.gstate.transform.m[1][1]; }
10320   if (e) { *e = ctx->state.gstate.transform.m[2][0]; }
10321   if (f) { *f = ctx->state.gstate.transform.m[2][1]; }
10322 }
10323 
10324 void
ctx_source_transform(Ctx * ctx,float a,float b,float c,float d,float e,float f)10325 ctx_source_transform (Ctx *ctx, float a, float b,  // hscale, hskew
10326                       float c, float d,  // vskew,  vscale
10327                       float e, float f)  // htran,  vtran
10328 {
10329   CtxEntry command[3]=
10330   {
10331     ctx_f (CTX_SOURCE_TRANSFORM, a, b),
10332     ctx_f (CTX_CONT,             c, d),
10333     ctx_f (CTX_CONT,             e, f)
10334   };
10335   ctx_process (ctx, command);
10336 }
10337 
10338 void
ctx_source_transform_matrix(Ctx * ctx,CtxMatrix * matrix)10339 ctx_source_transform_matrix (Ctx *ctx, CtxMatrix *matrix)
10340 {
10341   ctx_source_transform (ctx,
10342     matrix->m[0][0], matrix->m[0][1],
10343     matrix->m[1][0], matrix->m[1][1],
10344     matrix->m[2][0], matrix->m[2][1]);
10345 }
10346 
ctx_apply_matrix(Ctx * ctx,CtxMatrix * matrix)10347 void ctx_apply_matrix (Ctx *ctx, CtxMatrix *matrix)
10348 {
10349   ctx_apply_transform (ctx,
10350                        matrix->m[0][0], matrix->m[0][1],
10351                        matrix->m[1][0], matrix->m[1][1],
10352                        matrix->m[2][0], matrix->m[2][1]);
10353 }
10354 
ctx_get_matrix(Ctx * ctx,CtxMatrix * matrix)10355 void ctx_get_matrix (Ctx *ctx, CtxMatrix *matrix)
10356 {
10357   *matrix = ctx->state.gstate.transform;
10358 }
10359 
ctx_set_matrix(Ctx * ctx,CtxMatrix * matrix)10360 void ctx_set_matrix (Ctx *ctx, CtxMatrix *matrix)
10361 {
10362   ctx_identity (ctx);
10363   ctx_apply_matrix (ctx, matrix);
10364 }
10365 
ctx_rotate(Ctx * ctx,float x)10366 void ctx_rotate (Ctx *ctx, float x)
10367 {
10368   if (x == 0.0f)
10369     return;
10370   CTX_PROCESS_F1 (CTX_ROTATE, x);
10371   if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
10372     { ctx->drawlist.count--; }
10373 }
10374 
ctx_scale(Ctx * ctx,float x,float y)10375 void ctx_scale (Ctx *ctx, float x, float y)
10376 {
10377   if (x == 1.0f && y == 1.0f)
10378     return;
10379   CTX_PROCESS_F (CTX_SCALE, x, y);
10380   if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
10381     { ctx->drawlist.count--; }
10382 }
10383 
ctx_translate(Ctx * ctx,float x,float y)10384 void ctx_translate (Ctx *ctx, float x, float y)
10385 {
10386   if (x == 0.0f && y == 0.0f)
10387     return;
10388   CTX_PROCESS_F (CTX_TRANSLATE, x, y);
10389   if (ctx->transformation & CTX_TRANSFORMATION_SCREEN_SPACE)
10390     { ctx->drawlist.count--; }
10391 }
10392 
10393 void
ctx_matrix_invert(CtxMatrix * m)10394 ctx_matrix_invert (CtxMatrix *m)
10395 {
10396   CtxMatrix t = *m;
10397   float invdet, det = m->m[0][0] * m->m[1][1] -
10398                       m->m[1][0] * m->m[0][1];
10399   if (det > -0.0000001f && det < 0.0000001f)
10400     {
10401       m->m[0][0] = m->m[0][1] =
10402                      m->m[1][0] = m->m[1][1] =
10403                                     m->m[2][0] = m->m[2][1] = 0.0;
10404       return;
10405     }
10406   invdet = 1.0f / det;
10407   m->m[0][0] = t.m[1][1] * invdet;
10408   m->m[1][0] = -t.m[1][0] * invdet;
10409   m->m[2][0] = (t.m[1][0] * t.m[2][1] - t.m[1][1] * t.m[2][0]) * invdet;
10410   m->m[0][1] = -t.m[0][1] * invdet;
10411   m->m[1][1] = t.m[0][0] * invdet;
10412   m->m[2][1] = (t.m[0][1] * t.m[2][0] - t.m[0][0] * t.m[2][1]) * invdet ;
10413 }
10414 
10415 
10416 
10417 #endif
10418 #ifndef __CTX_COLOR
10419 #define __CTX_COLOR
10420 
ctx_color_model_get_components(CtxColorModel model)10421 int ctx_color_model_get_components (CtxColorModel model)
10422 {
10423   switch (model)
10424     {
10425       case CTX_GRAY:
10426         return 1;
10427       case CTX_GRAYA:
10428       case CTX_GRAYA_A:
10429         return 1;
10430       case CTX_RGB:
10431       case CTX_LAB:
10432       case CTX_LCH:
10433       case CTX_DRGB:
10434         return 3;
10435       case CTX_CMYK:
10436       case CTX_DCMYK:
10437       case CTX_LABA:
10438       case CTX_LCHA:
10439       case CTX_RGBA:
10440       case CTX_DRGBA:
10441       case CTX_RGBA_A:
10442       case CTX_RGBA_A_DEVICE:
10443         return 4;
10444       case CTX_DCMYKA:
10445       case CTX_CMYKA:
10446       case CTX_CMYKA_A:
10447       case CTX_DCMYKA_A:
10448         return 5;
10449     }
10450   return 0;
10451 }
10452 
10453 #if 0
10454 inline static float ctx_u8_to_float (uint8_t val_u8)
10455 {
10456   float val_f = val_u8 / 255.0;
10457   return val_f;
10458 }
10459 #else
10460 float ctx_u8_float[256];
10461 #endif
10462 
ctx_color_new(void)10463 CtxColor *ctx_color_new (void)
10464 {
10465   CtxColor *color = (CtxColor*)ctx_calloc (sizeof (CtxColor), 1);
10466   return color;
10467 }
10468 
ctx_color_is_transparent(CtxColor * color)10469 int ctx_color_is_transparent (CtxColor *color)
10470 {
10471   return color->alpha <= 0.001f;
10472 }
10473 
10474 
ctx_color_free(CtxColor * color)10475 void ctx_color_free (CtxColor *color)
10476 {
10477   free (color);
10478 }
10479 
ctx_color_set_RGBA8(CtxState * state,CtxColor * color,uint8_t r,uint8_t g,uint8_t b,uint8_t a)10480 static void ctx_color_set_RGBA8 (CtxState *state, CtxColor *color, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
10481 {
10482   color->original = color->valid = CTX_VALID_RGBA_U8;
10483   color->rgba[0] = r;
10484   color->rgba[1] = g;
10485   color->rgba[2] = b;
10486   color->rgba[3] = a;
10487 #if CTX_ENABLE_CM
10488   color->space = state->gstate.device_space;
10489 #endif
10490 }
10491 
10492 #if 0
10493 static void ctx_color_set_RGBA8_ (CtxColor *color, const uint8_t *in)
10494 {
10495   ctx_color_set_RGBA8 (color, in[0], in[1], in[2], in[3]);
10496 }
10497 #endif
10498 
ctx_color_set_graya(CtxState * state,CtxColor * color,float gray,float alpha)10499 static void ctx_color_set_graya (CtxState *state, CtxColor *color, float gray, float alpha)
10500 {
10501   color->original = color->valid = CTX_VALID_GRAYA;
10502   color->l = gray;
10503   color->alpha = alpha;
10504 }
10505 #if 0
10506 static void ctx_color_set_graya_ (CtxColor *color, const float *in)
10507 {
10508   return ctx_color_set_graya (color, in[0], in[1]);
10509 }
10510 #endif
10511 
ctx_color_set_rgba(CtxState * state,CtxColor * color,float r,float g,float b,float a)10512 void ctx_color_set_rgba (CtxState *state, CtxColor *color, float r, float g, float b, float a)
10513 {
10514 #if CTX_ENABLE_CM
10515   color->original = color->valid = CTX_VALID_RGBA;
10516   color->red      = r;
10517   color->green    = g;
10518   color->blue     = b;
10519   color->space    = state->gstate.rgb_space;
10520 #else
10521   color->original     = color->valid = CTX_VALID_RGBA_DEVICE;
10522   color->device_red   = r;
10523   color->device_green = g;
10524   color->device_blue  = b;
10525 #endif
10526   color->alpha        = a;
10527 }
10528 
ctx_color_set_drgba(CtxState * state,CtxColor * color,float r,float g,float b,float a)10529 static void ctx_color_set_drgba (CtxState *state, CtxColor *color, float r, float g, float b, float a)
10530 {
10531 #if CTX_ENABLE_CM
10532   color->original     = color->valid = CTX_VALID_RGBA_DEVICE;
10533   color->device_red   = r;
10534   color->device_green = g;
10535   color->device_blue  = b;
10536   color->alpha        = a;
10537   color->space        = state->gstate.device_space;
10538 #else
10539   ctx_color_set_rgba (state, color, r, g, b, a);
10540 #endif
10541 }
10542 
10543 #if 0
10544 static void ctx_color_set_rgba_ (CtxState *state, CtxColor *color, const float *in)
10545 {
10546   ctx_color_set_rgba (color, in[0], in[1], in[2], in[3]);
10547 }
10548 #endif
10549 
10550 /* the baseline conversions we have whether CMYK support is enabled or not,
10551  * providing an effort at right rendering
10552  */
ctx_cmyk_to_rgb(float c,float m,float y,float k,float * r,float * g,float * b)10553 static void ctx_cmyk_to_rgb (float c, float m, float y, float k, float *r, float *g, float *b)
10554 {
10555   *r = (1.0f-c) * (1.0f-k);
10556   *g = (1.0f-m) * (1.0f-k);
10557   *b = (1.0f-y) * (1.0f-k);
10558 }
10559 
ctx_rgb_to_cmyk(float r,float g,float b,float * c_out,float * m_out,float * y_out,float * k_out)10560 void ctx_rgb_to_cmyk (float r, float g, float b,
10561                       float *c_out, float *m_out, float *y_out, float *k_out)
10562 {
10563   float c = 1.0f - r;
10564   float m = 1.0f - g;
10565   float y = 1.0f - b;
10566   float k = ctx_minf (c, ctx_minf (y, m) );
10567   if (k < 1.0f)
10568     {
10569       c = (c - k) / (1.0f - k);
10570       m = (m - k) / (1.0f - k);
10571       y = (y - k) / (1.0f - k);
10572     }
10573   else
10574     {
10575       c = m = y = 0.0f;
10576     }
10577   *c_out = c;
10578   *m_out = m;
10579   *y_out = y;
10580   *k_out = k;
10581 }
10582 
10583 #if CTX_ENABLE_CMYK
ctx_color_set_cmyka(CtxState * state,CtxColor * color,float c,float m,float y,float k,float a)10584 static void ctx_color_set_cmyka (CtxState *state, CtxColor *color, float c, float m, float y, float k, float a)
10585 {
10586   color->original = color->valid = CTX_VALID_CMYKA;
10587   color->cyan     = c;
10588   color->magenta  = m;
10589   color->yellow   = y;
10590   color->key      = k;
10591   color->alpha    = a;
10592 #if CTX_ENABLE_CM
10593   color->space    = state->gstate.cmyk_space;
10594 #endif
10595 }
10596 
ctx_color_set_dcmyka(CtxState * state,CtxColor * color,float c,float m,float y,float k,float a)10597 static void ctx_color_set_dcmyka (CtxState *state, CtxColor *color, float c, float m, float y, float k, float a)
10598 {
10599   color->original       = color->valid = CTX_VALID_DCMYKA;
10600   color->device_cyan    = c;
10601   color->device_magenta = m;
10602   color->device_yellow  = y;
10603   color->device_key     = k;
10604   color->alpha          = a;
10605 #if CTX_ENABLE_CM
10606   color->space = state->gstate.device_space;
10607 #endif
10608 }
10609 
10610 #endif
10611 
10612 #if CTX_ENABLE_CM
10613 
ctx_rgb_user_to_device(CtxState * state,float rin,float gin,float bin,float * rout,float * gout,float * bout)10614 static void ctx_rgb_user_to_device (CtxState *state, float rin, float gin, float bin,
10615                                     float *rout, float *gout, float *bout)
10616 {
10617 #if CTX_BABL
10618 #if 0
10619   fprintf (stderr, "-[%p %p\n",
10620     state->gstate.fish_rgbaf_user_to_device,
10621     state->gstate.fish_rgbaf_device_to_user);
10622 #endif
10623   if (state->gstate.fish_rgbaf_user_to_device)
10624   {
10625     float rgbaf[4]={rin,gin,bin,1.0};
10626     float rgbafo[4];
10627     babl_process (state->gstate.fish_rgbaf_user_to_device,
10628                   rgbaf, rgbafo, 1);
10629 
10630     *rout = rgbafo[0];
10631     *gout = rgbafo[1];
10632     *bout = rgbafo[2];
10633     return;
10634   }
10635 #endif
10636   *rout = rin;
10637   *gout = gin;
10638   *bout = bin;
10639 }
10640 
ctx_rgb_device_to_user(CtxState * state,float rin,float gin,float bin,float * rout,float * gout,float * bout)10641 static void ctx_rgb_device_to_user (CtxState *state, float rin, float gin, float bin,
10642                                     float *rout, float *gout, float *bout)
10643 {
10644 #if CTX_BABL
10645 #if 0
10646   fprintf (stderr, "=[%p %p\n",
10647     state->gstate.fish_rgbaf_user_to_device,
10648     state->gstate.fish_rgbaf_device_to_user);
10649 #endif
10650   if (state->gstate.fish_rgbaf_device_to_user)
10651   {
10652     float rgbaf[4]={rin,gin,bin,1.0};
10653     float rgbafo[4];
10654     babl_process (state->gstate.fish_rgbaf_device_to_user,
10655                   rgbaf, rgbafo, 1);
10656 
10657     *rout = rgbafo[0];
10658     *gout = rgbafo[1];
10659     *bout = rgbafo[2];
10660     return;
10661   }
10662 #endif
10663   *rout = rin;
10664   *gout = gin;
10665   *bout = bin;
10666 }
10667 #endif
10668 
ctx_color_get_drgba(CtxState * state,CtxColor * color,float * out)10669 static void ctx_color_get_drgba (CtxState *state, CtxColor *color, float *out)
10670 {
10671   if (! (color->valid & CTX_VALID_RGBA_DEVICE) )
10672     {
10673 #if CTX_ENABLE_CM
10674       if (color->valid & CTX_VALID_RGBA)
10675         {
10676           ctx_rgb_user_to_device (state, color->red, color->green, color->blue,
10677                                   & (color->device_red), & (color->device_green), & (color->device_blue) );
10678         }
10679       else
10680 #endif
10681         if (color->valid & CTX_VALID_RGBA_U8)
10682           {
10683             float red = ctx_u8_to_float (color->rgba[0]);
10684             float green = ctx_u8_to_float (color->rgba[1]);
10685             float blue = ctx_u8_to_float (color->rgba[2]);
10686 #if CTX_ENABLE_CM
10687             ctx_rgb_user_to_device (state, red, green, blue,
10688                                   & (color->device_red), & (color->device_green), & (color->device_blue) );
10689 #else
10690             color->device_red = red;
10691             color->device_green = green;
10692             color->device_blue = blue;
10693 #endif
10694             color->alpha        = ctx_u8_to_float (color->rgba[3]);
10695           }
10696 #if CTX_ENABLE_CMYK
10697         else if (color->valid & CTX_VALID_CMYKA)
10698           {
10699             ctx_cmyk_to_rgb (color->cyan, color->magenta, color->yellow, color->key,
10700                              &color->device_red,
10701                              &color->device_green,
10702                              &color->device_blue);
10703           }
10704 #endif
10705         else if (color->valid & CTX_VALID_GRAYA)
10706           {
10707             color->device_red   =
10708               color->device_green =
10709                 color->device_blue  = color->l;
10710           }
10711       color->valid |= CTX_VALID_RGBA_DEVICE;
10712     }
10713   out[0] = color->device_red;
10714   out[1] = color->device_green;
10715   out[2] = color->device_blue;
10716   out[3] = color->alpha;
10717 }
10718 
10719 
10720 static inline void
_ctx_color_get_rgba(CtxState * state,CtxColor * color,float * out)10721 _ctx_color_get_rgba (CtxState *state, CtxColor *color, float *out)
10722 {
10723 #if CTX_ENABLE_CM
10724   if (! (color->valid & CTX_VALID_RGBA) )
10725     {
10726       ctx_color_get_drgba (state, color, out);
10727       if (color->valid & CTX_VALID_RGBA_DEVICE)
10728         {
10729           ctx_rgb_device_to_user (state, color->device_red, color->device_green, color->device_blue,
10730                                   & (color->red), & (color->green), & (color->blue) );
10731         }
10732       color->valid |= CTX_VALID_RGBA;
10733     }
10734   out[0] = color->red;
10735   out[1] = color->green;
10736   out[2] = color->blue;
10737   out[3] = color->alpha;
10738 #else
10739   ctx_color_get_drgba (state, color, out);
10740 #endif
10741 }
10742 
ctx_color_get_rgba(CtxState * state,CtxColor * color,float * out)10743 void ctx_color_get_rgba (CtxState *state, CtxColor *color, float *out)
10744 {
10745   _ctx_color_get_rgba (state, color, out);
10746 }
10747 
10748 
10749 
ctx_float_color_rgb_to_gray(CtxState * state,const float * rgb)10750 float ctx_float_color_rgb_to_gray (CtxState *state, const float *rgb)
10751 {
10752         // XXX todo replace with correct according to primaries
10753   return CTX_CSS_RGB_TO_LUMINANCE(rgb);
10754 }
ctx_u8_color_rgb_to_gray(CtxState * state,const uint8_t * rgb)10755 uint8_t ctx_u8_color_rgb_to_gray (CtxState *state, const uint8_t *rgb)
10756 {
10757         // XXX todo replace with correct according to primaries
10758   return CTX_CSS_RGB_TO_LUMINANCE(rgb);
10759 }
10760 
ctx_color_get_graya(CtxState * state,CtxColor * color,float * out)10761 void ctx_color_get_graya (CtxState *state, CtxColor *color, float *out)
10762 {
10763   if (! (color->valid & CTX_VALID_GRAYA) )
10764     {
10765       float rgba[4];
10766       ctx_color_get_drgba (state, color, rgba);
10767       color->l = ctx_float_color_rgb_to_gray (state, rgba);
10768       color->valid |= CTX_VALID_GRAYA;
10769     }
10770   out[0] = color->l;
10771   out[1] = color->alpha;
10772 }
10773 
10774 #if CTX_ENABLE_CMYK
ctx_color_get_cmyka(CtxState * state,CtxColor * color,float * out)10775 void ctx_color_get_cmyka (CtxState *state, CtxColor *color, float *out)
10776 {
10777   if (! (color->valid & CTX_VALID_CMYKA) )
10778     {
10779       if (color->valid & CTX_VALID_GRAYA)
10780         {
10781           color->cyan = color->magenta = color->yellow = 0.0;
10782           color->key = color->l;
10783         }
10784       else
10785         {
10786           float rgba[4];
10787           ctx_color_get_rgba (state, color, rgba);
10788           ctx_rgb_to_cmyk (rgba[0], rgba[1], rgba[2],
10789                            &color->cyan, &color->magenta, &color->yellow, &color->key);
10790           color->alpha = rgba[3];
10791         }
10792       color->valid |= CTX_VALID_CMYKA;
10793     }
10794   out[0] = color->cyan;
10795   out[1] = color->magenta;
10796   out[2] = color->yellow;
10797   out[3] = color->key;
10798   out[4] = color->alpha;
10799 }
10800 
10801 #if 0
10802 static void ctx_color_get_cmyka_u8 (CtxState *state, CtxColor *color, uint8_t *out)
10803 {
10804   if (! (color->valid & CTX_VALID_CMYKA_U8) )
10805     {
10806       float cmyka[5];
10807       ctx_color_get_cmyka (color, cmyka);
10808       for (int i = 0; i < 5; i ++)
10809         { color->cmyka[i] = ctx_float_to_u8 (cmyka[i]); }
10810       color->valid |= CTX_VALID_CMYKA_U8;
10811     }
10812   out[0] = color->cmyka[0];
10813   out[1] = color->cmyka[1];
10814   out[2] = color->cmyka[2];
10815   out[3] = color->cmyka[3];
10816 }
10817 #endif
10818 #endif
10819 
10820 static inline void
_ctx_color_get_rgba8(CtxState * state,CtxColor * color,uint8_t * out)10821 _ctx_color_get_rgba8 (CtxState *state, CtxColor *color, uint8_t *out)
10822 {
10823   if (! (color->valid & CTX_VALID_RGBA_U8) )
10824     {
10825       float rgba[4];
10826       ctx_color_get_drgba (state, color, rgba);
10827       for (int i = 0; i < 4; i ++)
10828         { color->rgba[i] = ctx_float_to_u8 (rgba[i]); }
10829       color->valid |= CTX_VALID_RGBA_U8;
10830     }
10831   out[0] = color->rgba[0];
10832   out[1] = color->rgba[1];
10833   out[2] = color->rgba[2];
10834   out[3] = color->rgba[3];
10835 }
10836 
10837 void
ctx_color_get_rgba8(CtxState * state,CtxColor * color,uint8_t * out)10838 ctx_color_get_rgba8 (CtxState *state, CtxColor *color, uint8_t *out)
10839 {
10840   _ctx_color_get_rgba8 (state, color, out);
10841 }
10842 
ctx_color_get_graya_u8(CtxState * state,CtxColor * color,uint8_t * out)10843 void ctx_color_get_graya_u8 (CtxState *state, CtxColor *color, uint8_t *out)
10844 {
10845   if (! (color->valid & CTX_VALID_GRAYA_U8) )
10846     {
10847       float graya[2];
10848       ctx_color_get_graya (state, color, graya);
10849       color->l_u8 = ctx_float_to_u8 (graya[0]);
10850       color->rgba[3] = ctx_float_to_u8 (graya[1]);
10851       color->valid |= CTX_VALID_GRAYA_U8;
10852     }
10853   out[0] = color->l_u8;
10854   out[1] = color->rgba[3];
10855 }
10856 
10857 #if 0
10858 void
10859 ctx_get_rgba (Ctx *ctx, float *rgba)
10860 {
10861   ctx_color_get_rgba (& (ctx->state), &ctx->state.gstate.source.color, rgba);
10862 }
10863 
10864 void
10865 ctx_get_drgba (Ctx *ctx, float *rgba)
10866 {
10867   ctx_color_get_drgba (& (ctx->state), &ctx->state.gstate.source.color, rgba);
10868 }
10869 #endif
10870 
ctx_in_fill(Ctx * ctx,float x,float y)10871 int ctx_in_fill (Ctx *ctx, float x, float y)
10872 {
10873   float x1, y1, x2, y2;
10874   ctx_path_extents (ctx, &x1, &y1, &x2, &y2);
10875 
10876   if (x1 <= x && x <= x2 && // XXX - just bounding box for now
10877       y1 <= y && y <= y2)   //
10878     return 1;
10879   return 0;
10880 }
10881 
10882 
10883 #if CTX_ENABLE_CMYK
10884 #if 0
10885 void
10886 ctx_get_cmyka (Ctx *ctx, float *cmyka)
10887 {
10888   ctx_color_get_cmyka (& (ctx->state), &ctx->state.gstate.source.color, cmyka);
10889 }
10890 #endif
10891 #endif
10892 #if 0
10893 void
10894 ctx_get_graya (Ctx *ctx, float *ya)
10895 {
10896   ctx_color_get_graya (& (ctx->state), &ctx->state.gstate.source.color, ya);
10897 }
10898 #endif
10899 
ctx_stroke_source(Ctx * ctx)10900 void ctx_stroke_source (Ctx *ctx)
10901 {
10902   CtxEntry set_stroke = ctx_void (CTX_STROKE_SOURCE);
10903   ctx_process (ctx, &set_stroke);
10904 }
10905 
10906 
ctx_color_raw(Ctx * ctx,CtxColorModel model,float * components,int stroke)10907 static void ctx_color_raw (Ctx *ctx, CtxColorModel model, float *components, int stroke)
10908 {
10909 #if 0
10910   CtxSource *source = stroke?
10911           &ctx->state.gstate.source_stroke:
10912           &ctx->state.gstate.source_fill;
10913 
10914   if (model == CTX_RGB || model == CTX_RGBA)
10915   {
10916     float rgba[4];
10917   // XXX it should be possible to disable this, to get a more accurate record
10918   // when it is intentional
10919     float a = 1.0f;
10920     if (model == CTX_RGBA) a = components[3];
10921     ctx_color_get_rgba (&ctx->state, &source->color, rgba);
10922     if (rgba[0] == components[0] && rgba[1] == components[1] && rgba[2] == components[2] && rgba[3] == a)
10923      return;
10924   }
10925 #endif
10926 
10927   if (stroke)
10928   {
10929     ctx_stroke_source (ctx);
10930   }
10931 
10932   CtxEntry command[3]= {
10933   ctx_f (CTX_COLOR, model, 0)
10934   };
10935   switch (model)
10936   {
10937     case CTX_RGBA:
10938     case CTX_RGBA_A:
10939     case CTX_RGBA_A_DEVICE:
10940     case CTX_DRGBA:
10941     case CTX_LABA:
10942     case CTX_LCHA:
10943       command[2].data.f[0]=components[3];
10944       /*FALLTHROUGH*/
10945     case CTX_RGB:
10946     case CTX_LAB:
10947     case CTX_LCH:
10948     case CTX_DRGB:
10949       command[0].data.f[1]=components[0];
10950       command[1].data.f[0]=components[1];
10951       command[1].data.f[1]=components[2];
10952       break;
10953     case CTX_DCMYKA:
10954     case CTX_CMYKA:
10955     case CTX_DCMYKA_A:
10956     case CTX_CMYKA_A:
10957       command[2].data.f[1]=components[4];
10958       /*FALLTHROUGH*/
10959     case CTX_CMYK:
10960     case CTX_DCMYK:
10961       command[0].data.f[1]=components[0];
10962       command[1].data.f[0]=components[1];
10963       command[1].data.f[1]=components[2];
10964       command[2].data.f[0]=components[3];
10965       break;
10966     case CTX_GRAYA:
10967     case CTX_GRAYA_A:
10968       command[1].data.f[0]=components[1];
10969       /*FALLTHROUGH*/
10970     case CTX_GRAY:
10971       command[0].data.f[1]=components[0];
10972       break;
10973   }
10974   ctx_process (ctx, command);
10975 }
10976 
ctx_rgba(Ctx * ctx,float r,float g,float b,float a)10977 void ctx_rgba (Ctx *ctx, float r, float g, float b, float a)
10978 {
10979   float components[4]={r,g,b,a};
10980   ctx_color_raw (ctx, CTX_RGBA, components, 0);
10981 }
10982 
ctx_rgba_stroke(Ctx * ctx,float r,float g,float b,float a)10983 void ctx_rgba_stroke (Ctx *ctx, float r, float g, float b, float a)
10984 {
10985   float components[4]={r,g,b,a};
10986   ctx_color_raw (ctx, CTX_RGBA, components, 1);
10987 }
10988 
ctx_rgb(Ctx * ctx,float r,float g,float b)10989 void ctx_rgb (Ctx *ctx, float   r, float   g, float   b)
10990 {
10991   ctx_rgba (ctx, r, g, b, 1.0f);
10992 }
10993 
ctx_rgb_stroke(Ctx * ctx,float r,float g,float b)10994 void ctx_rgb_stroke (Ctx *ctx, float   r, float   g, float   b)
10995 {
10996   ctx_rgba_stroke (ctx, r, g, b, 1.0f);
10997 }
10998 
ctx_gray_stroke(Ctx * ctx,float gray)10999 void ctx_gray_stroke   (Ctx *ctx, float gray)
11000 {
11001   ctx_color_raw (ctx, CTX_GRAY, &gray, 1);
11002 }
ctx_gray(Ctx * ctx,float gray)11003 void ctx_gray (Ctx *ctx, float gray)
11004 {
11005   ctx_color_raw (ctx, CTX_GRAY, &gray, 0);
11006 }
11007 
ctx_drgba_stroke(Ctx * ctx,float r,float g,float b,float a)11008 void ctx_drgba_stroke (Ctx *ctx, float r, float g, float b, float a)
11009 {
11010   float components[4]={r,g,b,a};
11011   ctx_color_raw (ctx, CTX_DRGBA, components, 1);
11012 }
ctx_drgba(Ctx * ctx,float r,float g,float b,float a)11013 void ctx_drgba (Ctx *ctx, float r, float g, float b, float a)
11014 {
11015   float components[4]={r,g,b,a};
11016   ctx_color_raw (ctx, CTX_DRGBA, components, 0);
11017 }
11018 
11019 #if CTX_ENABLE_CMYK
11020 
ctx_cmyka_stroke(Ctx * ctx,float c,float m,float y,float k,float a)11021 void ctx_cmyka_stroke (Ctx *ctx, float c, float m, float y, float k, float a)
11022 {
11023   float components[5]={c,m,y,k,a};
11024   ctx_color_raw (ctx, CTX_CMYKA, components, 1);
11025 }
ctx_cmyka(Ctx * ctx,float c,float m,float y,float k,float a)11026 void ctx_cmyka (Ctx *ctx, float c, float m, float y, float k, float a)
11027 {
11028   float components[5]={c,m,y,k,a};
11029   ctx_color_raw (ctx, CTX_CMYKA, components, 0);
11030 }
ctx_cmyk_stroke(Ctx * ctx,float c,float m,float y,float k)11031 void ctx_cmyk_stroke   (Ctx *ctx, float c, float m, float y, float k)
11032 {
11033   float components[4]={c,m,y,k};
11034   ctx_color_raw (ctx, CTX_CMYK, components, 1);
11035 }
ctx_cmyk(Ctx * ctx,float c,float m,float y,float k)11036 void ctx_cmyk (Ctx *ctx, float c, float m, float y, float k)
11037 {
11038   float components[4]={c,m,y,k};
11039   ctx_color_raw (ctx, CTX_CMYK, components, 0);
11040 }
11041 
11042 #if 0
11043 static void ctx_dcmyk_raw (Ctx *ctx, float c, float m, float y, float k, int stroke)
11044 {
11045   float components[5]={c,m,y,k,1.0f};
11046   ctx_color_raw (ctx, CTX_DCMYKA, components, stroke);
11047 }
11048 
11049 static void ctx_dcmyka_raw (Ctx *ctx, float c, float m, float y, float k, float a, int stroke)
11050 {
11051   CtxEntry command[3]=
11052   {
11053     ctx_f (CTX_COLOR, CTX_DCMYKA + 512 * stroke, c),
11054     ctx_f (CTX_CONT, m, y),
11055     ctx_f (CTX_CONT, k, a)
11056   };
11057   ctx_process (ctx, command);
11058 }
11059 #endif
11060 
ctx_dcmyk_stroke(Ctx * ctx,float c,float m,float y,float k)11061 void ctx_dcmyk_stroke   (Ctx *ctx, float c, float m, float y, float k)
11062 {
11063   float components[5]={c,m,y,k,1.0f};
11064   ctx_color_raw (ctx, CTX_DCMYK, components, 1);
11065 }
ctx_dcmyk(Ctx * ctx,float c,float m,float y,float k)11066 void ctx_dcmyk (Ctx *ctx, float c, float m, float y, float k)
11067 {
11068   float components[5]={c,m,y,k,1.0f};
11069   ctx_color_raw (ctx, CTX_DCMYK, components, 0);
11070 }
11071 
ctx_dcmyka_stroke(Ctx * ctx,float c,float m,float y,float k,float a)11072 void ctx_dcmyka_stroke   (Ctx *ctx, float c, float m, float y, float k, float a)
11073 {
11074   float components[5]={c,m,y,k,a};
11075   ctx_color_raw (ctx, CTX_DCMYKA, components, 1);
11076 }
ctx_dcmyka(Ctx * ctx,float c,float m,float y,float k,float a)11077 void ctx_dcmyka (Ctx *ctx, float c, float m, float y, float k, float a)
11078 {
11079   float components[5]={c,m,y,k,a};
11080   ctx_color_raw (ctx, CTX_DCMYKA, components, 0);
11081 }
11082 
11083 #endif
11084 
11085 /* XXX: missing CSS1:
11086  *
11087  *   EM { color: rgb(110%, 0%, 0%) }  // clipped to 100%
11088  *
11089  *
11090  *   :first-letter
11091  *   :first-list
11092  *   :link :visited :active
11093  *
11094  */
11095 
11096 typedef struct ColorDef {
11097   uint64_t name;
11098   float r;
11099   float g;
11100   float b;
11101   float a;
11102 } ColorDef;
11103 
11104 #if 0
11105 #define CTX_silver 	CTX_STRH('s','i','l','v','e','r',0,0,0,0,0,0,0,0)
11106 #define CTX_fuchsia 	CTX_STRH('f','u','c','h','s','i','a',0,0,0,0,0,0,0)
11107 #define CTX_gray 	CTX_STRH('g','r','a','y',0,0,0,0,0,0,0,0,0,0)
11108 #define CTX_yellow 	CTX_STRH('y','e','l','l','o','w',0,0,0,0,0,0,0,0)
11109 #define CTX_white 	CTX_STRH('w','h','i','t','e',0,0,0,0,0,0,0,0,0)
11110 #define CTX_maroon 	CTX_STRH('m','a','r','o','o','n',0,0,0,0,0,0,0,0)
11111 #define CTX_magenta 	CTX_STRH('m','a','g','e','n','t','a',0,0,0,0,0,0,0)
11112 #define CTX_blue 	CTX_STRH('b','l','u','e',0,0,0,0,0,0,0,0,0,0)
11113 #define CTX_green 	CTX_STRH('g','r','e','e','n',0,0,0,0,0,0,0,0,0)
11114 #define CTX_red 	CTX_STRH('r','e','d',0,0,0,0,0,0,0,0,0,0,0)
11115 #define CTX_purple 	CTX_STRH('p','u','r','p','l','e',0,0,0,0,0,0,0,0)
11116 #define CTX_olive 	CTX_STRH('o','l','i','v','e',0,0,0,0,0,0,0,0,0)
11117 #define CTX_teal        CTX_STRH('t','e','a','l',0,0,0,0,0,0,0,0,0,0)
11118 #define CTX_black 	CTX_STRH('b','l','a','c','k',0,0,0,0,0,0,0,0,0)
11119 #define CTX_cyan 	CTX_STRH('c','y','a','n',0,0,0,0,0,0,0,0,0,0)
11120 #define CTX_navy 	CTX_STRH('n','a','v','y',0,0,0,0,0,0,0,0,0,0)
11121 #define CTX_lime 	CTX_STRH('l','i','m','e',0,0,0,0,0,0,0,0,0,0)
11122 #define CTX_aqua 	CTX_STRH('a','q','u','a',0,0,0,0,0,0,0,0,0,0)
11123 #define CTX_transparent CTX_STRH('t','r','a','n','s','p','a','r','e','n','t',0,0,0)
11124 #endif
11125 
11126 static ColorDef _ctx_colors[]={
11127   {CTX_black,    0, 0, 0, 1},
11128   {CTX_red,      1, 0, 0, 1},
11129   {CTX_green,    0, 1, 0, 1},
11130   {CTX_yellow,   1, 1, 0, 1},
11131   {CTX_blue,     0, 0, 1, 1},
11132   {CTX_fuchsia,  1, 0, 1, 1},
11133   {CTX_cyan,     0, 1, 1, 1},
11134   {CTX_white,    1, 1, 1, 1},
11135   {CTX_silver,   0.75294, 0.75294, 0.75294, 1},
11136   {CTX_gray,     0.50196, 0.50196, 0.50196, 1},
11137   {CTX_magenta,  0.50196, 0, 0.50196, 1},
11138   {CTX_maroon,   0.50196, 0, 0, 1},
11139   {CTX_purple,   0.50196, 0, 0.50196, 1},
11140   {CTX_green,    0, 0.50196, 0, 1},
11141   {CTX_lime,     0, 1, 0, 1},
11142   {CTX_olive,    0.50196, 0.50196, 0, 1},
11143   {CTX_navy,     0, 0,      0.50196, 1},
11144   {CTX_teal,     0, 0.50196, 0.50196, 1},
11145   {CTX_aqua,     0, 1, 1, 1},
11146   {CTX_transparent, 0, 0, 0, 0},
11147   {CTX_none,     0, 0, 0, 0},
11148 };
11149 
xdigit_value(const char xdigit)11150 static int xdigit_value(const char xdigit)
11151 {
11152   if (xdigit >= '0' && xdigit <= '9')
11153    return xdigit - '0';
11154   switch (xdigit)
11155   {
11156     case 'A':case 'a': return 10;
11157     case 'B':case 'b': return 11;
11158     case 'C':case 'c': return 12;
11159     case 'D':case 'd': return 13;
11160     case 'E':case 'e': return 14;
11161     case 'F':case 'f': return 15;
11162   }
11163   return 0;
11164 }
11165 
11166 static int
ctx_color_parse_rgb(CtxState * ctxstate,CtxColor * color,const char * color_string)11167 ctx_color_parse_rgb (CtxState *ctxstate, CtxColor *color, const char *color_string)
11168 {
11169   float dcolor[4] = {0,0,0,1};
11170   while (*color_string && *color_string != '(')
11171     color_string++;
11172   if (*color_string) color_string++;
11173 
11174   {
11175     int n_floats = 0;
11176     char *p =    (char*)color_string;
11177     char *prev = (char*)NULL;
11178     for (; p && n_floats < 4 && p != prev && *p; )
11179     {
11180       float val;
11181       prev = p;
11182       val = _ctx_parse_float (p, &p);
11183       if (p != prev)
11184       {
11185         if (n_floats < 3)
11186           dcolor[n_floats++] = val/255.0;
11187         else
11188           dcolor[n_floats++] = val;
11189 
11190         while (*p == ' ' || *p == ',')
11191         {
11192           p++;
11193           prev++;
11194         }
11195       }
11196     }
11197   }
11198   ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
11199   return 0;
11200 }
11201 
ctx_isxdigit(uint8_t ch)11202 static int ctx_isxdigit (uint8_t ch)
11203 {
11204   if (ch >= '0' && ch <= '9') return 1;
11205   if (ch >= 'a' && ch <= 'f') return 1;
11206   if (ch >= 'A' && ch <= 'F') return 1;
11207   return 0;
11208 }
11209 
11210 static int
mrg_color_parse_hex(CtxState * ctxstate,CtxColor * color,const char * color_string)11211 mrg_color_parse_hex (CtxState *ctxstate, CtxColor *color, const char *color_string)
11212 {
11213   float dcolor[4]={0,0,0,1};
11214   int string_length = strlen (color_string);
11215   int i;
11216   dcolor[3] = 1.0;
11217 
11218   if (string_length == 7 ||  /* #rrggbb   */
11219       string_length == 9)    /* #rrggbbaa */
11220     {
11221       int num_iterations = (string_length - 1) / 2;
11222 
11223       for (i = 0; i < num_iterations; ++i)
11224         {
11225           if (ctx_isxdigit (color_string[2 * i + 1]) &&
11226               ctx_isxdigit (color_string[2 * i + 2]))
11227             {
11228               dcolor[i] = (xdigit_value (color_string[2 * i + 1]) << 4 |
11229                            xdigit_value (color_string[2 * i + 2])) / 255.f;
11230             }
11231           else
11232             {
11233               return 0;
11234             }
11235         }
11236       /* Successful #rrggbb(aa) parsing! */
11237       ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
11238       return 1;
11239     }
11240   else if (string_length == 4 ||  /* #rgb  */
11241            string_length == 5)    /* #rgba */
11242     {
11243       int num_iterations = string_length - 1;
11244       for (i = 0; i < num_iterations; ++i)
11245         {
11246           if (ctx_isxdigit (color_string[i + 1]))
11247             {
11248               dcolor[i] = (xdigit_value (color_string[i + 1]) << 4 |
11249                            xdigit_value (color_string[i + 1])) / 255.f;
11250             }
11251           else
11252             {
11253               return 0;
11254             }
11255         }
11256       ctx_color_set_rgba (ctxstate, color, dcolor[0], dcolor[1],dcolor[2],dcolor[3]);
11257       /* Successful #rgb(a) parsing! */
11258       return 0;
11259     }
11260   /* String was of unsupported length. */
11261   return 1;
11262 }
11263 
11264 //#define CTX_currentColor 	CTX_STRH('c','u','r','r','e','n','t','C','o','l','o','r',0,0)
11265 
ctx_color_set_from_string(Ctx * ctx,CtxColor * color,const char * string)11266 int ctx_color_set_from_string (Ctx *ctx, CtxColor *color, const char *string)
11267 {
11268   int i;
11269   uint32_t hash = ctx_strhash (string);
11270 //  ctx_color_set_rgba (&(ctx->state), color, 0.4,0.1,0.9,1.0);
11271 //  return 0;
11272     //rgba[0], rgba[1], rgba[2], rgba[3]);
11273 
11274   if (hash == CTX_currentColor)
11275   {
11276     float rgba[4];
11277     CtxColor ccolor;
11278     ctx_get_color (ctx, CTX_color, &ccolor);
11279     ctx_color_get_rgba (&(ctx->state), &ccolor, rgba);
11280     ctx_color_set_rgba (&(ctx->state), color, rgba[0], rgba[1], rgba[2], rgba[3]);
11281     return 0;
11282   }
11283 
11284   for (i = (sizeof(_ctx_colors)/sizeof(_ctx_colors[0]))-1; i>=0; i--)
11285   {
11286     if (hash == _ctx_colors[i].name)
11287     {
11288       ctx_color_set_rgba (&(ctx->state), color,
11289        _ctx_colors[i].r, _ctx_colors[i].g, _ctx_colors[i].b, _ctx_colors[i].a);
11290       return 0;
11291     }
11292   }
11293 
11294   if (string[0] == '#')
11295     mrg_color_parse_hex (&(ctx->state), color, string);
11296   else if (string[0] == 'r' &&
11297       string[1] == 'g' &&
11298       string[2] == 'b'
11299       )
11300     ctx_color_parse_rgb (&(ctx->state), color, string);
11301 
11302   return 0;
11303 }
11304 
ctx_color(Ctx * ctx,const char * string)11305 int ctx_color (Ctx *ctx, const char *string)
11306 {
11307   CtxColor color = {0,};
11308   ctx_color_set_from_string (ctx, &color, string);
11309   float rgba[4];
11310   ctx_color_get_rgba (&(ctx->state), &color, rgba);
11311   ctx_color_raw (ctx, CTX_RGBA, rgba, 0);
11312   return 0;
11313 }
11314 
11315 void
ctx_rgba8(Ctx * ctx,uint8_t r,uint8_t g,uint8_t b,uint8_t a)11316 ctx_rgba8 (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
11317 {
11318 #if 0
11319   CtxEntry command = ctx_u8 (CTX_SET_RGBA_U8, r, g, b, a, 0, 0, 0, 0);
11320 
11321   uint8_t rgba[4];
11322   ctx_color_get_rgba8 (&ctx->state, &ctx->state.gstate.source.color, rgba);
11323   if (rgba[0] == r && rgba[1] == g && rgba[2] == b && rgba[3] == a)
11324      return;
11325 
11326   ctx_process (ctx, &command);
11327 #else
11328   ctx_rgba (ctx, r/255.0f, g/255.0f, b/255.0f, a/255.0f);
11329 #endif
11330 }
11331 
ctx_rgba8_stroke(Ctx * ctx,uint8_t r,uint8_t g,uint8_t b,uint8_t a)11332 void ctx_rgba8_stroke (Ctx *ctx, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
11333 {
11334   ctx_rgba_stroke (ctx, r/255.0f, g/255.0f, b/255.0f, a/255.0f);
11335 }
11336 
11337 
11338 #endif
11339 
11340 #if CTX_BABL
ctx_rasterizer_colorspace_babl(CtxState * state,CtxColorSpace space_slot,const Babl * space)11341 void ctx_rasterizer_colorspace_babl (CtxState      *state,
11342                                      CtxColorSpace  space_slot,
11343                                      const Babl    *space)
11344 {
11345   switch (space_slot)
11346   {
11347     case CTX_COLOR_SPACE_DEVICE_RGB:
11348       state->gstate.device_space = space;
11349       break;
11350     case CTX_COLOR_SPACE_DEVICE_CMYK:
11351       state->gstate.device_space = space;
11352       break;
11353     case CTX_COLOR_SPACE_USER_RGB:
11354       state->gstate.rgb_space = space;
11355       break;
11356     case CTX_COLOR_SPACE_USER_CMYK:
11357       state->gstate.cmyk_space = space;
11358       break;
11359     case CTX_COLOR_SPACE_TEXTURE:
11360       state->gstate.texture_space = space;
11361       break;
11362   }
11363 
11364   const Babl *srgb = babl_space ("sRGB");
11365   if (!state->gstate.texture_space)
11366        state->gstate.texture_space = srgb;
11367   if (!state->gstate.device_space)
11368        state->gstate.device_space = srgb;
11369   if (!state->gstate.rgb_space)
11370        state->gstate.rgb_space = srgb;
11371 
11372   //fprintf (stderr, "%s\n", babl_get_name (state->gstate.device_space));
11373 
11374   state->gstate.fish_rgbaf_device_to_user = babl_fish (
11375        babl_format_with_space ("R'G'B'A float", state->gstate.device_space),
11376        babl_format_with_space ("R'G'B'A float", state->gstate.rgb_space));
11377   state->gstate.fish_rgbaf_user_to_device = babl_fish (
11378        babl_format_with_space ("R'G'B'A float", state->gstate.rgb_space),
11379        babl_format_with_space ("R'G'B'A float", state->gstate.device_space));
11380   state->gstate.fish_rgbaf_texture_to_device = babl_fish (
11381        babl_format_with_space ("R'G'B'A float", state->gstate.texture_space),
11382        babl_format_with_space ("R'G'B'A float", state->gstate.device_space));
11383 }
11384 #endif
11385 
ctx_rasterizer_colorspace_icc(CtxState * state,CtxColorSpace space_slot,char * icc_data,int icc_length)11386 void ctx_rasterizer_colorspace_icc (CtxState      *state,
11387                                     CtxColorSpace  space_slot,
11388                                     char          *icc_data,
11389                                     int            icc_length)
11390 {
11391 #if CTX_BABL
11392    const char *error = NULL;
11393    const Babl *space = NULL;
11394 
11395    if (icc_data == NULL) space = babl_space ("sRGB");
11396    else if (icc_length < 32)
11397    {
11398       if (icc_data[0] == '0' && icc_data[1] == 'x')
11399         sscanf (icc_data, "%p", &space);
11400       else
11401       {
11402         char tmp[24];
11403         int i;
11404         for (i = 0; i < icc_length; i++)
11405           tmp[i]= (icc_data[i]>='A' && icc_data[i]<='Z')?icc_data[i]+('a'-'A'):icc_data[i];
11406         tmp[icc_length]=0;
11407         if (!strcmp (tmp, "srgb"))            space = babl_space ("sRGB");
11408         else if (!strcmp (tmp, "scrgb"))      space = babl_space ("scRGB");
11409         else if (!strcmp (tmp, "acescg"))     space = babl_space ("ACEScg");
11410         else if (!strcmp (tmp, "adobe"))      space = babl_space ("Adobe");
11411         else if (!strcmp (tmp, "apple"))      space = babl_space ("Apple");
11412         else if (!strcmp (tmp, "rec2020"))    space = babl_space ("Rec2020");
11413         else if (!strcmp (tmp, "aces2065-1")) space = babl_space ("ACES2065-1");
11414       }
11415    }
11416 
11417    if (!space)
11418    {
11419      space = babl_space_from_icc (icc_data, icc_length, BABL_ICC_INTENT_RELATIVE_COLORIMETRIC, &error);
11420    }
11421    if (space)
11422    {
11423      ctx_rasterizer_colorspace_babl (state, space_slot, space);
11424    }
11425 #endif
11426 }
11427 
ctx_colorspace(Ctx * ctx,CtxColorSpace space_slot,unsigned char * data,int data_length)11428 void ctx_colorspace (Ctx           *ctx,
11429                      CtxColorSpace  space_slot,
11430                      unsigned char *data,
11431                      int            data_length)
11432 {
11433   if (data)
11434   {
11435     if (data_length <= 0) data_length = (int)strlen ((char*)data);
11436     ctx_process_cmd_str_with_len (ctx, CTX_COLOR_SPACE, (char*)data, space_slot, 0, data_length);
11437   }
11438   else
11439   {
11440     ctx_process_cmd_str_with_len (ctx, CTX_COLOR_SPACE, "sRGB", space_slot, 0, 4);
11441   }
11442 }
11443 
ctx_gradient_add_stop_u8(Ctx * ctx,float pos,uint8_t r,uint8_t g,uint8_t b,uint8_t a)11444 void ctx_gradient_add_stop_u8
11445 (Ctx *ctx, float pos, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
11446 {
11447   CtxEntry entry = ctx_f (CTX_GRADIENT_STOP, pos, 0);
11448   entry.data.u8[4+0] = r;
11449   entry.data.u8[4+1] = g;
11450   entry.data.u8[4+2] = b;
11451   entry.data.u8[4+3] = a;
11452   ctx_process (ctx, &entry);
11453 }
11454 
ctx_gradient_add_stop(Ctx * ctx,float pos,float r,float g,float b,float a)11455 void ctx_gradient_add_stop
11456 (Ctx *ctx, float pos, float r, float g, float b, float a)
11457 {
11458   int ir = r * 255;
11459   int ig = g * 255;
11460   int ib = b * 255;
11461   int ia = a * 255;
11462   ir = CTX_CLAMP (ir, 0,255);
11463   ig = CTX_CLAMP (ig, 0,255);
11464   ib = CTX_CLAMP (ib, 0,255);
11465   ia = CTX_CLAMP (ia, 0,255);
11466   ctx_gradient_add_stop_u8 (ctx, pos, ir, ig, ib, ia);
11467 }
11468 
ctx_gradient_add_stop_string(Ctx * ctx,float pos,const char * string)11469 void ctx_gradient_add_stop_string
11470 (Ctx *ctx, float pos, const char *string)
11471 {
11472   CtxColor color = {0,};
11473   ctx_color_set_from_string (ctx, &color, string);
11474   float rgba[4];
11475   ctx_color_get_rgba (&(ctx->state), &color, rgba);
11476   ctx_gradient_add_stop (ctx, pos, rgba[0], rgba[1], rgba[2], rgba[3]);
11477 }
11478 
11479 //  deviceRGB .. settable when creating an RGB image surface..
11480 //               queryable when running in terminal - is it really needed?
11481 //               though it is settable ; and functional for changing this state at runtime..
11482 //
11483 //  userRGB - settable at any time, stored in save|restore
11484 //  texture - set as the space of data on subsequent
11485 
ctx_state_get(CtxState * state,uint32_t hash)11486 static float ctx_state_get (CtxState *state, uint32_t hash)
11487 {
11488   for (int i = state->gstate.keydb_pos-1; i>=0; i--)
11489     {
11490       if (state->keydb[i].key == hash)
11491         { return state->keydb[i].value; }
11492     }
11493   return -0.0;
11494 }
11495 
ctx_state_set(CtxState * state,uint32_t key,float value)11496 static void ctx_state_set (CtxState *state, uint32_t key, float value)
11497 {
11498   if (key != CTX_new_state)
11499     {
11500       if (ctx_state_get (state, key) == value)
11501         { return; }
11502       for (int i = state->gstate.keydb_pos-1;
11503            i >= 0 && state->keydb[i].key != CTX_new_state;
11504            i--)
11505         {
11506           if (state->keydb[i].key == key)
11507             {
11508               state->keydb[i].value = value;
11509               return;
11510             }
11511         }
11512     }
11513   if (state->gstate.keydb_pos >= CTX_MAX_KEYDB)
11514     { return; }
11515   state->keydb[state->gstate.keydb_pos].key = key;
11516   state->keydb[state->gstate.keydb_pos].value = value;
11517   state->gstate.keydb_pos++;
11518 }
11519 
11520 
11521 #define CTX_KEYDB_STRING_START (-90000.0)
11522 #define CTX_KEYDB_STRING_END   (CTX_KEYDB_STRING_START + CTX_STRINGPOOL_SIZE)
11523 
ctx_float_is_string(float val)11524 static int ctx_float_is_string (float val)
11525 {
11526   return val >= CTX_KEYDB_STRING_START && val <= CTX_KEYDB_STRING_END;
11527 }
11528 
ctx_float_to_string_index(float val)11529 static int ctx_float_to_string_index (float val)
11530 {
11531   int idx = -1;
11532   if (ctx_float_is_string (val))
11533   {
11534     idx = val - CTX_KEYDB_STRING_START;
11535   }
11536   return idx;
11537 }
11538 
ctx_string_index_to_float(int index)11539 static float ctx_string_index_to_float (int index)
11540 {
11541   return CTX_KEYDB_STRING_START + index;
11542 }
11543 
ctx_state_get_blob(CtxState * state,uint32_t key)11544 static void *ctx_state_get_blob (CtxState *state, uint32_t key)
11545 {
11546   float stored = ctx_state_get (state, key);
11547   int idx = ctx_float_to_string_index (stored);
11548   if (idx >= 0)
11549   {
11550      // can we know length?
11551      return &state->stringpool[idx];
11552   }
11553 
11554   // format number as string?
11555   return NULL;
11556 }
11557 
ctx_state_get_string(CtxState * state,uint32_t key)11558 static const char *ctx_state_get_string (CtxState *state, uint32_t key)
11559 {
11560   const char *ret = (char*)ctx_state_get_blob (state, key);
11561   if (ret && ret[0] == 127)
11562     return NULL;
11563   return ret;
11564 }
11565 
11566 
ctx_state_set_blob(CtxState * state,uint32_t key,uint8_t * data,int len)11567 static void ctx_state_set_blob (CtxState *state, uint32_t key, uint8_t *data, int len)
11568 {
11569   int idx = state->gstate.stringpool_pos;
11570 
11571   if (idx + len > CTX_STRINGPOOL_SIZE)
11572   {
11573     ctx_log ("blowing varpool size [%c..]\n", data[0]);
11574     //fprintf (stderr, "blowing varpool size [%c%c%c..]\n", data[0],data[1], data[1]?data[2]:0);
11575 #if 0
11576     for (int i = 0; i< CTX_STRINGPOOL_SIZE; i++)
11577     {
11578        if (i==0) fprintf (stderr, "\n%i ", i);
11579        else      fprintf (stderr, "%c", state->stringpool[i]);
11580     }
11581 #endif
11582     return;
11583   }
11584 
11585   memcpy (&state->stringpool[idx], data, len);
11586   state->gstate.stringpool_pos+=len;
11587   state->stringpool[state->gstate.stringpool_pos++]=0;
11588   ctx_state_set (state, key, ctx_string_index_to_float (idx));
11589 }
11590 
ctx_state_set_string(CtxState * state,uint32_t key,const char * string)11591 static void ctx_state_set_string (CtxState *state, uint32_t key, const char *string)
11592 {
11593   float old_val = ctx_state_get (state, key);
11594   int   old_idx = ctx_float_to_string_index (old_val);
11595 
11596   if (old_idx >= 0)
11597   {
11598     const char *old_string = ctx_state_get_string (state, key);
11599     if (old_string && !strcmp (old_string, string))
11600       return;
11601   }
11602 
11603   if (ctx_str_is_number (string))
11604   {
11605     ctx_state_set (state, key, strtod (string, NULL));
11606     return;
11607   }
11608   // should do same with color
11609 
11610   // XXX should special case when the string modified is at the
11611   //     end of the stringpool.
11612   //
11613   //     for clips the behavior is howevre ideal, since
11614   //     we can have more than one clip per save/restore level
11615   ctx_state_set_blob (state, key, (uint8_t*)string, strlen(string));
11616 }
11617 
ctx_state_get_color(CtxState * state,uint32_t key,CtxColor * color)11618 static int ctx_state_get_color (CtxState *state, uint32_t key, CtxColor *color)
11619 {
11620   CtxColor *stored = (CtxColor*)ctx_state_get_blob (state, key);
11621   if (stored)
11622   {
11623     if (stored->magic == 127)
11624     {
11625       *color = *stored;
11626       return 0;
11627     }
11628   }
11629   return -1;
11630 }
11631 
ctx_state_set_color(CtxState * state,uint32_t key,CtxColor * color)11632 static void ctx_state_set_color (CtxState *state, uint32_t key, CtxColor *color)
11633 {
11634   CtxColor mod_color;
11635   CtxColor old_color;
11636   mod_color = *color;
11637   mod_color.magic = 127;
11638   if (ctx_state_get_color (state, key, &old_color)==0)
11639   {
11640     if (!memcmp (&mod_color, &old_color, sizeof (mod_color)))
11641       return;
11642   }
11643   ctx_state_set_blob (state, key, (uint8_t*)&mod_color, sizeof (CtxColor));
11644 }
11645 
ctx_get_string(Ctx * ctx,uint32_t hash)11646 const char *ctx_get_string (Ctx *ctx, uint32_t hash)
11647 {
11648   return ctx_state_get_string (&ctx->state, hash);
11649 }
ctx_get_float(Ctx * ctx,uint32_t hash)11650 float ctx_get_float (Ctx *ctx, uint32_t hash)
11651 {
11652   return ctx_state_get (&ctx->state, hash);
11653 }
ctx_get_int(Ctx * ctx,uint32_t hash)11654 int ctx_get_int (Ctx *ctx, uint32_t hash)
11655 {
11656   return ctx_state_get (&ctx->state, hash);
11657 }
ctx_set_float(Ctx * ctx,uint32_t hash,float value)11658 void ctx_set_float (Ctx *ctx, uint32_t hash, float value)
11659 {
11660   ctx_state_set (&ctx->state, hash, value);
11661 }
ctx_set_string(Ctx * ctx,uint32_t hash,const char * value)11662 void ctx_set_string (Ctx *ctx, uint32_t hash, const char *value)
11663 {
11664   ctx_state_set_string (&ctx->state, hash, value);
11665 }
ctx_set_color(Ctx * ctx,uint32_t hash,CtxColor * color)11666 void ctx_set_color (Ctx *ctx, uint32_t hash, CtxColor *color)
11667 {
11668   ctx_state_set_color (&ctx->state, hash, color);
11669 }
ctx_get_color(Ctx * ctx,uint32_t hash,CtxColor * color)11670 int  ctx_get_color (Ctx *ctx, uint32_t hash, CtxColor *color)
11671 {
11672   return ctx_state_get_color (&ctx->state, hash, color);
11673 }
ctx_is_set(Ctx * ctx,uint32_t hash)11674 int ctx_is_set (Ctx *ctx, uint32_t hash)
11675 {
11676   return ctx_get_float (ctx, hash) != -0.0f;
11677 }
ctx_is_set_now(Ctx * ctx,uint32_t hash)11678 int ctx_is_set_now (Ctx *ctx, uint32_t hash)
11679 {
11680   return ctx_is_set (ctx, hash);
11681 }
11682 
11683 #if CTX_COMPOSITE
11684 
11685 #define CTX_REFERENCE 0
11686 
11687 
11688 #define CTX_RGBA8_R_SHIFT  0
11689 #define CTX_RGBA8_G_SHIFT  8
11690 #define CTX_RGBA8_B_SHIFT  16
11691 #define CTX_RGBA8_A_SHIFT  24
11692 
11693 #define CTX_RGBA8_R_MASK   (0xff << CTX_RGBA8_R_SHIFT)
11694 #define CTX_RGBA8_G_MASK   (0xff << CTX_RGBA8_G_SHIFT)
11695 #define CTX_RGBA8_B_MASK   (0xff << CTX_RGBA8_B_SHIFT)
11696 #define CTX_RGBA8_A_MASK   (0xff << CTX_RGBA8_A_SHIFT)
11697 
11698 #define CTX_RGBA8_RB_MASK  (CTX_RGBA8_R_MASK | CTX_RGBA8_B_MASK)
11699 #define CTX_RGBA8_GA_MASK  (CTX_RGBA8_G_MASK | CTX_RGBA8_A_MASK)
11700 
11701 
11702 CTX_INLINE static void
ctx_RGBA8_associate_alpha(uint8_t * u8)11703 ctx_RGBA8_associate_alpha (uint8_t *u8)
11704 {
11705 #if 1
11706   uint32_t val = *((uint32_t*)(u8));
11707   uint32_t a = u8[3];
11708   uint32_t g = (((val & CTX_RGBA8_G_MASK) * a) >> 8) & CTX_RGBA8_G_MASK;
11709   uint32_t rb =(((val & CTX_RGBA8_RB_MASK) * a) >> 8) & CTX_RGBA8_RB_MASK;
11710   *((uint32_t*)(u8)) = g|rb|(a << CTX_RGBA8_A_SHIFT);
11711 #else
11712   uint32_t a = u8[3];
11713   u8[0] = (u8[0] * a + 255) >> 8;
11714   u8[1] = (u8[1] * a + 255) >> 8;
11715   u8[2] = (u8[2] * a + 255) >> 8;
11716 #endif
11717 }
11718 
11719 CTX_INLINE static void
ctx_RGBA8_associate_alpha_probably_opaque(uint8_t * u8)11720 ctx_RGBA8_associate_alpha_probably_opaque (uint8_t *u8)
11721 {
11722   uint32_t val = *((uint32_t*)(u8));
11723   uint32_t a = val>>24;//u8[3];
11724   //if (CTX_UNLIKELY(a==0))
11725   //   *((uint32_t*)(u8)) = 0;
11726   if (CTX_UNLIKELY(a!=255))
11727   {
11728      uint32_t g = (((val & CTX_RGBA8_G_MASK) * a) >> 8) & CTX_RGBA8_G_MASK;
11729      uint32_t rb =(((val & CTX_RGBA8_RB_MASK) * a) >> 8) & CTX_RGBA8_RB_MASK;
11730      *((uint32_t*)(u8)) = g|rb|(a << CTX_RGBA8_A_SHIFT);
11731   }
11732 }
11733 
ctx_bi_RGBA8(uint32_t isrc00,uint32_t isrc01,uint32_t isrc10,uint32_t isrc11,uint8_t dx,uint8_t dy)11734 CTX_INLINE static uint32_t ctx_bi_RGBA8 (uint32_t isrc00, uint32_t isrc01, uint32_t isrc10, uint32_t isrc11, uint8_t dx, uint8_t dy)
11735 {
11736 #if 0
11737 #if 0
11738   uint8_t ret[4];
11739   uint8_t *src00 = (uint8_t*)&isrc00;
11740   uint8_t *src10 = (uint8_t*)&isrc10;
11741   uint8_t *src01 = (uint8_t*)&isrc01;
11742   uint8_t *src11 = (uint8_t*)&isrc11;
11743   for (int c = 0; c < 4; c++)
11744   {
11745     ret[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dx),
11746                          ctx_lerp_u8 (src10[c], src11[c], dx), dy);
11747   }
11748   return  ((uint32_t*)&ret[0])[0];
11749 #else
11750   return ctx_lerp_RGBA8 (ctx_lerp_RGBA8 (isrc00, isrc01, dx),
11751                          ctx_lerp_RGBA8 (isrc10, isrc11, dx), dy);
11752 #endif
11753 #else
11754   uint32_t s0_ga, s0_rb, s1_ga, s1_rb;
11755   ctx_lerp_RGBA8_split (isrc00, isrc01, dx, &s0_ga, &s0_rb);
11756   ctx_lerp_RGBA8_split (isrc10, isrc11, dx, &s1_ga, &s1_rb);
11757   return ctx_lerp_RGBA8_merge (s0_ga, s0_rb, s1_ga, s1_rb, dy);
11758 #endif
11759 }
11760 
11761 #if CTX_GRADIENTS
11762 #if CTX_GRADIENT_CACHE
11763 static uint8_t ctx_gradient_cache_u8[CTX_GRADIENT_CACHE_ELEMENTS][4];
11764 extern int ctx_gradient_cache_valid;
11765 
11766 
ctx_grad_index(float v)11767 inline static int ctx_grad_index (float v)
11768 {
11769   int ret = v * (CTX_GRADIENT_CACHE_ELEMENTS - 1) + 0.5f;
11770   ret = ctx_maxi (0, ret);
11771   ret = ctx_mini (CTX_GRADIENT_CACHE_ELEMENTS-1, ret);
11772   return ret;
11773 }
11774 
ctx_grad_index_i(int v)11775 inline static int ctx_grad_index_i (int v)
11776 {
11777   v = v >> 8;
11778   return ctx_maxi (0, ctx_mini (CTX_GRADIENT_CACHE_ELEMENTS-1, v));
11779 }
11780 
11781 
11782 //static void
11783 //ctx_gradient_cache_reset (void)
11784 //{
11785 //  ctx_gradient_cache_valid = 0;
11786 //}
11787 #endif
11788 
11789 
11790 CTX_INLINE static void
_ctx_fragment_gradient_1d_RGBA8(CtxRasterizer * rasterizer,float x,float y,uint8_t * rgba)11791 _ctx_fragment_gradient_1d_RGBA8 (CtxRasterizer *rasterizer, float x, float y, uint8_t *rgba)
11792 {
11793   float v = x;
11794   CtxGradient *g = &rasterizer->state->gradient;
11795   if (v < 0) { v = 0; }
11796   if (v > 1) { v = 1; }
11797 
11798   if (g->n_stops == 0)
11799     {
11800       rgba[0] = rgba[1] = rgba[2] = v * 255;
11801       rgba[3] = 255;
11802       return;
11803     }
11804   CtxGradientStop *stop      = NULL;
11805   CtxGradientStop *next_stop = &g->stops[0];
11806   CtxColor *color;
11807   for (int s = 0; s < g->n_stops; s++)
11808     {
11809       stop      = &g->stops[s];
11810       next_stop = &g->stops[s+1];
11811       if (s + 1 >= g->n_stops) { next_stop = NULL; }
11812       if (v >= stop->pos && next_stop && v < next_stop->pos)
11813         { break; }
11814       stop = NULL;
11815       next_stop = NULL;
11816     }
11817   if (stop == NULL && next_stop)
11818     {
11819       color = & (next_stop->color);
11820     }
11821   else if (stop && next_stop == NULL)
11822     {
11823       color = & (stop->color);
11824     }
11825   else if (stop && next_stop)
11826     {
11827       uint8_t stop_rgba[4];
11828       uint8_t next_rgba[4];
11829       ctx_color_get_rgba8 (rasterizer->state, & (stop->color), stop_rgba);
11830       ctx_color_get_rgba8 (rasterizer->state, & (next_stop->color), next_rgba);
11831       int dx = (v - stop->pos) * 255 / (next_stop->pos - stop->pos);
11832 #if 1
11833       ((uint32_t*)rgba)[0] = ctx_lerp_RGBA8 (((uint32_t*)stop_rgba)[0],
11834                                              ((uint32_t*)next_rgba)[0], dx);
11835 #else
11836       for (int c = 0; c < 4; c++)
11837         { rgba[c] = ctx_lerp_u8 (stop_rgba[c], next_rgba[c], dx); }
11838 #endif
11839       ctx_RGBA8_associate_alpha (rgba);
11840       return;
11841     }
11842   else
11843     {
11844       color = & (g->stops[g->n_stops-1].color);
11845     }
11846   ctx_color_get_rgba8 (rasterizer->state, color, rgba);
11847   if (rasterizer->swap_red_green)
11848   {
11849     uint8_t tmp = rgba[0];
11850     rgba[0] = rgba[2];
11851     rgba[2] = tmp;
11852   }
11853   ctx_RGBA8_associate_alpha (rgba);
11854 }
11855 
11856 #if CTX_GRADIENT_CACHE
11857 static void
11858 ctx_gradient_cache_prime (CtxRasterizer *rasterizer);
11859 #endif
11860 
11861 CTX_INLINE static void
ctx_fragment_gradient_1d_RGBA8(CtxRasterizer * rasterizer,float x,float y,uint8_t * rgba)11862 ctx_fragment_gradient_1d_RGBA8 (CtxRasterizer *rasterizer, float x, float y, uint8_t *rgba)
11863 {
11864 #if CTX_GRADIENT_CACHE
11865   *((uint32_t*)rgba) = *((uint32_t*)(&ctx_gradient_cache_u8[ctx_grad_index(x)][0]));
11866 #else
11867  _ctx_fragment_gradient_1d_RGBA8 (rasterizer, x, y, rgba);
11868 #endif
11869 }
11870 #endif
11871 
11872 CTX_INLINE static void
ctx_u8_associate_alpha(int components,uint8_t * u8)11873 ctx_u8_associate_alpha (int components, uint8_t *u8)
11874 {
11875   for (int c = 0; c < components-1; c++)
11876     u8[c] = (u8[c] * u8[components-1] + 255)>>8;
11877 }
11878 
11879 #if CTX_GRADIENTS
11880 #if CTX_GRADIENT_CACHE
11881 static void
ctx_gradient_cache_prime(CtxRasterizer * rasterizer)11882 ctx_gradient_cache_prime (CtxRasterizer *rasterizer)
11883 {
11884   if (ctx_gradient_cache_valid)
11885     return;
11886   for (int u = 0; u < CTX_GRADIENT_CACHE_ELEMENTS; u++)
11887   {
11888     float v = u / (CTX_GRADIENT_CACHE_ELEMENTS - 1.0f);
11889     _ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 0.0f, &ctx_gradient_cache_u8[u][0]);
11890     //*((uint32_t*)(&ctx_gradient_cache_u8_a[u][0]))= *((uint32_t*)(&ctx_gradient_cache_u8[u][0]));
11891     //memcpy(&ctx_gradient_cache_u8_a[u][0], &ctx_gradient_cache_u8[u][0], 4);
11892     //ctx_RGBA8_associate_alpha (&ctx_gradient_cache_u8_a[u][0]);
11893   }
11894   ctx_gradient_cache_valid = 1;
11895 }
11896 #endif
11897 
11898 CTX_INLINE static void
ctx_fragment_gradient_1d_GRAYA8(CtxRasterizer * rasterizer,float x,float y,uint8_t * rgba)11899 ctx_fragment_gradient_1d_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, uint8_t *rgba)
11900 {
11901   float v = x;
11902   CtxGradient *g = &rasterizer->state->gradient;
11903   if (v < 0) { v = 0; }
11904   if (v > 1) { v = 1; }
11905   if (g->n_stops == 0)
11906     {
11907       rgba[0] = rgba[1] = rgba[2] = v * 255;
11908       rgba[1] = 255;
11909       return;
11910     }
11911   CtxGradientStop *stop      = NULL;
11912   CtxGradientStop *next_stop = &g->stops[0];
11913   CtxColor *color;
11914   for (int s = 0; s < g->n_stops; s++)
11915     {
11916       stop      = &g->stops[s];
11917       next_stop = &g->stops[s+1];
11918       if (s + 1 >= g->n_stops) { next_stop = NULL; }
11919       if (v >= stop->pos && next_stop && v < next_stop->pos)
11920         { break; }
11921       stop = NULL;
11922       next_stop = NULL;
11923     }
11924   if (stop == NULL && next_stop)
11925     {
11926       color = & (next_stop->color);
11927     }
11928   else if (stop && next_stop == NULL)
11929     {
11930       color = & (stop->color);
11931     }
11932   else if (stop && next_stop)
11933     {
11934       uint8_t stop_rgba[4];
11935       uint8_t next_rgba[4];
11936       ctx_color_get_graya_u8 (rasterizer->state, & (stop->color), stop_rgba);
11937       ctx_color_get_graya_u8 (rasterizer->state, & (next_stop->color), next_rgba);
11938       int dx = (v - stop->pos) * 255 / (next_stop->pos - stop->pos);
11939       for (int c = 0; c < 2; c++)
11940         { rgba[c] = ctx_lerp_u8 (stop_rgba[c], next_rgba[c], dx); }
11941       return;
11942     }
11943   else
11944     {
11945       color = & (g->stops[g->n_stops-1].color);
11946     }
11947   ctx_color_get_graya_u8 (rasterizer->state, color, rgba);
11948 }
11949 
11950 CTX_INLINE static void
ctx_fragment_gradient_1d_RGBAF(CtxRasterizer * rasterizer,float v,float y,float * rgba)11951 ctx_fragment_gradient_1d_RGBAF (CtxRasterizer *rasterizer, float v, float y, float *rgba)
11952 {
11953   CtxGradient *g = &rasterizer->state->gradient;
11954   if (v < 0) { v = 0; }
11955   if (v > 1) { v = 1; }
11956   if (g->n_stops == 0)
11957     {
11958       rgba[0] = rgba[1] = rgba[2] = v;
11959       rgba[3] = 1.0;
11960       return;
11961     }
11962   CtxGradientStop *stop      = NULL;
11963   CtxGradientStop *next_stop = &g->stops[0];
11964   CtxColor *color;
11965   for (int s = 0; s < g->n_stops; s++)
11966     {
11967       stop      = &g->stops[s];
11968       next_stop = &g->stops[s+1];
11969       if (s + 1 >= g->n_stops) { next_stop = NULL; }
11970       if (v >= stop->pos && next_stop && v < next_stop->pos)
11971         { break; }
11972       stop = NULL;
11973       next_stop = NULL;
11974     }
11975   if (stop == NULL && next_stop)
11976     {
11977       color = & (next_stop->color);
11978     }
11979   else if (stop && next_stop == NULL)
11980     {
11981       color = & (stop->color);
11982     }
11983   else if (stop && next_stop)
11984     {
11985       float stop_rgba[4];
11986       float next_rgba[4];
11987       ctx_color_get_rgba (rasterizer->state, & (stop->color), stop_rgba);
11988       ctx_color_get_rgba (rasterizer->state, & (next_stop->color), next_rgba);
11989       int dx = (v - stop->pos) / (next_stop->pos - stop->pos);
11990       for (int c = 0; c < 4; c++)
11991         { rgba[c] = ctx_lerpf (stop_rgba[c], next_rgba[c], dx); }
11992       return;
11993     }
11994   else
11995     {
11996       color = & (g->stops[g->n_stops-1].color);
11997     }
11998   ctx_color_get_rgba (rasterizer->state, color, rgba);
11999 }
12000 #endif
12001 
12002 static void
ctx_fragment_image_RGBA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12003 ctx_fragment_image_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
12004 {
12005   uint8_t *rgba = (uint8_t *) out;
12006   CtxSource *g = &rasterizer->state->gstate.source_fill;
12007   CtxBuffer *buffer = g->texture.buffer->color_managed;
12008   ctx_assert (rasterizer);
12009   ctx_assert (g);
12010   ctx_assert (buffer);
12011 
12012   for (int i = 0; i < count; i ++)
12013   {
12014 
12015   int u = x;
12016   int v = y;
12017   int width = buffer->width;
12018   int height = buffer->height;
12019   if ( u < 0 || v < 0 ||
12020        u >= width ||
12021        v >= height)
12022     {
12023       *((uint32_t*)(rgba)) = 0;
12024     }
12025   else
12026     {
12027       int bpp = buffer->format->bpp/8;
12028       if (rasterizer->state->gstate.image_smoothing)
12029       {
12030       uint8_t *src00 = (uint8_t *) buffer->data;
12031       src00 += v * buffer->stride + u * bpp;
12032       uint8_t *src01 = src00;
12033       if ( u + 1 < width)
12034       {
12035         src01 = src00 + bpp;
12036       }
12037       uint8_t *src11 = src01;
12038       uint8_t *src10 = src00;
12039       if ( v + 1 < height)
12040       {
12041         src10 = src00 + buffer->stride;
12042         src11 = src01 + buffer->stride;
12043       }
12044       float dx = (x-(int)(x)) * 255.9;
12045       float dy = (y-(int)(y)) * 255.9;
12046 
12047       switch (bpp)
12048       {
12049       case 1:
12050         rgba[0] = rgba[1] = rgba[2] = ctx_lerp_u8 (ctx_lerp_u8 (src00[0], src01[0], dx),
12051                                ctx_lerp_u8 (src10[0], src11[0], dx), dy);
12052         rgba[3] = 255;
12053         break;
12054       case 2:
12055         rgba[0] = rgba[1] = rgba[2] = ctx_lerp_u8 (ctx_lerp_u8 (src00[0], src01[0], dx),
12056                                ctx_lerp_u8 (src10[0], src11[0], dx), dy);
12057         rgba[3] = ctx_lerp_u8 (ctx_lerp_u8 (src00[1], src01[1], dx),
12058                                ctx_lerp_u8 (src10[1], src11[1], dx), dy);
12059         break;
12060       case 3:
12061       for (int c = 0; c < bpp; c++)
12062         { rgba[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dx),
12063                                  ctx_lerp_u8 (src10[c], src11[c], dx), dy);
12064 
12065         }
12066         rgba[3]=255;
12067         break;
12068       break;
12069       case 4:
12070       for (int c = 0; c < bpp; c++)
12071         { rgba[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dx),
12072                                  ctx_lerp_u8 (src10[c], src11[c], dx), dy);
12073 
12074         }
12075       }
12076       }
12077       else
12078       {
12079       uint8_t *src = (uint8_t *) buffer->data;
12080       src += v * buffer->stride + u * bpp;
12081       switch (bpp)
12082         {
12083           case 1:
12084             for (int c = 0; c < 3; c++)
12085               { rgba[c] = src[0]; }
12086             rgba[3] = 255;
12087             break;
12088           case 2:
12089             for (int c = 0; c < 3; c++)
12090               { rgba[c] = src[0]; }
12091             rgba[3] = src[1];
12092             break;
12093           case 3:
12094             for (int c = 0; c < 3; c++)
12095               { rgba[c] = src[c]; }
12096             rgba[3] = 255;
12097             break;
12098           case 4:
12099             for (int c = 0; c < 4; c++)
12100               { rgba[c] = src[c]; }
12101             break;
12102         }
12103       }
12104       if (rasterizer->swap_red_green)
12105       {
12106         uint8_t tmp = rgba[0];
12107         rgba[0] = rgba[2];
12108         rgba[2] = tmp;
12109       }
12110     }
12111     ctx_RGBA8_associate_alpha_probably_opaque (rgba); // XXX: really?
12112     rgba += 4;
12113     x += dx;
12114     y += dy;
12115   }
12116 }
12117 
12118 #if CTX_DITHER
ctx_dither_mask_a(int x,int y,int c,int divisor)12119 static inline int ctx_dither_mask_a (int x, int y, int c, int divisor)
12120 {
12121   /* https://pippin.gimp.org/a_dither/ */
12122   return ( ( ( ( (x + c * 67) + y * 236) * 119) & 255 )-127) / divisor;
12123 }
12124 
12125 inline static void
ctx_dither_rgba_u8(uint8_t * rgba,int x,int y,int dither_red_blue,int dither_green)12126 ctx_dither_rgba_u8 (uint8_t *rgba, int x, int y, int dither_red_blue, int dither_green)
12127 {
12128   if (dither_red_blue == 0)
12129     { return; }
12130   for (int c = 0; c < 3; c ++)
12131     {
12132       int val = rgba[c] + ctx_dither_mask_a (x, y, 0, c==1?dither_green:dither_red_blue);
12133       rgba[c] = CTX_CLAMP (val, 0, 255);
12134     }
12135 }
12136 
12137 inline static void
ctx_dither_graya_u8(uint8_t * rgba,int x,int y,int dither_red_blue,int dither_green)12138 ctx_dither_graya_u8 (uint8_t *rgba, int x, int y, int dither_red_blue, int dither_green)
12139 {
12140   if (dither_red_blue == 0)
12141     { return; }
12142   for (int c = 0; c < 1; c ++)
12143     {
12144       int val = rgba[c] + ctx_dither_mask_a (x, y, 0, dither_red_blue);
12145       rgba[c] = CTX_CLAMP (val, 0, 255);
12146     }
12147 }
12148 #endif
12149 
12150 CTX_INLINE static void
ctx_RGBA8_deassociate_alpha(const uint8_t * in,uint8_t * out)12151 ctx_RGBA8_deassociate_alpha (const uint8_t *in, uint8_t *out)
12152 {
12153     uint32_t val = *((uint32_t*)(in));
12154     int a = val >> CTX_RGBA8_A_SHIFT;
12155     if (a)
12156     {
12157     if (a ==255)
12158     {
12159       *((uint32_t*)(out)) = val;
12160     } else
12161     {
12162       uint32_t g = (((val & CTX_RGBA8_G_MASK) * 255 / a) >> 8) & CTX_RGBA8_G_MASK;
12163       uint32_t rb =(((val & CTX_RGBA8_RB_MASK) * 255 / a) >> 8) & CTX_RGBA8_RB_MASK;
12164       *((uint32_t*)(out)) = g|rb|(a << CTX_RGBA8_A_SHIFT);
12165     }
12166     }
12167     else
12168     {
12169       *((uint32_t*)(out)) = 0;
12170     }
12171 }
12172 
12173 CTX_INLINE static void
ctx_u8_deassociate_alpha(int components,const uint8_t * in,uint8_t * out)12174 ctx_u8_deassociate_alpha (int components, const uint8_t *in, uint8_t *out)
12175 {
12176   if (in[components-1])
12177   {
12178     if (in[components-1] != 255)
12179     for (int c = 0; c < components-1; c++)
12180       out[c] = (in[c] * 255) / in[components-1];
12181     else
12182     for (int c = 0; c < components-1; c++)
12183       out[c] = in[c];
12184     out[components-1] = in[components-1];
12185   }
12186   else
12187   {
12188   for (int c = 0; c < components; c++)
12189     out[c] = 0;
12190   }
12191 }
12192 
12193 CTX_INLINE static void
ctx_float_associate_alpha(int components,float * rgba)12194 ctx_float_associate_alpha (int components, float *rgba)
12195 {
12196   float alpha = rgba[components-1];
12197   for (int c = 0; c < components-1; c++)
12198     rgba[c] *= alpha;
12199 }
12200 
12201 CTX_INLINE static void
ctx_float_deassociate_alpha(int components,float * rgba,float * dst)12202 ctx_float_deassociate_alpha (int components, float *rgba, float *dst)
12203 {
12204   float ralpha = rgba[components-1];
12205   if (ralpha != 0.0) ralpha = 1.0/ralpha;
12206 
12207   for (int c = 0; c < components-1; c++)
12208     dst[c] = (rgba[c] * ralpha);
12209   dst[components-1] = rgba[components-1];
12210 }
12211 
12212 CTX_INLINE static void
ctx_RGBAF_associate_alpha(float * rgba)12213 ctx_RGBAF_associate_alpha (float *rgba)
12214 {
12215   ctx_float_associate_alpha (4, rgba);
12216 }
12217 
12218 CTX_INLINE static void
ctx_RGBAF_deassociate_alpha(float * rgba,float * dst)12219 ctx_RGBAF_deassociate_alpha (float *rgba, float *dst)
12220 {
12221   ctx_float_deassociate_alpha (4, rgba, dst);
12222 }
12223 
12224 
ctx_swap_red_green_u8(void * data)12225 static inline void ctx_swap_red_green_u8 (void *data)
12226 {
12227   uint8_t *rgba = (uint8_t*)data;
12228   uint8_t tmp = rgba[0];
12229   rgba[0] = rgba[2];
12230   rgba[2] = tmp;
12231 }
12232 
12233 static void
ctx_fragment_swap_red_green_u8(void * out,int count)12234 ctx_fragment_swap_red_green_u8 (void *out, int count)
12235 {
12236   uint8_t *rgba = (uint8_t*)out;
12237   for (int x = 0; x < count; x++)
12238   {
12239     ctx_swap_red_green_u8 (rgba);
12240     rgba += 4;
12241   }
12242 }
12243 
12244 /**** rgb8 ***/
12245 
12246 static void
ctx_fragment_image_rgb8_RGBA8_box(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12247 ctx_fragment_image_rgb8_RGBA8_box (CtxRasterizer *rasterizer,
12248                                    float x,
12249                                    float y,
12250                                    void *out, int count, float dx, float dy)
12251 {
12252   uint8_t *rgba = (uint8_t *) out;
12253   CtxSource *g = &rasterizer->state->gstate.source_fill;
12254   CtxBuffer *buffer = g->texture.buffer->color_managed;
12255   int width = buffer->width;
12256   int height = buffer->height;
12257 
12258   for (int i = 0; i < count; i++)
12259   {
12260 
12261   int u = x;
12262   int v = y;
12263   if ( u < 0 || v < 0 ||
12264        u >= width ||
12265        v >= height)
12266     {
12267       *((uint32_t*)(rgba))= 0;
12268     }
12269   else
12270     {
12271       int bpp = 3;
12272       rgba[3]=255;
12273       float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
12274           int dim = (1.0 / factor) / 2;
12275           uint64_t sum[4]={0,0,0,0};
12276           int count = 0;
12277           for (int ou = - dim; ou < dim; ou++)
12278           for (int ov = - dim; ov < dim; ov++)
12279           {
12280             uint8_t *src = (uint8_t *) buffer->data;
12281 
12282             if (v+ov >= 0 && u+ou >=0 && u + ou < width && v + ov < height)
12283             {
12284               int o = (v+ov) * width + (u + ou);
12285               src += o * bpp;
12286 
12287               for (int c = 0; c < bpp; c++)
12288                 sum[c] += src[c];
12289               count ++;
12290             }
12291           }
12292           if (count)
12293           {
12294             int recip = 65536/count;
12295             for (int c = 0; c < bpp; c++)
12296               rgba[c] = sum[c] * recip >> 16;
12297           }
12298           ctx_RGBA8_associate_alpha_probably_opaque (rgba);
12299     }
12300     rgba += 4;
12301     x += dx;
12302     y += dy;
12303   }
12304 #if CTX_DITHER
12305 //ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
12306 //                    rasterizer->format->dither_green);
12307 #endif
12308 }
12309 
12310 static void
ctx_fragment_image_rgb8_RGBA8_box_swap_red_green(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12311 ctx_fragment_image_rgb8_RGBA8_box_swap_red_green (CtxRasterizer *rasterizer,
12312                                   float x,
12313                                   float y,
12314                                   void *out, int count, float dx, float dy)
12315 {
12316   ctx_fragment_image_rgb8_RGBA8_box (rasterizer, x, y, out, count, dx, dy);
12317   ctx_fragment_swap_red_green_u8 (out, count);
12318 }
12319 
12320 
12321 #if CTX_FRAGMENT_SPECIALIZE
12322 static void
ctx_fragment_image_rgb8_RGBA8_bi(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12323 ctx_fragment_image_rgb8_RGBA8_bi (CtxRasterizer *rasterizer,
12324                                   float x,
12325                                   float y,
12326                                   void *out, int count, float dx, float dy)
12327 {
12328   uint8_t *rgba = (uint8_t *) out;
12329 
12330   CtxSource *g = &rasterizer->state->gstate.source_fill;
12331   CtxBuffer *buffer = g->texture.buffer->color_managed;
12332   int width = buffer->width;
12333   int height = buffer->height;
12334 
12335   for (int i = 0; i < count; i++)
12336   {
12337 
12338   int u = x;
12339   int v = y;
12340   if ( u < 0 || v < 0 ||
12341        u >= width ||
12342        v >= height)
12343     {
12344       *((uint32_t*)(rgba))= 0;
12345     }
12346   else
12347     {
12348       int bpp = 3;
12349       rgba[3]=255;
12350       uint8_t *src00 = (uint8_t *) buffer->data;
12351       int stride = buffer->stride;
12352       src00 += v * stride + u * bpp;
12353       uint8_t *src01 = src00;
12354       if ( u + 1 < width)
12355       {
12356         src01 = src00 + bpp;
12357       }
12358       uint8_t *src11 = src01;
12359       uint8_t *src10 = src00;
12360       if ( v + 1 < height)
12361       {
12362         src10 = src00 + stride;
12363         src11 = src01 + stride;
12364       }
12365       float dx = (x-(int)(x)) * 255.9f;
12366       float dy = (y-(int)(y)) * 255.9f;
12367       for (int c = 0; c < bpp; c++)
12368       {
12369         rgba[c] = ctx_lerp_u8 (ctx_lerp_u8 (src00[c], src01[c], dx),
12370                                ctx_lerp_u8 (src10[c], src11[c], dx), dy);
12371       }
12372       ctx_RGBA8_associate_alpha_probably_opaque (rgba);
12373     }
12374     x += dx;
12375     y += dy;
12376     rgba += 4;
12377   }
12378 #if CTX_DITHER
12379 //ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
12380 //                    rasterizer->format->dither_green);
12381 #endif
12382 }
12383 
12384 static void
ctx_fragment_image_rgb8_RGBA8_bi_swap_red_green(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12385 ctx_fragment_image_rgb8_RGBA8_bi_swap_red_green (CtxRasterizer *rasterizer,
12386                                   float x,
12387                                   float y,
12388                                   void *out, int count, float dx, float dy)
12389 {
12390   ctx_fragment_image_rgb8_RGBA8_bi (rasterizer, x, y, out, count, dx, dy);
12391   ctx_fragment_swap_red_green_u8 (out, count);
12392 }
12393 
12394 static CTX_INLINE void
ctx_fragment_image_rgb8_RGBA8_nearest(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12395 ctx_fragment_image_rgb8_RGBA8_nearest (CtxRasterizer *rasterizer,
12396                                        float x,
12397                                        float y,
12398                                        void *out, int count, float dx, float dy)
12399 {
12400   CtxSource *g = &rasterizer->state->gstate.source_fill;
12401   CtxBuffer *buffer = g->texture.buffer;
12402   if (buffer->color_managed)
12403    buffer = buffer->color_managed;
12404   uint8_t *rgba = (uint8_t *) out;
12405   uint8_t *src = (uint8_t *) buffer->data;
12406   int bwidth = buffer->width;
12407   int bheight = buffer->height;
12408   int stride = buffer->stride;
12409 
12410   x += 0.5f;
12411   y += 0.5f;
12412 
12413   if (CTX_UNLIKELY (dy == 0.0f && dx > 0.999f && dx < 1.001f))
12414   {
12415     int v = y;
12416     int u = x;
12417 
12418     if (v < buffer->height && v > 0)
12419     {
12420       int o = v * stride + u * 3;
12421       int i;
12422       for (i = 0; i < count && u < bwidth && u <0; i++)
12423       {
12424         *((uint32_t*)(rgba))= 0;
12425         rgba += 4;
12426         o += 3;
12427         u+=1;
12428       }
12429 
12430       for (; i < count && u < bwidth; i++)
12431       {
12432         rgba[0] = src[o];
12433         rgba[1] = src[o+1];
12434         rgba[2] = src[o+2];
12435         rgba[3]=255;
12436         rgba += 4;
12437         o += 3;
12438         u+=1;
12439       }
12440       for (; i < count; i++)
12441       {
12442         *((uint32_t*)(rgba))= 0;
12443         rgba += 4;
12444       }
12445     }
12446     else
12447     {
12448       for (int i = 0; i < count; i++)
12449       {
12450         *((uint32_t*)(rgba))= 0;
12451         rgba+=4;
12452       }
12453     }
12454   }
12455   else
12456   {
12457     int u = x;
12458     int v = y;
12459     int i;
12460     for (i = 0; i < count && u < bwidth && u <0; i++)
12461     {
12462       u = x;
12463       v = y;;
12464       *((uint32_t*)(rgba))= 0;
12465       x += dx;
12466       y += dy;
12467       rgba += 4;
12468     }
12469     for (; i < count && u < bwidth; i++)
12470     {
12471       u = x;
12472       v = y;
12473     if (CTX_UNLIKELY(v < 0 || v >= bheight))
12474       {
12475         *((uint32_t*)(rgba))= 0;
12476       }
12477     else
12478       {
12479         int o = v * stride + u * 3;
12480         rgba[0] = src[o];
12481         rgba[1] = src[o+1];
12482         rgba[2] = src[o+2];
12483         rgba[3]=255;
12484       }
12485 
12486       rgba += 4;
12487       x += dx;
12488       y += dy;
12489     }
12490       for (; i < count; i++)
12491       {
12492         *((uint32_t*)(rgba))= 0;
12493         rgba += 4;
12494       }
12495   }
12496 #if CTX_DITHER
12497   //ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
12498   //                    rasterizer->format->dither_green);
12499 #endif
12500 }
12501 
12502 
12503 static CTX_INLINE void
ctx_fragment_image_rgb8_RGBA8_nearest_swap_red_green(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12504 ctx_fragment_image_rgb8_RGBA8_nearest_swap_red_green (CtxRasterizer *rasterizer,
12505                                                       float x,
12506                                                       float y,
12507                                                       void *out, int count, float dx, float dy)
12508 {
12509   ctx_fragment_image_rgb8_RGBA8_nearest (rasterizer, x, y, out, count, dx, dy);
12510   ctx_fragment_swap_red_green_u8 (out, count);
12511 }
12512 
12513 static void
ctx_fragment_image_rgb8_RGBA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12514 ctx_fragment_image_rgb8_RGBA8 (CtxRasterizer *rasterizer,
12515                                float x,
12516                                float y,
12517                                void *out, int count, float dx, float dy)
12518 {
12519   if (rasterizer->state->gstate.image_smoothing)
12520   {
12521     float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
12522     if (factor <= 0.50f)
12523     {
12524       if (rasterizer->swap_red_green)
12525         ctx_fragment_image_rgb8_RGBA8_box_swap_red_green (rasterizer, x, y, out, count, dx, dy);
12526       else
12527         ctx_fragment_image_rgb8_RGBA8_box (rasterizer, x, y, out, count, dx, dy);
12528     }
12529 #if CTX_ALWAYS_USE_NEAREST_FOR_SCALE1
12530     else if (factor > 0.99f && factor < 1.01f)
12531     {
12532       // XXX missing translate test
12533       if (rasterizer->swap_red_green)
12534         ctx_fragment_image_rgb8_RGBA8_nearest_swap_red_green (rasterizer, x, y, out, count, dx, dy);
12535       else
12536         ctx_fragment_image_rgb8_RGBA8_nearest (rasterizer, x, y, out, count, dx, dy);
12537     }
12538 #endif
12539     else
12540     {
12541       if (rasterizer->swap_red_green)
12542         ctx_fragment_image_rgb8_RGBA8_bi_swap_red_green (rasterizer, x, y, out, count, dx, dy);
12543       else
12544         ctx_fragment_image_rgb8_RGBA8_bi (rasterizer, x, y, out, count, dx, dy);
12545     }
12546   }
12547   else
12548   {
12549     if (rasterizer->swap_red_green)
12550       ctx_fragment_image_rgb8_RGBA8_nearest_swap_red_green (rasterizer, x, y, out, count, dx, dy);
12551     else
12552       ctx_fragment_image_rgb8_RGBA8_nearest (rasterizer, x, y, out, count, dx, dy);
12553   }
12554 #if CTX_DITHER
12555   {
12556   uint8_t *rgba = (uint8_t*)out;
12557   ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
12558                       rasterizer->format->dither_green);
12559   }
12560 #endif
12561 }
12562 
12563 
12564 /************** rgba8 */
12565 
12566 static void
ctx_fragment_image_rgba8_RGBA8_box(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12567 ctx_fragment_image_rgba8_RGBA8_box (CtxRasterizer *rasterizer,
12568                                     float x,
12569                                     float y,
12570                                     void *out, int count, float dx, float dy)
12571 {
12572   uint8_t *rgba = (uint8_t *) out;
12573   CtxSource *g = &rasterizer->state->gstate.source_fill;
12574   CtxBuffer *buffer = g->texture.buffer->color_managed;
12575 
12576   for (int i = 0; i < count; i ++)
12577   {
12578 
12579   int u = x;
12580   int v = y;
12581   if ( u < 0 || v < 0 ||
12582        u >= buffer->width ||
12583        v >= buffer->height)
12584     {
12585       *((uint32_t*)(rgba))= 0;
12586     }
12587   else
12588     {
12589       int bpp = 4;
12590       float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
12591           int dim = (1.0 / factor) / 2;
12592           uint64_t sum[4]={0,0,0,0};
12593           int count = 0;
12594           int width = buffer->width;
12595           int height = buffer->height;
12596           for (int ou = - dim; ou < dim; ou++)
12597           for (int ov = - dim; ov < dim; ov++)
12598           {
12599 
12600             if (v+ov >= 0 && u+ou >=0 && u + ou < width && v + ov < height)
12601             {
12602               int o = (v+ov) * width + (u + ou);
12603               uint8_t *src = (uint8_t *) buffer->data + o * bpp;
12604 
12605               for (int c = 0; c < bpp; c++)
12606                 sum[c] += src[c];
12607               count ++;
12608             }
12609           }
12610           if (count)
12611           {
12612             int recip = 65536/count;
12613             for (int c = 0; c < bpp; c++)
12614               rgba[c] = sum[c]*recip>>16;
12615           }
12616           ctx_RGBA8_associate_alpha_probably_opaque (rgba);
12617     }
12618     rgba += 4;
12619     x += dx;
12620     y += dy;
12621   }
12622 #if CTX_DITHER
12623 //ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
12624 //                    rasterizer->format->dither_green);
12625 #endif
12626 }
12627 
12628 
12629 static void
ctx_fragment_image_rgba8_RGBA8_nearest(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12630 ctx_fragment_image_rgba8_RGBA8_nearest (CtxRasterizer *rasterizer,
12631                                         float x,
12632                                         float y,
12633                                         void *out, int count, float dx, float dy)
12634 {
12635   CtxSource *g = &rasterizer->state->gstate.source_fill;
12636   CtxBuffer *buffer = g->texture.buffer;
12637   if (buffer->color_managed)
12638     buffer = buffer->color_managed;
12639   int ideltax = dx * 65536;
12640   int ideltay = dy * 65536;
12641   uint32_t *src = (uint32_t *) buffer->data;
12642   uint32_t *dst = (uint32_t*)out;
12643   int bwidth  = buffer->width;
12644   int bheight = buffer->height;
12645   x += 0.5f;
12646   y += 0.5f;
12647 
12648 #if 1
12649   if (CTX_UNLIKELY(ideltay == 0 && ideltax == 65536))
12650   {
12651     int i = 0;
12652     int u = x;
12653     int v = y;
12654     if (!(v >= 0 && v < bheight))
12655     {
12656       for (i = 0 ; i < count; i++)
12657         *dst++ = 0;
12658       return;
12659     }
12660     src += bwidth * v + u;
12661     while (count && !(u >= 0))
12662     {
12663       *dst++ = 0;
12664       src ++;
12665       u++;
12666       count--;
12667     }
12668     int limit = ctx_mini (count, bwidth - u);
12669     if (limit>0)
12670     {
12671       memcpy (dst, src, limit * 4);
12672       dst += limit;
12673       i = limit;
12674     }
12675     for (;i < count; i++)
12676       *dst++ = 0;
12677     return;
12678   }
12679 #endif
12680 
12681   {
12682     int i = 0;
12683     float u1 = x + dx * (count-1);
12684     float v1 = y + dy * (count-1);
12685     uint32_t *edst = ((uint32_t*)out)+count;
12686     for (; i < count; )
12687     {
12688       if ((u1 < 0.0f || v1 < 0.0f || u1 >= bwidth || v1 >= bheight))
12689       {
12690         *edst-- = 0;
12691         count --;
12692         u1 -= dx;
12693         v1 -= dy;
12694       }
12695       else break;
12696     }
12697 
12698 
12699     for (i = 0; i < count; i ++)
12700     {
12701       if ((x < 0.0f || y < 0.0f || x >= bwidth || y >= bheight))
12702       {
12703         *dst = 0;
12704         dst++;
12705         x += dx;
12706         y += dy;
12707       }
12708       else break;
12709     }
12710 
12711 
12712     uint32_t ix = x * 65536;
12713     uint32_t iy = y * 65536;
12714 
12715     for (; i < count; i ++)
12716     {
12717       *dst = src[(iy>>16) * bwidth + (ix>>16)];
12718       ix += ideltax;
12719       iy += ideltay;
12720       dst++;
12721     }
12722   }
12723 }
12724 
12725 static void
ctx_fragment_image_rgba8_RGBA8_bi(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12726 ctx_fragment_image_rgba8_RGBA8_bi (CtxRasterizer *rasterizer,
12727                                    float x,
12728                                    float y,
12729                                    void *out, int count, float dx, float dy)
12730 {
12731   uint8_t *rgba = (uint8_t *) out;
12732   float ox = (x-(int)(x));
12733   float oy = (y-(int)(y));
12734 
12735   CtxSource *g = &rasterizer->state->gstate.source_fill;
12736   CtxBuffer *buffer = g->texture.buffer->color_managed;
12737   const int bwidth = buffer->width;
12738   const int bheight = buffer->height;
12739   int i = 0;
12740 
12741   if (dy == 0.0f && dx > 0.0f)
12742   {
12743     if (!(y >= 0 && y < bheight))
12744     {
12745       uint32_t *dst = (uint32_t*)rgba;
12746       for (i = 0 ; i < count; i++)
12747         *dst++ = 0;
12748       return;
12749     }
12750 
12751     if ((dx > 0.99f && dx < 1.01f &&
12752          ox < 0.01 && oy < 0.01))
12753     {
12754       /* TODO: this could have been rigged up in composite_setup */
12755       ctx_fragment_image_rgba8_RGBA8_nearest (rasterizer,
12756                                    x, y, out, count, dx, dy);
12757       return;
12758     }
12759     x+=1; // XXX off by one somewhere? ,, needed for alignment with nearest
12760 
12761     uint32_t *data = ((uint32_t*)buffer->data);
12762     uint32_t yi = y * 65536;
12763     uint32_t xi = x * 65536;
12764     int xi_delta = dx * 65536;
12765 
12766     for (i= 0; i < count; i ++)
12767     {
12768       int u = xi >> 16;
12769       if ( u  < 0 || u >= bwidth-1)
12770       {
12771         *((uint32_t*)(rgba))= 0;
12772         xi += xi_delta;
12773         rgba += 4;
12774       }
12775       else
12776         break;
12777     }
12778 
12779   int loaded = -4;
12780   uint32_t s0_ga = 0, s0_rb = 0, s1_ga = 0, s1_rb = 0;
12781 
12782   int v = yi >> 16;
12783   data += bwidth * v;
12784   int dv = (yi >> 8) & 0xff;
12785 
12786   int u = xi >> 16;
12787 
12788   uint32_t *ndata = data;
12789   if (v < bheight-1) ndata += bwidth;
12790 
12791   uint32_t *src0 = data, *src1 = ndata;
12792 
12793 
12794   if (xi_delta == 65536 && u < bwidth -1)
12795   {
12796     int du = (xi >> 8) & 0xff;
12797 
12798     src0 = data + u;
12799     src1 = ndata + u;
12800     ctx_lerp_RGBA8_split (src0[0],src1[0], dv, &s1_ga, &s1_rb);
12801 
12802     int limit = bwidth-u;
12803     limit = ctx_mini(count,limit);
12804 
12805     for (; i < limit; i ++)
12806     {
12807       s0_ga = s1_ga;
12808       s0_rb = s1_rb;
12809       ctx_lerp_RGBA8_split (src0[1],src1[1], dv, &s1_ga, &s1_rb);
12810       ((uint32_t*)(&rgba[0]))[0] =
12811       ctx_lerp_RGBA8_merge (s0_ga, s0_rb, s1_ga, s1_rb, du);
12812       rgba += 4;
12813       u++;
12814       src0 ++;
12815       src1 ++;
12816     }
12817   }
12818   else
12819   {
12820 
12821   for (; i < count; i ++)
12822   {
12823     if (CTX_UNLIKELY(u >= bwidth-1))
12824     {
12825       break;
12826     }
12827     else if (CTX_LIKELY(loaded + 1 == u))
12828     {
12829       s0_ga = s1_ga;
12830       s0_rb = s1_rb;
12831       ctx_lerp_RGBA8_split (src0[1],src1[1], dv, &s1_ga, &s1_rb);
12832       src0 ++;
12833       src1 ++;
12834     }
12835     else if (loaded != u)
12836     {
12837       src0 = data + u;
12838       src1 = ndata + u;
12839       ctx_lerp_RGBA8_split (src0[0],src1[0], dv, &s0_ga, &s0_rb);
12840       ctx_lerp_RGBA8_split (src0[1],src1[1], dv, &s1_ga, &s1_rb);
12841     }
12842     loaded = u;
12843     ((uint32_t*)(&rgba[0]))[0] =
12844       ctx_lerp_RGBA8_merge (s0_ga, s0_rb, s1_ga, s1_rb, ((xi>>8)&0xff));
12845     xi += xi_delta;
12846     rgba += 4;
12847     u = xi >> 16;
12848   }
12849   }
12850 
12851   }
12852   else // //
12853   {
12854     uint32_t *data = ((uint32_t*)buffer->data);
12855     for (i= 0; i < count; i ++)
12856     {
12857       int u = x;
12858       int v = y;
12859       int ut = x + 1.5;
12860       int vt = y + 1.5;
12861       if ( ut  <= 0 || vt  <= 0 || u >= buffer->width || v >= buffer->height)
12862       {
12863         *((uint32_t*)(rgba))= 0;
12864       }
12865       else
12866         break;
12867       x += dx;
12868       y += dy;
12869       rgba += 4;
12870     }
12871 
12872   uint32_t yi = y * 65536;
12873   uint32_t xi = x * 65536;
12874 
12875   int yi_delta = dy * 65536;
12876   int xi_delta = dx * 65536;
12877 
12878   int loaded = -4;
12879   uint32_t *src00=data;
12880   uint32_t *src01=data;
12881   uint32_t *src10=data;
12882   uint32_t *src11=data;
12883 
12884   int u = xi >> 16;
12885   int v = yi >> 16;
12886   int offset = bwidth * v + u;
12887 
12888   for (; i < count; i ++)
12889   {
12890   if (CTX_UNLIKELY(
12891        u >= buffer->width ||
12892        v  <= -65536 ||
12893        u  <= -65536 ||
12894        v >= buffer->height))
12895     {
12896       break;
12897     }
12898 #if 1
12899   else if (CTX_UNLIKELY(u < 0 || v < 0)) // default to next sample down and to right
12900   {
12901       int got_prev_pix = (u >= 0);
12902       int got_prev_row = (v>=0);
12903       src11 = data  + offset + bwidth + 1;
12904       src10 = src11 - got_prev_pix;
12905       src01 = src11 - bwidth * got_prev_row;
12906       src00 = src10 - bwidth * got_prev_row;
12907   }
12908 #endif
12909 #if 1
12910   else if (loaded + 1 == offset)
12911   {
12912       src00++;
12913       src01++;
12914       src10++;
12915       src11++;
12916   }
12917 #endif
12918   else if (loaded != offset)
12919   {
12920       int next_row = ( v + 1 < bheight) * bwidth;
12921       int next_pix = (u + 1 < bwidth);
12922       src00 = data  + offset;
12923       src01 = src00 + next_pix;
12924       src10 = src00 + next_row;
12925       src11 = src01 + next_row;
12926   }
12927     loaded = offset;
12928     ((uint32_t*)(&rgba[0]))[0] = ctx_bi_RGBA8 (*src00,*src01,*src10,*src11, (xi>>8),(yi>>8)); // the argument type does the & 0xff
12929     xi += xi_delta;
12930     yi += yi_delta;
12931     rgba += 4;
12932 
12933     u = xi >> 16;
12934     v = yi >> 16;
12935     offset = bwidth * v + u;
12936   }
12937   }
12938 
12939   for (; i < count; i ++)
12940   {
12941     *((uint32_t*)(rgba))= 0;
12942     rgba += 4;
12943   }
12944 }
12945 #endif
12946 
12947 #define ctx_clampi(val,min,max) \
12948      ctx_mini (ctx_maxi ((val), (min)), (max))
12949 
ctx_yuv_to_rgba32(uint8_t y,uint8_t u,uint8_t v)12950 static inline uint32_t ctx_yuv_to_rgba32 (uint8_t y, uint8_t u, uint8_t v)
12951 {
12952   int cy  = ((y - 16) * 76309) >> 16;
12953   int cr  = (v - 128);
12954   int cb  = (u - 128);
12955   int red = cy + ((cr * 104597) >> 16);
12956   int green = cy - ((cb * 25674 + cr * 53278) >> 16);
12957   int blue = cy + ((cb * 132201) >> 16);
12958   return  ctx_clampi (red, 0, 255) |
12959           (ctx_clampi (green, 0, 255) << 8) |
12960           (ctx_clampi (blue, 0, 255) << 16) |
12961           (0xff << 24);
12962 }
12963 
12964 static void
ctx_fragment_image_yuv420_RGBA8_nearest(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)12965 ctx_fragment_image_yuv420_RGBA8_nearest (CtxRasterizer *rasterizer,
12966                                          float x,
12967                                          float y,
12968                                          void *out, int count, float dx, float dy)
12969 {
12970   uint8_t *rgba = (uint8_t *) out;
12971   CtxSource *g = &rasterizer->state->gstate.source_fill;
12972   CtxBuffer *buffer = g->texture.buffer;
12973   if (buffer->color_managed)
12974     buffer = buffer->color_managed;
12975   uint8_t *src = (uint8_t *) buffer->data;
12976   int bwidth  = buffer->width;
12977   int bheight = buffer->height;
12978   int bwidth_div_2  = bwidth/2;
12979   int bheight_div_2  = bheight/2;
12980   x += 0.5f;
12981   y += 0.5f;
12982 
12983   {
12984     int i = 0;
12985 
12986     for (; i < count; i ++)
12987     {
12988       int u = x;
12989       int v = y;
12990       if ((u < 0 || v < 0 || u >= bwidth || v >= bheight))
12991       {
12992         *((uint32_t*)(rgba))= 0;
12993       }
12994       else
12995       {
12996         break;
12997       }
12998       x += dx;
12999       y += dy;
13000       rgba += 4;
13001     }
13002 
13003     uint32_t u_offset = bheight * bwidth;
13004     uint32_t v_offset = u_offset + bheight_div_2 * bwidth_div_2;
13005 
13006     if (rasterizer->swap_red_green)
13007     {
13008       v_offset = bheight * bwidth;
13009       u_offset = v_offset + bheight_div_2 * bwidth_div_2;
13010     }
13011 
13012     // XXX this is incorrect- but fixes some bug!
13013     int ix = 65536;//x * 65536;
13014     int iy = y * 65536;
13015 
13016     int ideltax = dx * 65536;
13017     int ideltay = dy * 65536;
13018 
13019     for (; i < count; i ++)
13020     {
13021       int u = ix >> 16;
13022       int v = iy >> 16;
13023       if (u >= 0 && v >= 0 && u < bwidth && v < bheight)
13024       {
13025         uint32_t y  = v * bwidth + u;
13026         uint32_t uv = (v / 2) * bwidth_div_2 + (u / 2);
13027 
13028         *((uint32_t*)(rgba))= ctx_yuv_to_rgba32 (src[y],
13029                         //127, 127);
13030                         src[u_offset+uv], src[v_offset+uv]);
13031         //ctx_RGBA8_associate_alpha_probably_opaque (rgba);
13032 #if CTX_DITHER
13033        ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
13034                            rasterizer->format->dither_green);
13035 #endif
13036       }
13037       else
13038       {
13039         break;
13040       }
13041       ix += ideltax;
13042       iy += ideltay;
13043       rgba += 4;
13044     }
13045 
13046     for (; i < count; i++)
13047     {
13048       *((uint32_t*)(rgba))= 0;
13049       rgba += 4;
13050     }
13051   }
13052 }
13053 
13054 #if CTX_FRAGMENT_SPECIALIZE
13055 
13056 static void
ctx_fragment_image_rgba8_RGBA8_box_swap_red_green(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13057 ctx_fragment_image_rgba8_RGBA8_box_swap_red_green (CtxRasterizer *rasterizer,
13058                                     float x,
13059                                     float y,
13060                                     void *out, int count, float dx, float dy)
13061 {
13062   ctx_fragment_image_rgba8_RGBA8_box (rasterizer, x, y, out, count, dx, dy);
13063   ctx_fragment_swap_red_green_u8 (out, count);
13064 }
13065 
13066 static void
ctx_fragment_image_rgba8_RGBA8_bi_swap_red_green(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13067 ctx_fragment_image_rgba8_RGBA8_bi_swap_red_green (CtxRasterizer *rasterizer,
13068                                     float x,
13069                                     float y,
13070                                     void *out, int count, float dx, float dy)
13071 {
13072   ctx_fragment_image_rgba8_RGBA8_bi (rasterizer, x, y, out, count, dx, dy);
13073   ctx_fragment_swap_red_green_u8 (out, count);
13074 }
13075 
13076 static void
ctx_fragment_image_rgba8_RGBA8_nearest_swap_red_green(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13077 ctx_fragment_image_rgba8_RGBA8_nearest_swap_red_green (CtxRasterizer *rasterizer,
13078                                     float x,
13079                                     float y,
13080                                     void *out, int count, float dx, float dy)
13081 {
13082   ctx_fragment_image_rgba8_RGBA8_nearest (rasterizer, x, y, out, count, dx, dy);
13083   ctx_fragment_swap_red_green_u8 (out, count);
13084 }
13085 
13086 static void
ctx_fragment_image_rgba8_RGBA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13087 ctx_fragment_image_rgba8_RGBA8 (CtxRasterizer *rasterizer,
13088                                 float x,
13089                                 float y,
13090                                 void *out, int count, float dx, float dy)
13091 {
13092   if (rasterizer->state->gstate.image_smoothing)
13093   {
13094     float factor = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
13095     if (factor <= 0.50f)
13096     {
13097       if (rasterizer->swap_red_green)
13098         ctx_fragment_image_rgba8_RGBA8_box_swap_red_green (rasterizer, x, y, out, count, dx, dy);
13099       else
13100         ctx_fragment_image_rgba8_RGBA8_box (rasterizer, x, y, out, count, dx, dy);
13101     }
13102 #if CTX_ALWAYS_USE_NEAREST_FOR_SCALE1
13103     else if (factor > 0.99f && factor < 1.01f)
13104     {
13105       // XXX: also verify translate == 0 for this fast path to be valid
13106       if (rasterizer->swap_red_green)
13107         ctx_fragment_image_rgba8_RGBA8_nearest_swap_red_green (rasterizer, x, y, out, count, dx, dy);
13108       else
13109         ctx_fragment_image_rgba8_RGBA8_nearest (rasterizer, x, y, out, count, dx, dy);
13110     }
13111 #endif
13112     else
13113     {
13114       if (rasterizer->swap_red_green)
13115         ctx_fragment_image_rgba8_RGBA8_bi_swap_red_green (rasterizer, x, y, out, count, dx, dy);
13116       else
13117         ctx_fragment_image_rgba8_RGBA8_bi (rasterizer, x, y, out, count, dx, dy);
13118     }
13119   }
13120   else
13121   {
13122     if (rasterizer->swap_red_green)
13123       ctx_fragment_image_rgba8_RGBA8_nearest_swap_red_green (rasterizer, x, y, out, count, dx, dy);
13124     else
13125       ctx_fragment_image_rgba8_RGBA8_nearest (rasterizer, x, y, out, count, dx, dy);
13126   }
13127   //ctx_fragment_swap_red_green_u8 (out, count);
13128 #if CTX_DITHER
13129   uint8_t *rgba = (uint8_t*)out;
13130   ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
13131                       rasterizer->format->dither_green);
13132 #endif
13133 }
13134 #endif
13135 
13136 static void
ctx_fragment_image_gray1_RGBA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13137 ctx_fragment_image_gray1_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
13138 {
13139   uint8_t *rgba = (uint8_t *) out;
13140   CtxSource *g = &rasterizer->state->gstate.source_fill;
13141   CtxBuffer *buffer = g->texture.buffer;
13142   ctx_assert (rasterizer);
13143   ctx_assert (g);
13144   ctx_assert (buffer);
13145   for (int i = 0; i < count; i ++)
13146   {
13147   int u = x;
13148   int v = y;
13149   if ( u < 0 || v < 0 ||
13150        u >= buffer->width ||
13151        v >= buffer->height)
13152     {
13153       rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
13154     }
13155   else
13156     {
13157       uint8_t *src = (uint8_t *) buffer->data;
13158       src += v * buffer->stride + u / 8;
13159       if (*src & (1<< (u & 7) ) )
13160         {
13161           rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
13162         }
13163       else
13164         {
13165           for (int c = 0; c < 4; c++)
13166             { rgba[c] = 255;
13167             }//g->texture.rgba[c];
13168             //}
13169         }
13170     }
13171 
13172     rgba += 4;
13173     x += dx;
13174     y += dy;
13175   }
13176 }
13177 
13178 #if CTX_GRADIENTS
13179 static void
ctx_fragment_radial_gradient_RGBA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13180 ctx_fragment_radial_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
13181 {
13182   uint8_t *rgba = (uint8_t *) out;
13183   CtxSource *g = &rasterizer->state->gstate.source_fill;
13184   for (int i = 0; i <  count; i ++)
13185   {
13186     float v = (ctx_hypotf_fast (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y) -
13187               g->radial_gradient.r0) * (g->radial_gradient.rdelta);
13188 #if CTX_GRADIENT_CACHE
13189     uint32_t *rgbap = (uint32_t*)&ctx_gradient_cache_u8[ctx_grad_index(v)][0];
13190     *((uint32_t*)rgba) = *rgbap;
13191 #else
13192     ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 0.0, rgba);
13193 #endif
13194 #if CTX_DITHER
13195     ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
13196                         rasterizer->format->dither_green);
13197 #endif
13198     rgba += 4;
13199     x += dx;
13200     y += dy;
13201   }
13202 }
13203 
13204 static void
ctx_fragment_linear_gradient_RGBA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13205 ctx_fragment_linear_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
13206 {
13207 #if 0
13208   uint8_t *rgba = (uint8_t *) out;
13209   CtxSource *g = &rasterizer->state->gstate.source_fill;
13210   for (int i = 0; i <  count; i ++)
13211   {
13212   float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
13213                 g->linear_gradient.length) -
13214               g->linear_gradient.start) * (g->linear_gradient.rdelta);
13215 #if CTX_GRADIENT_CACHE
13216   uint32_t*rgbap = ((uint32_t*)(&ctx_gradient_cache_u8[ctx_grad_index(v)][0]));
13217   *((uint32_t*)rgba) = *rgbap;
13218 #else
13219   _ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 1.0, rgba);
13220 #endif
13221 #if CTX_DITHER
13222   ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
13223                       rasterizer->format->dither_green);
13224 #endif
13225     rgba += 4;
13226     x += dx;
13227     y += dy;
13228   }
13229 #else
13230   uint8_t *rgba = (uint8_t *) out;
13231 
13232   CtxSource *g = &rasterizer->state->gstate.source_fill;
13233   float u0 = x; float v0 = y;
13234   float ud = dx; float vd = dy;
13235   float linear_gradient_rdelta = g->linear_gradient.rdelta;
13236   float linear_gradient_length = g->linear_gradient.length;
13237   float linear_gradient_length_recip = 1.0f/linear_gradient_length;
13238   float linear_gradient_dx = g->linear_gradient.dx *linear_gradient_length_recip * linear_gradient_rdelta;
13239   float linear_gradient_dy = g->linear_gradient.dy *linear_gradient_length_recip * linear_gradient_rdelta;
13240   float linear_gradient_start = g->linear_gradient.start * linear_gradient_rdelta;
13241 
13242 #if CTX_DITHER
13243   int dither_red_blue = rasterizer->format->dither_red_blue;
13244   int dither_green = rasterizer->format->dither_green;
13245 #endif
13246 
13247   u0 *= linear_gradient_dx;
13248   v0 *= linear_gradient_dy;
13249   ud *= linear_gradient_dx;
13250   vd *= linear_gradient_dy;
13251 
13252 #if CTX_GRADIENT_CACHE
13253   int vv = ((u0 + v0) - linear_gradient_start) * (CTX_GRADIENT_CACHE_ELEMENTS-1) * 256;
13254   int ud_plus_vd = (ud + vd) * (CTX_GRADIENT_CACHE_ELEMENTS-1) * 256;
13255 #else
13256   float vv = ((u0 + v0) - linear_gradient_start);
13257   float ud_plus_vd = (ud + vd);
13258 #endif
13259 
13260   for (int x = 0; x < count ; x++)
13261   {
13262 #if CTX_GRADIENT_CACHE
13263   uint32_t*rgbap = ((uint32_t*)(&ctx_gradient_cache_u8[ctx_grad_index_i (vv)][0]));
13264   *((uint32_t*)rgba) = *rgbap;
13265 #else
13266   _ctx_fragment_gradient_1d_RGBA8 (rasterizer, vv, 1.0, rgba);
13267 #endif
13268 #if CTX_DITHER
13269       ctx_dither_rgba_u8 (rgba, u0, v0, dither_red_blue, dither_green);
13270 #endif
13271     rgba+= 4;
13272     vv += ud_plus_vd;
13273   }
13274 #endif
13275 }
13276 
13277 #endif
13278 
13279 static void
ctx_fragment_color_RGBA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13280 ctx_fragment_color_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
13281 {
13282   uint8_t *rgba_out = (uint8_t *) out;
13283   CtxSource *g = &rasterizer->state->gstate.source_fill;
13284   _ctx_color_get_rgba8 (rasterizer->state, &g->color, rgba_out);
13285   ctx_RGBA8_associate_alpha (rgba_out);
13286   if (rasterizer->swap_red_green)
13287   {
13288     int tmp = rgba_out[0];
13289     rgba_out[0] = rgba_out[2];
13290     rgba_out[2] = tmp;
13291   }
13292   for (int i = 1; i < count; i++, rgba_out+=4)
13293     memcpy (rgba_out + count * 4, rgba_out, 4);
13294 }
13295 #if CTX_ENABLE_FLOAT
13296 
13297 #if CTX_GRADIENTS
13298 static void
ctx_fragment_linear_gradient_RGBAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13299 ctx_fragment_linear_gradient_RGBAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
13300 {
13301   float *rgba = (float *) out;
13302   CtxSource *g = &rasterizer->state->gstate.source_fill;
13303   for (int i = 0; i < count; i++)
13304   {
13305     float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
13306                   g->linear_gradient.length) -
13307                 g->linear_gradient.start) * (g->linear_gradient.rdelta);
13308     ctx_fragment_gradient_1d_RGBAF (rasterizer, v, 1.0f, rgba);
13309     x += dx;
13310     y += dy;
13311     rgba += 4;
13312   }
13313 }
13314 
13315 static void
ctx_fragment_radial_gradient_RGBAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13316 ctx_fragment_radial_gradient_RGBAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
13317 {
13318   float *rgba = (float *) out;
13319   CtxSource *g = &rasterizer->state->gstate.source_fill;
13320   for (int i = 0; i < count; i++)
13321   {
13322   float v = ctx_hypotf (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y);
13323         v = (v - g->radial_gradient.r0) * (g->radial_gradient.rdelta);
13324   ctx_fragment_gradient_1d_RGBAF (rasterizer, v, 0.0f, rgba);
13325     x+=dx;
13326     y+=dy;
13327     rgba +=4;
13328   }
13329 }
13330 #endif
13331 
13332 
13333 static void
ctx_fragment_color_RGBAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13334 ctx_fragment_color_RGBAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
13335 {
13336   float *rgba = (float *) out;
13337   for (int i = 0; i < count; i++)
13338   {
13339     CtxSource *g = &rasterizer->state->gstate.source_fill;
13340     ctx_color_get_rgba (rasterizer->state, &g->color, rgba);
13341     for (int c = 0; c < 3; c++)
13342       rgba[c] *= rgba[3];
13343     rgba += 4;
13344   }
13345 }
13346 
ctx_fragment_image_RGBAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)13347 static void ctx_fragment_image_RGBAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
13348 {
13349   float *outf = (float *) out;
13350   uint8_t rgba[4];
13351   CtxGState *gstate = &rasterizer->state->gstate;
13352   CtxBuffer *buffer = gstate->source_fill.texture.buffer;
13353   switch (buffer->format->bpp)
13354     {
13355 #if CTX_FRAGMENT_SPECIALIZE
13356       case 1:  ctx_fragment_image_gray1_RGBA8 (rasterizer, x, y, rgba, count, dx, dy); break;
13357       case 24: ctx_fragment_image_rgb8_RGBA8 (rasterizer, x, y, rgba, count, dx, dy);  break;
13358       case 32: ctx_fragment_image_rgba8_RGBA8 (rasterizer, x, y, rgba, count, dx, dy); break;
13359 #endif
13360       default: ctx_fragment_image_RGBA8 (rasterizer, x, y, rgba, count, dx, dy);       break;
13361     }
13362   for (int c = 0; c < 4 * count; c ++) { outf[c] = ctx_u8_to_float (rgba[c]); }
13363 }
13364 
ctx_rasterizer_get_fragment_RGBAF(CtxRasterizer * rasterizer)13365 static CtxFragment ctx_rasterizer_get_fragment_RGBAF (CtxRasterizer *rasterizer)
13366 {
13367   CtxGState *gstate = &rasterizer->state->gstate;
13368   switch (gstate->source_fill.type)
13369     {
13370       case CTX_SOURCE_TEXTURE:         return ctx_fragment_image_RGBAF;
13371       case CTX_SOURCE_COLOR:           return ctx_fragment_color_RGBAF;
13372 #if CTX_GRADIENTS
13373       case CTX_SOURCE_LINEAR_GRADIENT: return ctx_fragment_linear_gradient_RGBAF;
13374       case CTX_SOURCE_RADIAL_GRADIENT: return ctx_fragment_radial_gradient_RGBAF;
13375 #endif
13376     }
13377   return ctx_fragment_color_RGBAF;
13378 }
13379 #endif
13380 
ctx_rasterizer_get_fragment_RGBA8(CtxRasterizer * rasterizer)13381 static CtxFragment ctx_rasterizer_get_fragment_RGBA8 (CtxRasterizer *rasterizer)
13382 {
13383   CtxGState *gstate = &rasterizer->state->gstate;
13384   CtxBuffer *buffer = gstate->source_fill.texture.buffer;
13385   switch (gstate->source_fill.type)
13386     {
13387       case CTX_SOURCE_TEXTURE:
13388         if (!buffer || !buffer->format)
13389           return ctx_fragment_color_RGBA8;
13390 
13391         if (buffer->format->pixel_format == CTX_FORMAT_YUV420)
13392         {
13393           return ctx_fragment_image_yuv420_RGBA8_nearest;
13394         }
13395         else
13396 #if CTX_FRAGMENT_SPECIALIZE
13397         switch (buffer->format->bpp)
13398           {
13399             case 1:  return ctx_fragment_image_gray1_RGBA8;
13400             case 24:
13401               {
13402                 if (gstate->image_smoothing)
13403                 {
13404                   float factor = ctx_matrix_get_scale (&gstate->transform);
13405                           //fprintf (stderr, "{%.3f}", factor);
13406                   if (factor < 0.5f)
13407                   {
13408                     if (rasterizer->swap_red_green)
13409                       return ctx_fragment_image_rgb8_RGBA8_box_swap_red_green;
13410                     return ctx_fragment_image_rgb8_RGBA8_box;
13411                   }
13412 #if CTX_ALWAYS_USE_NEAREST_FOR_SCALE1
13413                   else if (factor > 0.99f && factor < 1.01f)
13414                   {
13415                     if (rasterizer->swap_red_green)
13416                       return ctx_fragment_image_rgb8_RGBA8_nearest_swap_red_green;
13417                     return ctx_fragment_image_rgb8_RGBA8_nearest;
13418                   }
13419 #endif
13420                   else
13421                   {
13422                     if (rasterizer->swap_red_green)
13423                       return ctx_fragment_image_rgb8_RGBA8_bi_swap_red_green;
13424                     return ctx_fragment_image_rgb8_RGBA8_bi;
13425                   }
13426                 }
13427                 else
13428                 {
13429                   if (rasterizer->swap_red_green)
13430                     return ctx_fragment_image_rgb8_RGBA8_nearest_swap_red_green;
13431                   return ctx_fragment_image_rgb8_RGBA8_nearest;
13432                 }
13433               }
13434               break;
13435             case 32:
13436               {
13437                 if (gstate->image_smoothing)
13438                 {
13439                   float factor = ctx_matrix_get_scale (&gstate->transform);
13440                           //fprintf (stderr, "[%.3f]", factor);
13441                   if (factor < 0.5f)
13442                   {
13443                     if (rasterizer->swap_red_green)
13444                       return ctx_fragment_image_rgba8_RGBA8_box_swap_red_green;
13445                     return ctx_fragment_image_rgba8_RGBA8_box;
13446                   }
13447 #if CTX_ALWAYS_USE_NEAREST_FOR_SCALE1
13448                   else if (factor > 0.99f && factor < 1.01f)
13449                   {
13450                     if (rasterizer->swap_red_green)
13451                       return ctx_fragment_image_rgba8_RGBA8_nearest_swap_red_green;
13452                     return ctx_fragment_image_rgba8_RGBA8_nearest;
13453                   }
13454 #endif
13455                   else
13456                   {
13457                     if (rasterizer->swap_red_green)
13458                       return ctx_fragment_image_rgba8_RGBA8_bi_swap_red_green;
13459                     return ctx_fragment_image_rgba8_RGBA8_bi;
13460                   }
13461                 }
13462                 else
13463                 {
13464                   if (rasterizer->swap_red_green)
13465                     return ctx_fragment_image_rgba8_RGBA8_nearest_swap_red_green;
13466                   return ctx_fragment_image_rgba8_RGBA8_nearest;
13467                 }
13468               }
13469             default: return ctx_fragment_image_RGBA8;
13470           }
13471 #else
13472           return ctx_fragment_image_RGBA8;
13473 #endif
13474 
13475       case CTX_SOURCE_COLOR:           return ctx_fragment_color_RGBA8;
13476 #if CTX_GRADIENTS
13477       case CTX_SOURCE_LINEAR_GRADIENT: return ctx_fragment_linear_gradient_RGBA8;
13478       case CTX_SOURCE_RADIAL_GRADIENT: return ctx_fragment_radial_gradient_RGBA8;
13479 #endif
13480     }
13481   return ctx_fragment_color_RGBA8;
13482 }
13483 
13484 static void
ctx_init_uv(CtxRasterizer * rasterizer,int x0,int count,float * u0,float * v0,float * ud,float * vd)13485 ctx_init_uv (CtxRasterizer *rasterizer,
13486              int x0, int count,
13487              float *u0, float *v0, float *ud, float *vd)
13488 {
13489   CtxGState *gstate = &rasterizer->state->gstate;
13490   *u0 = x0;
13491   *v0 = rasterizer->scanline / 15;//rasterizer->aa;
13492   float u1 = *u0 + count;
13493   float v1 = *v0;
13494 
13495   _ctx_matrix_apply_transform (&gstate->source_fill.transform, u0, v0);
13496   _ctx_matrix_apply_transform (&gstate->source_fill.transform, &u1, &v1);
13497 
13498   *ud = (u1-*u0) / (count);
13499   *vd = (v1-*v0) / (count);
13500 }
13501 
13502 
13503 static void
ctx_u8_copy_normal(int components,CTX_COMPOSITE_ARGUMENTS)13504 ctx_u8_copy_normal (int components, CTX_COMPOSITE_ARGUMENTS)
13505 {
13506   if (CTX_UNLIKELY(rasterizer->fragment))
13507     {
13508       float u0 = 0; float v0 = 0;
13509       float ud = 0; float vd = 0;
13510       ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
13511       while (count--)
13512       {
13513         uint8_t cov = *coverage;
13514         if (CTX_UNLIKELY(cov == 0))
13515         {
13516           u0+=ud;
13517           v0+=vd;
13518         }
13519         else
13520         {
13521           rasterizer->fragment (rasterizer, u0, v0, src, 1, ud, vd);
13522           u0+=ud;
13523           v0+=vd;
13524           if (cov == 255)
13525           {
13526             for (int c = 0; c < components; c++)
13527               dst[c] = src[c];
13528           }
13529           else
13530           {
13531             uint8_t rcov = 255 - cov;
13532             for (int c = 0; c < components; c++)
13533               { dst[c] = (src[c]*cov + dst[c]*rcov)/255; }
13534           }
13535         }
13536         dst += components;
13537         coverage ++;
13538       }
13539       return;
13540     }
13541 
13542   while (count--)
13543   {
13544     uint8_t cov = *coverage;
13545     uint8_t rcov = 255-cov;
13546     for (int c = 0; c < components; c++)
13547       { dst[c] = (src[c]*cov+dst[c]*rcov)/255; }
13548     dst += components;
13549     coverage ++;
13550   }
13551 }
13552 
13553 static void
ctx_u8_clear_normal(int components,CTX_COMPOSITE_ARGUMENTS)13554 ctx_u8_clear_normal (int components, CTX_COMPOSITE_ARGUMENTS)
13555 {
13556   while (count--)
13557   {
13558     uint8_t cov = *coverage;
13559     for (int c = 0; c < components; c++)
13560       { dst[c] = (dst[c] * (256-cov)) >> 8; }
13561     coverage ++;
13562     dst += components;
13563   }
13564 }
13565 
13566 typedef enum {
13567   CTX_PORTER_DUFF_0,
13568   CTX_PORTER_DUFF_1,
13569   CTX_PORTER_DUFF_ALPHA,
13570   CTX_PORTER_DUFF_1_MINUS_ALPHA,
13571 } CtxPorterDuffFactor;
13572 
13573 #define  \
13574 ctx_porter_duff_factors(mode, foo, bar)\
13575 {\
13576   switch (mode)\
13577   {\
13578      case CTX_COMPOSITE_SOURCE_ATOP:\
13579         f_s = CTX_PORTER_DUFF_ALPHA;\
13580         f_d = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13581       break;\
13582      case CTX_COMPOSITE_DESTINATION_ATOP:\
13583         f_s = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13584         f_d = CTX_PORTER_DUFF_ALPHA;\
13585       break;\
13586      case CTX_COMPOSITE_DESTINATION_IN:\
13587         f_s = CTX_PORTER_DUFF_0;\
13588         f_d = CTX_PORTER_DUFF_ALPHA;\
13589       break;\
13590      case CTX_COMPOSITE_DESTINATION:\
13591         f_s = CTX_PORTER_DUFF_0;\
13592         f_d = CTX_PORTER_DUFF_1;\
13593        break;\
13594      case CTX_COMPOSITE_SOURCE_OVER:\
13595         f_s = CTX_PORTER_DUFF_1;\
13596         f_d = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13597        break;\
13598      case CTX_COMPOSITE_DESTINATION_OVER:\
13599         f_s = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13600         f_d = CTX_PORTER_DUFF_1;\
13601        break;\
13602      case CTX_COMPOSITE_XOR:\
13603         f_s = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13604         f_d = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13605        break;\
13606      case CTX_COMPOSITE_DESTINATION_OUT:\
13607         f_s = CTX_PORTER_DUFF_0;\
13608         f_d = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13609        break;\
13610      case CTX_COMPOSITE_SOURCE_OUT:\
13611         f_s = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13612         f_d = CTX_PORTER_DUFF_0;\
13613        break;\
13614      case CTX_COMPOSITE_SOURCE_IN:\
13615         f_s = CTX_PORTER_DUFF_ALPHA;\
13616         f_d = CTX_PORTER_DUFF_0;\
13617        break;\
13618      case CTX_COMPOSITE_COPY:\
13619         f_s = CTX_PORTER_DUFF_1;\
13620         f_d = CTX_PORTER_DUFF_1_MINUS_ALPHA;\
13621        break;\
13622      default:\
13623      case CTX_COMPOSITE_CLEAR:\
13624         f_s = CTX_PORTER_DUFF_0;\
13625         f_d = CTX_PORTER_DUFF_0;\
13626        break;\
13627   }\
13628 }
13629 
13630 static void
ctx_u8_source_over_normal_color(int components,CtxRasterizer * rasterizer,uint8_t * __restrict__ dst,uint8_t * __restrict__ src,int x0,uint8_t * __restrict__ coverage,int count)13631 ctx_u8_source_over_normal_color (int components,
13632                                  CtxRasterizer         *rasterizer,
13633                                  uint8_t * __restrict__ dst,
13634                                  uint8_t * __restrict__ src,
13635                                  int                    x0,
13636                                  uint8_t * __restrict__ coverage,
13637                                  int                    count)
13638 {
13639   uint8_t tsrc[5];
13640   *((uint32_t*)tsrc) = *((uint32_t*)src);
13641 
13642   while (count--)
13643   {
13644     for (int c = 0; c < components; c++)
13645       //dst[c] =  ((tsrc[c] * *coverage)>>8) + (dst[c] * (((65536)-(tsrc[components-1] * *coverage)))>>16);
13646       dst[c] =  ((((tsrc[c] * *coverage)) + (dst[c] * (((255)-(((255+(tsrc[components-1] * *coverage))>>8))))))>>8);
13647     coverage ++;
13648     dst+=components;
13649   }
13650 }
13651 
13652 static void
ctx_u8_source_copy_normal_color(int components,CTX_COMPOSITE_ARGUMENTS)13653 ctx_u8_source_copy_normal_color (int components, CTX_COMPOSITE_ARGUMENTS)
13654 {
13655   while (count--)
13656   {
13657     for (int c = 0; c < components; c++)
13658       dst[c] =  ctx_lerp_u8(dst[c],src[c],coverage[0]);
13659     coverage ++;
13660     dst+=components;
13661   }
13662 }
13663 
13664 static inline void
ctx_RGBA8_source_over_normal_buf(CTX_COMPOSITE_ARGUMENTS,uint8_t * tsrc)13665 ctx_RGBA8_source_over_normal_buf (CTX_COMPOSITE_ARGUMENTS, uint8_t *tsrc)
13666 {
13667   while (count--)
13668   {
13669      uint32_t si_ga = ((*((uint32_t*)tsrc)) & 0xff00ff00) >> 8;
13670      uint32_t si_rb = (*((uint32_t*)tsrc)) & 0x00ff00ff;
13671 //   uint32_t di_ga = ((*((uint32_t*)dst)) & 0xff00ff00) >> 8;
13672 //   uint32_t di_rb = (*((uint32_t*)dst)) & 0x00ff00ff;
13673      uint32_t si_a  = si_ga >> 16;
13674      uint32_t cov = *coverage;
13675      uint32_t racov = (255-((255+si_a*cov)>>8));
13676      *((uint32_t*)(dst)) =
13677 
13678      (((si_rb*cov+0xff00ff+(((*((uint32_t*)(dst)))&0x00ff00ff)*racov))>>8)&0x00ff00ff)|
13679      ((si_ga*cov+0xff00ff+((((*((uint32_t*)(dst)))&0xff00ff00)>>8)*racov))&0xff00ff00);
13680 
13681      coverage ++;
13682      tsrc += 4;
13683      dst  += 4;
13684   }
13685 }
13686 
13687 static inline void
ctx_RGBA8_source_over_normal_full_cov_buf(CTX_COMPOSITE_ARGUMENTS,uint8_t * tsrc)13688 ctx_RGBA8_source_over_normal_full_cov_buf (CTX_COMPOSITE_ARGUMENTS, uint8_t *tsrc)
13689 {
13690   while (count--)
13691   {
13692      uint32_t si_ga = ((*((uint32_t*)tsrc)) & 0xff00ff00) >> 8;
13693      uint32_t si_rb = (*((uint32_t*)tsrc)) & 0x00ff00ff;
13694      uint32_t si_a  = si_ga >> 16;
13695      uint32_t racov = (255-si_a);
13696      *((uint32_t*)(dst)) =
13697      (((si_rb*255+0xff00ff+(((*((uint32_t*)(dst)))&0x00ff00ff)*racov))>>8)&0x00ff00ff)|
13698      ((si_ga*255+0xff00ff+((((*((uint32_t*)(dst)))&0xff00ff00)>>8)*racov))&0xff00ff00);
13699      tsrc += 4;
13700      dst  += 4;
13701   }
13702 }
13703 
13704 static void
ctx_RGBA8_source_copy_normal_buf(CTX_COMPOSITE_ARGUMENTS,uint8_t * tsrc)13705 ctx_RGBA8_source_copy_normal_buf (CTX_COMPOSITE_ARGUMENTS, uint8_t *tsrc)
13706 {
13707   while (count--)
13708   {
13709     ((uint32_t*)dst)[0]=ctx_lerp_RGBA8 (((uint32_t*)dst)[0],
13710                                         ((uint32_t*)tsrc)[0], coverage[0]);
13711     coverage ++;
13712     tsrc += 4;
13713     dst  += 4;
13714   }
13715 }
13716 
13717 static void
ctx_RGBA8_source_over_normal_fragment(CTX_COMPOSITE_ARGUMENTS)13718 ctx_RGBA8_source_over_normal_fragment (CTX_COMPOSITE_ARGUMENTS)
13719 {
13720   float u0 = 0; float v0 = 0;
13721   float ud = 0; float vd = 0;
13722   ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
13723   uint8_t _tsrc[4 * (count)];
13724   rasterizer->fragment (rasterizer, u0, v0, &_tsrc[0], count, ud, vd);
13725   ctx_RGBA8_source_over_normal_buf (rasterizer,
13726                        dst, src, x0, coverage, count, &_tsrc[0]);
13727 }
13728 
13729 static inline void
ctx_RGBA8_source_over_normal_full_cov_fragment(CTX_COMPOSITE_ARGUMENTS)13730 ctx_RGBA8_source_over_normal_full_cov_fragment (CTX_COMPOSITE_ARGUMENTS)
13731 {
13732   float u0 = 0; float v0 = 0;
13733   float ud = 0; float vd = 0;
13734   ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
13735   uint8_t _tsrc[4 * (count)];
13736   rasterizer->fragment (rasterizer, u0, v0, &_tsrc[0], count, ud, vd);
13737   ctx_RGBA8_source_over_normal_full_cov_buf (rasterizer,
13738                        dst, src, x0, coverage, count, &_tsrc[0]);
13739 }
13740 
13741 static void
ctx_RGBA8_source_copy_normal_fragment(CTX_COMPOSITE_ARGUMENTS)13742 ctx_RGBA8_source_copy_normal_fragment (CTX_COMPOSITE_ARGUMENTS)
13743 {
13744   float u0 = 0; float v0 = 0;
13745   float ud = 0; float vd = 0;
13746   ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
13747   uint8_t _tsrc[4 * (count)];
13748   rasterizer->fragment (rasterizer, u0, v0, &_tsrc[0], count, ud, vd);
13749   ctx_RGBA8_source_copy_normal_buf (rasterizer,
13750                        dst, src, x0, coverage, count, &_tsrc[0]);
13751 }
13752 
13753 
13754 static void
ctx_RGBA8_source_over_normal_color(CTX_COMPOSITE_ARGUMENTS)13755 ctx_RGBA8_source_over_normal_color (CTX_COMPOSITE_ARGUMENTS)
13756 {
13757 #if CTX_REFERENCE
13758   ctx_u8_source_over_normal_color (4, rasterizer, dst, src, x0, coverage, count);
13759 #else
13760   uint32_t si_ga = ((uint32_t*)rasterizer->color)[1];
13761   uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
13762   uint32_t si_a  = si_ga >> 16;
13763 
13764   while (count--)
13765   {
13766      uint32_t cov   = *coverage++;
13767      uint32_t rcov  = (((255+si_a * cov)>>8))^255;
13768      uint32_t di    = *((uint32_t*)dst);
13769      uint32_t di_ga = ((di & 0xff00ff00) >> 8);
13770      uint32_t di_rb = (di & 0x00ff00ff);
13771      *((uint32_t*)(dst)) =
13772      (((si_rb * cov + 0xff00ff + di_rb * rcov) & 0xff00ff00) >> 8)  |
13773       ((si_ga * cov + 0xff00ff + di_ga * rcov) & 0xff00ff00);
13774      dst+=4;
13775   }
13776 #endif
13777 }
13778 
13779 static void
ctx_RGBA8_source_copy_normal_color(CTX_COMPOSITE_ARGUMENTS)13780 ctx_RGBA8_source_copy_normal_color (CTX_COMPOSITE_ARGUMENTS)
13781 {
13782 #if CTX_REFERENCE
13783   ctx_u8_source_copy_normal_color (4, rasterizer, dst, src, x0, coverage, count);
13784 #else
13785   uint32_t si_ga = ((uint32_t*)rasterizer->color)[1];
13786   uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
13787 
13788   while (count--)
13789   {
13790      uint32_t cov   = *coverage++;
13791      uint32_t di    = *((uint32_t*)dst);
13792      uint32_t di_ga = (di & 0xff00ff00);
13793      uint32_t di_rb = (di & 0x00ff00ff);
13794 
13795      uint32_t d_rb  = si_rb - di_rb;
13796      uint32_t d_ga  = si_ga - (di_ga>>8);
13797 
13798      *((uint32_t*)(dst)) =
13799 
13800      (((di_rb + ((d_rb * cov)>>8)) & 0x00ff00ff))  |
13801       ((di_ga + ((d_ga * cov)      & 0xff00ff00)));
13802      dst +=4;
13803   }
13804 #endif
13805 }
13806 
13807 static void
ctx_RGBA8_clear_normal(CTX_COMPOSITE_ARGUMENTS)13808 ctx_RGBA8_clear_normal (CTX_COMPOSITE_ARGUMENTS)
13809 {
13810   ctx_u8_clear_normal (4, rasterizer, dst, src, x0, coverage, count);
13811 }
13812 
13813 static void
ctx_u8_blend_normal(int components,uint8_t * __restrict__ dst,uint8_t * src,uint8_t * blended,int count)13814 ctx_u8_blend_normal (int components, uint8_t * __restrict__ dst, uint8_t *src, uint8_t *blended, int count)
13815 {
13816   for (int j = 0; j < count; j++)
13817   {
13818   switch (components)
13819   {
13820      case 3:
13821        ((uint8_t*)(blended))[2] = ((uint8_t*)(src))[2];
13822        *((uint16_t*)(blended)) = *((uint16_t*)(src));
13823        break;
13824      case 2:
13825        *((uint16_t*)(blended)) = *((uint16_t*)(src));
13826        break;
13827      case 5:
13828        *((uint32_t*)(blended)) = *((uint32_t*)(src));
13829        ((uint8_t*)(blended))[4] = ((uint8_t*)(src))[4];
13830        break;
13831      case 4:
13832        *((uint32_t*)(blended)) = *((uint32_t*)(src));
13833        break;
13834      default:
13835        {
13836         for (int i = 0; i<components;i++)
13837            blended[i] = src[i];
13838        }
13839        break;
13840   }
13841     blended+=components;
13842     src+=components;
13843   }
13844 }
13845 
13846 /* branchless 8bit add that maxes out at 255 */
ctx_sadd8(uint8_t a,uint8_t b)13847 static inline uint8_t ctx_sadd8(uint8_t a, uint8_t b)
13848 {
13849   uint16_t s = (uint16_t)a+b;
13850   return -(s>>8) | (uint8_t)s;
13851 }
13852 
13853 #if CTX_BLENDING_AND_COMPOSITING
13854 
13855 #define ctx_u8_blend_define(name, CODE) \
13856 static void \
13857 ctx_u8_blend_##name (int components, uint8_t * __restrict__ dst, uint8_t *src, uint8_t *blended, int count)\
13858 {\
13859   for (int j = 0; j < count; j++) { \
13860   uint8_t *s=src; uint8_t b[components];\
13861   ctx_u8_deassociate_alpha (components, dst, b);\
13862     CODE;\
13863   blended[components-1] = src[components-1];\
13864   ctx_u8_associate_alpha (components, blended);\
13865   src += components;\
13866   dst += components;\
13867   blended += components;\
13868   }\
13869 }
13870 
13871 #define ctx_u8_blend_define_seperable(name, CODE) \
13872         ctx_u8_blend_define(name, for (int c = 0; c < components-1; c++) { CODE ;}) \
13873 
13874 ctx_u8_blend_define_seperable(multiply,     blended[c] = (b[c] * s[c])/255;)
13875 ctx_u8_blend_define_seperable(screen,       blended[c] = s[c] + b[c] - (s[c] * b[c])/255;)
13876 ctx_u8_blend_define_seperable(overlay,      blended[c] = b[c] < 127 ? (s[c] * b[c])/255 :
13877                                                          s[c] + b[c] - (s[c] * b[c])/255;)
13878 ctx_u8_blend_define_seperable(darken,       blended[c] = ctx_mini (b[c], s[c]))
13879 ctx_u8_blend_define_seperable(lighten,      blended[c] = ctx_maxi (b[c], s[c]))
13880 ctx_u8_blend_define_seperable(color_dodge,  blended[c] = b[c] == 0 ? 0 :
13881                                      s[c] == 255 ? 255 : ctx_mini(255, (255 * b[c]) / (255-s[c])))
13882 ctx_u8_blend_define_seperable(color_burn,   blended[c] = b[c] == 1 ? 1 :
13883                                      s[c] == 0 ? 0 : 255 - ctx_mini(255, (255*(255 - b[c])) / s[c]))
13884 ctx_u8_blend_define_seperable(hard_light,   blended[c] = s[c] < 127 ? (b[c] * s[c])/255 :
13885                                                           b[c] + s[c] - (b[c] * s[c])/255;)
13886 ctx_u8_blend_define_seperable(difference,   blended[c] = (b[c] - s[c]))
13887 ctx_u8_blend_define_seperable(divide,       blended[c] = s[c]?(255 * b[c]) / s[c]:0)
13888 ctx_u8_blend_define_seperable(addition,     blended[c] = ctx_sadd8 (s[c], b[c]))
13889 ctx_u8_blend_define_seperable(subtract,     blended[c] = ctx_maxi(0, s[c]-b[c]))
13890 ctx_u8_blend_define_seperable(exclusion,    blended[c] = b[c] + s[c] - 2 * (b[c] * s[c]/255))
13891 ctx_u8_blend_define_seperable(soft_light,
13892   if (s[c] <= 255/2)
13893   {
13894     blended[c] = b[c] - (255 - 2 * s[c]) * b[c] * (255 - b[c]) / (255 * 255);
13895   }
13896   else
13897   {
13898     int d;
13899     if (b[c] <= 255/4)
13900       d = (((16 * b[c] - 12 * 255)/255 * b[c] + 4 * 255) * b[c])/255;
13901     else
13902       d = ctx_sqrtf(b[c]/255.0) * 255.4;
13903     blended[c] = (b[c] + (2 * s[c] - 255) * (d - b[c]))/255;
13904   }
13905 )
13906 
ctx_int_get_max(int components,int * c)13907 static int ctx_int_get_max (int components, int *c)
13908 {
13909   int max = 0;
13910   for (int i = 0; i < components - 1; i ++)
13911   {
13912     if (c[i] > max) max = c[i];
13913   }
13914   return max;
13915 }
13916 
ctx_int_get_min(int components,int * c)13917 static int ctx_int_get_min (int components, int *c)
13918 {
13919   int min = 400;
13920   for (int i = 0; i < components - 1; i ++)
13921   {
13922     if (c[i] < min) min = c[i];
13923   }
13924   return min;
13925 }
13926 
ctx_int_get_lum(int components,int * c)13927 static int ctx_int_get_lum (int components, int *c)
13928 {
13929   switch (components)
13930   {
13931     case 3:
13932     case 4:
13933             return CTX_CSS_RGB_TO_LUMINANCE(c);
13934     case 1:
13935     case 2:
13936             return c[0];
13937             break;
13938     default:
13939        {
13940          int sum = 0;
13941          for (int i = 0; i < components - 1; i ++)
13942          {
13943            sum += c[i];
13944          }
13945          return sum / (components - 1);
13946        }
13947             break;
13948   }
13949 }
13950 
ctx_u8_get_lum(int components,uint8_t * c)13951 static int ctx_u8_get_lum (int components, uint8_t *c)
13952 {
13953   switch (components)
13954   {
13955     case 3:
13956     case 4:
13957             return CTX_CSS_RGB_TO_LUMINANCE(c);
13958     case 1:
13959     case 2:
13960             return c[0];
13961             break;
13962     default:
13963        {
13964          int sum = 0;
13965          for (int i = 0; i < components - 1; i ++)
13966          {
13967            sum += c[i];
13968          }
13969          return sum / (components - 1);
13970        }
13971             break;
13972   }
13973 }
ctx_u8_get_sat(int components,uint8_t * c)13974 static int ctx_u8_get_sat (int components, uint8_t *c)
13975 {
13976   switch (components)
13977   {
13978     case 3:
13979     case 4:
13980             { int r = c[0];
13981               int g = c[1];
13982               int b = c[2];
13983               return ctx_maxi(r, ctx_maxi(g,b)) - ctx_mini(r,ctx_mini(g,b));
13984             }
13985             break;
13986     case 1:
13987     case 2:
13988             return 0.0;
13989             break;
13990     default:
13991        {
13992          int min = 1000;
13993          int max = -1000;
13994          for (int i = 0; i < components - 1; i ++)
13995          {
13996            if (c[i] < min) min = c[i];
13997            if (c[i] > max) max = c[i];
13998          }
13999          return max-min;
14000        }
14001        break;
14002   }
14003 }
14004 
ctx_u8_set_lum(int components,uint8_t * c,uint8_t lum)14005 static void ctx_u8_set_lum (int components, uint8_t *c, uint8_t lum)
14006 {
14007   int d = lum - ctx_u8_get_lum (components, c);
14008   int tc[components];
14009   for (int i = 0; i < components - 1; i++)
14010   {
14011     tc[i] = c[i] + d;
14012   }
14013 
14014   int l = ctx_int_get_lum (components, tc);
14015   int n = ctx_int_get_min (components, tc);
14016   int x = ctx_int_get_max (components, tc);
14017 
14018   if (n < 0 && l!=n)
14019   {
14020     for (int i = 0; i < components - 1; i++)
14021       tc[i] = l + (((tc[i] - l) * l) / (l-n));
14022   }
14023 
14024   if (x > 255 && x!=l)
14025   {
14026     for (int i = 0; i < components - 1; i++)
14027       tc[i] = l + (((tc[i] - l) * (255 - l)) / (x-l));
14028   }
14029   for (int i = 0; i < components - 1; i++)
14030     c[i] = tc[i];
14031 }
14032 
ctx_u8_set_sat(int components,uint8_t * c,uint8_t sat)14033 static void ctx_u8_set_sat (int components, uint8_t *c, uint8_t sat)
14034 {
14035   int max = 0, mid = 1, min = 2;
14036 
14037   if (c[min] > c[mid]){int t = min; min = mid; mid = t;}
14038   if (c[mid] > c[max]){int t = mid; mid = max; max = t;}
14039   if (c[min] > c[mid]){int t = min; min = mid; mid = t;}
14040 
14041   if (c[max] > c[min])
14042   {
14043     c[mid] = ((c[mid]-c[min]) * sat) / (c[max] - c[min]);
14044     c[max] = sat;
14045   }
14046   else
14047   {
14048     c[mid] = c[max] = 0;
14049   }
14050   c[min] = 0;
14051 }
14052 
14053 ctx_u8_blend_define(color,
14054   for (int i = 0; i < components; i++)
14055     blended[i] = s[i];
14056   ctx_u8_set_lum(components, blended, ctx_u8_get_lum (components, s));
14057 )
14058 
14059 ctx_u8_blend_define(hue,
14060   int in_sat = ctx_u8_get_sat(components, b);
14061   int in_lum = ctx_u8_get_lum(components, b);
14062   for (int i = 0; i < components; i++)
14063     blended[i] = s[i];
14064   ctx_u8_set_sat(components, blended, in_sat);
14065   ctx_u8_set_lum(components, blended, in_lum);
14066 )
14067 
14068 ctx_u8_blend_define(saturation,
14069   int in_sat = ctx_u8_get_sat(components, s);
14070   int in_lum = ctx_u8_get_lum(components, b);
14071   for (int i = 0; i < components; i++)
14072     blended[i] = b[i];
14073   ctx_u8_set_sat(components, blended, in_sat);
14074   ctx_u8_set_lum(components, blended, in_lum);
14075 )
14076 
14077 ctx_u8_blend_define(luminosity,
14078   int in_lum = ctx_u8_get_lum(components, s);
14079   for (int i = 0; i < components; i++)
14080     blended[i] = b[i];
14081   ctx_u8_set_lum(components, blended, in_lum);
14082 )
14083 #endif
14084 
14085 CTX_INLINE static void
ctx_u8_blend(int components,CtxBlend blend,uint8_t * __restrict__ dst,uint8_t * src,uint8_t * blended,int count)14086 ctx_u8_blend (int components, CtxBlend blend, uint8_t * __restrict__ dst, uint8_t *src, uint8_t *blended, int count)
14087 {
14088 #if CTX_BLENDING_AND_COMPOSITING
14089   switch (blend)
14090   {
14091     case CTX_BLEND_NORMAL:      ctx_u8_blend_normal      (components, dst, src, blended, count); break;
14092     case CTX_BLEND_MULTIPLY:    ctx_u8_blend_multiply    (components, dst, src, blended, count); break;
14093     case CTX_BLEND_SCREEN:      ctx_u8_blend_screen      (components, dst, src, blended, count); break;
14094     case CTX_BLEND_OVERLAY:     ctx_u8_blend_overlay     (components, dst, src, blended, count); break;
14095     case CTX_BLEND_DARKEN:      ctx_u8_blend_darken      (components, dst, src, blended, count); break;
14096     case CTX_BLEND_LIGHTEN:     ctx_u8_blend_lighten     (components, dst, src, blended, count); break;
14097     case CTX_BLEND_COLOR_DODGE: ctx_u8_blend_color_dodge (components, dst, src, blended, count); break;
14098     case CTX_BLEND_COLOR_BURN:  ctx_u8_blend_color_burn  (components, dst, src, blended, count); break;
14099     case CTX_BLEND_HARD_LIGHT:  ctx_u8_blend_hard_light  (components, dst, src, blended, count); break;
14100     case CTX_BLEND_SOFT_LIGHT:  ctx_u8_blend_soft_light  (components, dst, src, blended, count); break;
14101     case CTX_BLEND_DIFFERENCE:  ctx_u8_blend_difference  (components, dst, src, blended, count); break;
14102     case CTX_BLEND_EXCLUSION:   ctx_u8_blend_exclusion   (components, dst, src, blended, count); break;
14103     case CTX_BLEND_COLOR:       ctx_u8_blend_color       (components, dst, src, blended, count); break;
14104     case CTX_BLEND_HUE:         ctx_u8_blend_hue         (components, dst, src, blended, count); break;
14105     case CTX_BLEND_SATURATION:  ctx_u8_blend_saturation  (components, dst, src, blended, count); break;
14106     case CTX_BLEND_LUMINOSITY:  ctx_u8_blend_luminosity  (components, dst, src, blended, count); break;
14107     case CTX_BLEND_ADDITION:    ctx_u8_blend_addition    (components, dst, src, blended, count); break;
14108     case CTX_BLEND_DIVIDE:      ctx_u8_blend_divide      (components, dst, src, blended, count); break;
14109     case CTX_BLEND_SUBTRACT:    ctx_u8_blend_subtract    (components, dst, src, blended, count); break;
14110   }
14111 #else
14112   switch (blend)
14113   {
14114     default:                    ctx_u8_blend_normal      (components, dst, src, blended, count); break;
14115   }
14116 
14117 #endif
14118 }
14119 
14120 CTX_INLINE static void
__ctx_u8_porter_duff(CtxRasterizer * rasterizer,int components,uint8_t * dst,uint8_t * src,int x0,uint8_t * __restrict__ coverage,int count,CtxCompositingMode compositing_mode,CtxFragment fragment,CtxBlend blend)14121 __ctx_u8_porter_duff (CtxRasterizer         *rasterizer,
14122                      int                    components,
14123                      uint8_t *              dst,
14124                      uint8_t *              src,
14125                      int                    x0,
14126                      uint8_t * __restrict__ coverage,
14127                      int                    count,
14128                      CtxCompositingMode     compositing_mode,
14129                      CtxFragment            fragment,
14130                      CtxBlend               blend)
14131 {
14132   CtxPorterDuffFactor f_s, f_d;
14133   ctx_porter_duff_factors (compositing_mode, &f_s, &f_d);
14134   CtxGState *gstate = &rasterizer->state->gstate;
14135   uint8_t global_alpha_u8 = gstate->global_alpha_u8;
14136   uint8_t tsrc[components * count];
14137   int src_step = 0;
14138 
14139   if (gstate->source_fill.type == CTX_SOURCE_COLOR)
14140   {
14141     src = &tsrc[0];
14142     fragment (rasterizer, 0, 0, src, 1, 0, 0);
14143     if (blend != CTX_BLEND_NORMAL)
14144       ctx_u8_blend (components, blend, dst, src, src, 1);
14145   }
14146   else
14147   {
14148     float u0 = 0; float v0 = 0;
14149     float ud = 0; float vd = 0;
14150     src = &tsrc[0];
14151 
14152     ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
14153     fragment (rasterizer, u0, v0, src, count, ud, vd);
14154     if (blend != CTX_BLEND_NORMAL)
14155       ctx_u8_blend (components, blend, dst, src, src, count);
14156     src_step = components;
14157   }
14158 
14159   while (count--)
14160   {
14161     uint32_t cov = *coverage;
14162 
14163     if (CTX_UNLIKELY(global_alpha_u8 != 255))
14164       cov = (cov * global_alpha_u8 + 255) >> 8;
14165 
14166     uint8_t csrc[components];
14167     for (int c = 0; c < components; c++)
14168       csrc[c] = (src[c] * cov + 255) >> 8;
14169 
14170     for (int c = 0; c < components; c++)
14171     {
14172       uint32_t res = 0;
14173 #if 1
14174       switch (f_s)
14175       {
14176         case CTX_PORTER_DUFF_0:             break;
14177         case CTX_PORTER_DUFF_1:             res += (csrc[c] ); break;
14178         case CTX_PORTER_DUFF_ALPHA:         res += (csrc[c] * dst[components-1] + 255) >> 8; break;
14179         case CTX_PORTER_DUFF_1_MINUS_ALPHA: res += (csrc[c] * (256-dst[components-1])) >> 8; break;
14180       }
14181       switch (f_d)
14182       {
14183         case CTX_PORTER_DUFF_0: break;
14184         case CTX_PORTER_DUFF_1:             res += dst[c]; break;
14185         case CTX_PORTER_DUFF_ALPHA:         res += (dst[c] * csrc[components-1] + 255) >> 8; break;
14186         case CTX_PORTER_DUFF_1_MINUS_ALPHA: res += (dst[c] * (256-csrc[components-1])) >> 8; break;
14187       }
14188 #else
14189       switch (f_s)
14190       {
14191         case CTX_PORTER_DUFF_0:             break;
14192         case CTX_PORTER_DUFF_1:             res += (csrc[c] ); break;
14193         case CTX_PORTER_DUFF_ALPHA:         res += (csrc[c] * dst[components-1])/255; break;
14194         case CTX_PORTER_DUFF_1_MINUS_ALPHA: res += (csrc[c] * (255-dst[components-1]))/255; break;
14195       }
14196       switch (f_d)
14197       {
14198         case CTX_PORTER_DUFF_0: break;
14199         case CTX_PORTER_DUFF_1:             res += dst[c]; break;
14200         case CTX_PORTER_DUFF_ALPHA:         res += (dst[c] * csrc[components-1])/255; break;
14201         case CTX_PORTER_DUFF_1_MINUS_ALPHA: res += (dst[c] * (255-csrc[components-1]))/255; break;
14202       }
14203 #endif
14204       dst[c] = res;
14205     }
14206     coverage ++;
14207     src+=src_step;
14208     dst+=components;
14209   }
14210 }
14211 
14212 CTX_INLINE static void
_ctx_u8_porter_duff(CtxRasterizer * rasterizer,int components,uint8_t * dst,uint8_t * __restrict__ src,int x0,uint8_t * coverage,int count,CtxCompositingMode compositing_mode,CtxFragment fragment,CtxBlend blend)14213 _ctx_u8_porter_duff (CtxRasterizer         *rasterizer,
14214                      int                    components,
14215                      uint8_t *              dst,
14216                      uint8_t * __restrict__ src,
14217                      int                    x0,
14218                      uint8_t *              coverage,
14219                      int                    count,
14220                      CtxCompositingMode     compositing_mode,
14221                      CtxFragment            fragment,
14222                      CtxBlend               blend)
14223 {
14224   __ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count, compositing_mode, fragment, blend);
14225 }
14226 
14227 #define _ctx_u8_porter_duffs(comp_format, components, source, fragment, blend) \
14228    switch (rasterizer->state->gstate.compositing_mode) \
14229    { \
14230      case CTX_COMPOSITE_SOURCE_ATOP: \
14231       _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count, \
14232         CTX_COMPOSITE_SOURCE_ATOP, fragment, blend);\
14233       break;\
14234      case CTX_COMPOSITE_DESTINATION_ATOP:\
14235       _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14236         CTX_COMPOSITE_DESTINATION_ATOP, fragment, blend);\
14237       break;\
14238      case CTX_COMPOSITE_DESTINATION_IN:\
14239       _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14240         CTX_COMPOSITE_DESTINATION_IN, fragment, blend);\
14241       break;\
14242      case CTX_COMPOSITE_DESTINATION:\
14243       _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14244         CTX_COMPOSITE_DESTINATION, fragment, blend);\
14245        break;\
14246      case CTX_COMPOSITE_SOURCE_OVER:\
14247       _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14248         CTX_COMPOSITE_SOURCE_OVER, fragment, blend);\
14249        break;\
14250      case CTX_COMPOSITE_DESTINATION_OVER:\
14251       _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14252         CTX_COMPOSITE_DESTINATION_OVER, fragment, blend);\
14253        break;\
14254      case CTX_COMPOSITE_XOR:\
14255       _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14256         CTX_COMPOSITE_XOR, fragment, blend);\
14257        break;\
14258      case CTX_COMPOSITE_DESTINATION_OUT:\
14259        _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14260         CTX_COMPOSITE_DESTINATION_OUT, fragment, blend);\
14261        break;\
14262      case CTX_COMPOSITE_SOURCE_OUT:\
14263        _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14264         CTX_COMPOSITE_SOURCE_OUT, fragment, blend);\
14265        break;\
14266      case CTX_COMPOSITE_SOURCE_IN:\
14267        _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14268         CTX_COMPOSITE_SOURCE_IN, fragment, blend);\
14269        break;\
14270      case CTX_COMPOSITE_COPY:\
14271        _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14272         CTX_COMPOSITE_COPY, fragment, blend);\
14273        break;\
14274      case CTX_COMPOSITE_CLEAR:\
14275        _ctx_u8_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14276         CTX_COMPOSITE_CLEAR, fragment, blend);\
14277        break;\
14278    }
14279 
14280 /* generating one function per compositing_mode would be slightly more efficient,
14281  * but on embedded targets leads to slightly more code bloat,
14282  * here we trade off a slight amount of performance
14283  */
14284 #define ctx_u8_porter_duff(comp_format, components, source, fragment, blend) \
14285 static void \
14286 ctx_##comp_format##_porter_duff_##source (CTX_COMPOSITE_ARGUMENTS) \
14287 { \
14288   _ctx_u8_porter_duffs(comp_format, components, source, fragment, blend);\
14289 }
14290 
14291 ctx_u8_porter_duff(RGBA8, 4,generic, rasterizer->fragment, rasterizer->state->gstate.blend_mode)
14292 //ctx_u8_porter_duff(comp_name, components,color_##blend_name,  NULL, blend_mode)
14293 
14294 static void
ctx_RGBA8_nop(CTX_COMPOSITE_ARGUMENTS)14295 ctx_RGBA8_nop (CTX_COMPOSITE_ARGUMENTS)
14296 {
14297 }
14298 
14299 
14300 static void
ctx_setup_RGBA8(CtxRasterizer * rasterizer)14301 ctx_setup_RGBA8 (CtxRasterizer *rasterizer)
14302 {
14303   CtxGState *gstate = &rasterizer->state->gstate;
14304   int components       = 4;
14305   rasterizer->fragment = ctx_rasterizer_get_fragment_RGBA8 (rasterizer);
14306   rasterizer->comp_op  = ctx_RGBA8_porter_duff_generic;
14307   rasterizer->comp = CTX_COV_PATH_FALLBACK;
14308 
14309   int blend_mode       = gstate->blend_mode;
14310   int compositing_mode = gstate->compositing_mode;
14311 
14312   if (gstate->source_fill.type == CTX_SOURCE_COLOR)
14313     {
14314       ctx_fragment_color_RGBA8 (rasterizer, 0,0, rasterizer->color, 1, 0,0);
14315       if (gstate->global_alpha_u8 != 255)
14316       {
14317         for (int c = 0; c < 4; c ++)
14318           rasterizer->color[c] = (rasterizer->color[c] * gstate->global_alpha_u8 + 255)>>8;
14319       }
14320       uint32_t src_pix    = ((uint32_t*)rasterizer->color)[0];
14321       uint32_t si_ga      = (src_pix & 0xff00ff00) >> 8;
14322       uint32_t si_rb      = src_pix & 0x00ff00ff;
14323       uint32_t si_ga_full = si_ga * 255;
14324       uint32_t si_rb_full = si_rb * 255;
14325 //      uint32_t si_a       = si_ga >> 16;
14326 
14327       ((uint32_t*)rasterizer->color)[1] = si_ga;
14328       ((uint32_t*)rasterizer->color)[2] = si_rb;
14329       ((uint32_t*)rasterizer->color)[3] = si_ga_full;
14330       ((uint32_t*)rasterizer->color)[4] = si_rb_full;
14331 
14332       if (blend_mode == CTX_BLEND_NORMAL &&
14333            compositing_mode == CTX_COMPOSITE_COPY)
14334       {
14335         rasterizer->comp_op = ctx_RGBA8_source_copy_normal_color;
14336         rasterizer->comp = CTX_COV_PATH_COPY;
14337       }
14338       else if (blend_mode == CTX_BLEND_NORMAL &&
14339           compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
14340      {
14341        if (rasterizer->color[components-1] == 255)
14342        {
14343         rasterizer->comp_op = ctx_RGBA8_source_copy_normal_color;
14344         rasterizer->comp = CTX_COV_PATH_COPY;
14345        }
14346        else
14347        {
14348         rasterizer->comp_op = ctx_RGBA8_source_over_normal_color;
14349         rasterizer->comp = CTX_COV_PATH_OVER;
14350        }
14351      }
14352      else if (compositing_mode == CTX_COMPOSITE_CLEAR)
14353      {
14354        rasterizer->comp_op = ctx_RGBA8_clear_normal;
14355      }
14356   }
14357   else if (blend_mode == CTX_BLEND_NORMAL &&
14358            compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
14359   {
14360      rasterizer->comp_op = ctx_RGBA8_source_over_normal_fragment;
14361      rasterizer->comp = CTX_COV_PATH_OVER_FRAGMENT;
14362   }
14363   else if (blend_mode == CTX_BLEND_NORMAL &&
14364            compositing_mode == CTX_COMPOSITE_COPY)
14365   {
14366      rasterizer->comp_op = ctx_RGBA8_source_copy_normal_fragment;
14367      rasterizer->comp = CTX_COV_PATH_COPY_FRAGMENT;
14368   }
14369 }
14370 
14371 static void
ctx_composite_convert(CTX_COMPOSITE_ARGUMENTS)14372 ctx_composite_convert (CTX_COMPOSITE_ARGUMENTS)
14373 {
14374   uint8_t pixels[count * rasterizer->format->ebpp];
14375   rasterizer->format->to_comp (rasterizer, x0, dst, &pixels[0], count);
14376   rasterizer->comp_op (rasterizer, &pixels[0], rasterizer->color, x0, coverage, count);
14377   rasterizer->format->from_comp (rasterizer, x0, &pixels[0], dst, count);
14378 }
14379 
14380 #if CTX_ENABLE_FLOAT
14381 static void
ctx_float_copy_normal(int components,CTX_COMPOSITE_ARGUMENTS)14382 ctx_float_copy_normal (int components, CTX_COMPOSITE_ARGUMENTS)
14383 {
14384   float *dstf = (float*)dst;
14385   float *srcf = (float*)src;
14386   float u0 = 0; float v0 = 0;
14387   float ud = 0; float vd = 0;
14388 
14389   ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
14390 
14391   while (count--)
14392   {
14393     uint8_t cov = *coverage;
14394     float covf = ctx_u8_to_float (cov);
14395     for (int c = 0; c < components; c++)
14396       dstf[c] = dstf[c]*(1.0-covf) + srcf[c]*covf;
14397     dstf += components;
14398     coverage ++;
14399   }
14400 }
14401 
14402 static void
ctx_float_clear_normal(int components,CTX_COMPOSITE_ARGUMENTS)14403 ctx_float_clear_normal (int components, CTX_COMPOSITE_ARGUMENTS)
14404 {
14405   float *dstf = (float*)dst;
14406   while (count--)
14407   {
14408 #if 0
14409     uint8_t cov = *coverage;
14410     if (cov == 0)
14411     {
14412     }
14413     else if (cov == 255)
14414     {
14415 #endif
14416       switch (components)
14417       {
14418         case 2:
14419           ((uint64_t*)(dst))[0] = 0;
14420           break;
14421         case 4:
14422           ((uint64_t*)(dst))[0] = 0;
14423           ((uint64_t*)(dst))[1] = 0;
14424           break;
14425         default:
14426           for (int c = 0; c < components; c++)
14427             dstf[c] = 0.0f;
14428       }
14429 #if 0
14430     }
14431     else
14432     {
14433       float ralpha = 1.0 - ctx_u8_to_float (cov);
14434       for (int c = 0; c < components; c++)
14435         { dstf[c] = (dstf[c] * ralpha); }
14436     }
14437     coverage ++;
14438 #endif
14439     dstf += components;
14440   }
14441 }
14442 
14443 
14444 static inline void
ctx_float_source_over_normal_color(int components,CTX_COMPOSITE_ARGUMENTS)14445 ctx_float_source_over_normal_color (int components, CTX_COMPOSITE_ARGUMENTS)
14446 {
14447   float *dstf = (float*)dst;
14448   float *srcf = (float*)src;
14449   while (count--)
14450   {
14451     uint8_t cov = *coverage;
14452     float fcov = ctx_u8_to_float (cov);
14453     float ralpha = 1.0f - fcov * srcf[components-1];
14454     for (int c = 0; c < components-1; c++)
14455       dstf[c] = (srcf[c]*fcov + dstf[c] * ralpha);
14456     coverage ++;
14457     dstf+= components;
14458   }
14459 }
14460 
14461 static void
ctx_float_source_copy_normal_color(int components,CTX_COMPOSITE_ARGUMENTS)14462 ctx_float_source_copy_normal_color (int components, CTX_COMPOSITE_ARGUMENTS)
14463 {
14464   float *dstf = (float*)dst;
14465   float *srcf = (float*)src;
14466 
14467   while (count--)
14468   {
14469     uint8_t cov = *coverage;
14470     float fcov = ctx_u8_to_float (cov);
14471     float ralpha = 1.0f - fcov;
14472     for (int c = 0; c < components-1; c++)
14473       dstf[c] = (srcf[c]*fcov + dstf[c] * ralpha);
14474     coverage ++;
14475     dstf+= components;
14476   }
14477 }
14478 
14479 inline static void
ctx_float_blend_normal(int components,float * dst,float * src,float * blended)14480 ctx_float_blend_normal (int components, float *dst, float *src, float *blended)
14481 {
14482   float a = src[components-1];
14483   for (int c = 0; c <  components - 1; c++)
14484     blended[c] = src[c] * a;
14485   blended[components-1]=a;
14486 }
14487 
ctx_float_get_max(int components,float * c)14488 static float ctx_float_get_max (int components, float *c)
14489 {
14490   float max = -1000.0f;
14491   for (int i = 0; i < components - 1; i ++)
14492   {
14493     if (c[i] > max) max = c[i];
14494   }
14495   return max;
14496 }
14497 
ctx_float_get_min(int components,float * c)14498 static float ctx_float_get_min (int components, float *c)
14499 {
14500   float min = 400.0;
14501   for (int i = 0; i < components - 1; i ++)
14502   {
14503     if (c[i] < min) min = c[i];
14504   }
14505   return min;
14506 }
14507 
ctx_float_get_lum(int components,float * c)14508 static float ctx_float_get_lum (int components, float *c)
14509 {
14510   switch (components)
14511   {
14512     case 3:
14513     case 4:
14514             return CTX_CSS_RGB_TO_LUMINANCE(c);
14515     case 1:
14516     case 2:
14517             return c[0];
14518             break;
14519     default:
14520        {
14521          float sum = 0;
14522          for (int i = 0; i < components - 1; i ++)
14523          {
14524            sum += c[i];
14525          }
14526          return sum / (components - 1);
14527        }
14528   }
14529 }
14530 
ctx_float_get_sat(int components,float * c)14531 static float ctx_float_get_sat (int components, float *c)
14532 {
14533   switch (components)
14534   {
14535     case 3:
14536     case 4:
14537             { float r = c[0];
14538               float g = c[1];
14539               float b = c[2];
14540               return ctx_maxf(r, ctx_maxf(g,b)) - ctx_minf(r,ctx_minf(g,b));
14541             }
14542             break;
14543     case 1:
14544     case 2: return 0.0;
14545             break;
14546     default:
14547        {
14548          float min = 1000;
14549          float max = -1000;
14550          for (int i = 0; i < components - 1; i ++)
14551          {
14552            if (c[i] < min) min = c[i];
14553            if (c[i] > max) max = c[i];
14554          }
14555          return max-min;
14556        }
14557   }
14558 }
14559 
ctx_float_set_lum(int components,float * c,float lum)14560 static void ctx_float_set_lum (int components, float *c, float lum)
14561 {
14562   float d = lum - ctx_float_get_lum (components, c);
14563   float tc[components];
14564   for (int i = 0; i < components - 1; i++)
14565   {
14566     tc[i] = c[i] + d;
14567   }
14568 
14569   float l = ctx_float_get_lum (components, tc);
14570   float n = ctx_float_get_min (components, tc);
14571   float x = ctx_float_get_max (components, tc);
14572 
14573   if (n < 0.0f && l != n)
14574   {
14575     for (int i = 0; i < components - 1; i++)
14576       tc[i] = l + (((tc[i] - l) * l) / (l-n));
14577   }
14578 
14579   if (x > 1.0f && x != l)
14580   {
14581     for (int i = 0; i < components - 1; i++)
14582       tc[i] = l + (((tc[i] - l) * (1.0f - l)) / (x-l));
14583   }
14584   for (int i = 0; i < components - 1; i++)
14585     c[i] = tc[i];
14586 }
14587 
ctx_float_set_sat(int components,float * c,float sat)14588 static void ctx_float_set_sat (int components, float *c, float sat)
14589 {
14590   int max = 0, mid = 1, min = 2;
14591 
14592   if (c[min] > c[mid]){int t = min; min = mid; mid = t;}
14593   if (c[mid] > c[max]){int t = mid; mid = max; max = t;}
14594   if (c[min] > c[mid]){int t = min; min = mid; mid = t;}
14595 
14596   if (c[max] > c[min])
14597   {
14598     c[mid] = ((c[mid]-c[min]) * sat) / (c[max] - c[min]);
14599     c[max] = sat;
14600   }
14601   else
14602   {
14603     c[mid] = c[max] = 0.0f;
14604   }
14605   c[min] = 0.0f;
14606 
14607 }
14608 
14609 #define ctx_float_blend_define(name, CODE) \
14610 static void \
14611 ctx_float_blend_##name (int components, float * __restrict__ dst, float *src, float *blended)\
14612 {\
14613   float *s = src; float b[components];\
14614   ctx_float_deassociate_alpha (components, dst, b);\
14615     CODE;\
14616   blended[components-1] = s[components-1];\
14617   ctx_float_associate_alpha (components, blended);\
14618 }
14619 
14620 #define ctx_float_blend_define_seperable(name, CODE) \
14621         ctx_float_blend_define(name, for (int c = 0; c < components-1; c++) { CODE ;}) \
14622 
14623 ctx_float_blend_define_seperable(multiply,    blended[c] = (b[c] * s[c]);)
14624 ctx_float_blend_define_seperable(screen,      blended[c] = b[c] + s[c] - (b[c] * s[c]);)
14625 ctx_float_blend_define_seperable(overlay,     blended[c] = b[c] < 0.5f ? (s[c] * b[c]) :
14626                                                           s[c] + b[c] - (s[c] * b[c]);)
14627 ctx_float_blend_define_seperable(darken,      blended[c] = ctx_minf (b[c], s[c]))
14628 ctx_float_blend_define_seperable(lighten,     blended[c] = ctx_maxf (b[c], s[c]))
14629 ctx_float_blend_define_seperable(color_dodge, blended[c] = (b[c] == 0.0f) ? 0.0f :
14630                                      s[c] == 1.0f ? 1.0f : ctx_minf(1.0f, (b[c]) / (1.0f-s[c])))
14631 ctx_float_blend_define_seperable(color_burn,  blended[c] = (b[c] == 1.0f) ? 1.0f :
14632                                      s[c] == 0.0f ? 0.0f : 1.0f - ctx_minf(1.0f, ((1.0f - b[c])) / s[c]))
14633 ctx_float_blend_define_seperable(hard_light,  blended[c] = s[c] < 0.f ? (b[c] * s[c]) :
14634                                                           b[c] + s[c] - (b[c] * s[c]);)
14635 ctx_float_blend_define_seperable(difference,  blended[c] = (b[c] - s[c]))
14636 
14637 ctx_float_blend_define_seperable(divide,      blended[c] = s[c]?(b[c]) / s[c]:0.0f)
14638 ctx_float_blend_define_seperable(addition,    blended[c] = s[c]+b[c])
14639 ctx_float_blend_define_seperable(subtract,    blended[c] = s[c]-b[c])
14640 
14641 ctx_float_blend_define_seperable(exclusion,   blended[c] = b[c] + s[c] - 2.0f * b[c] * s[c])
14642 ctx_float_blend_define_seperable(soft_light,
14643   if (s[c] <= 0.5f)
14644   {
14645     blended[c] = b[c] - (1.0f - 2.0f * s[c]) * b[c] * (1.0f - b[c]);
14646   }
14647   else
14648   {
14649     int d;
14650     if (b[c] <= 255/4)
14651       d = (((16 * b[c] - 12.0f) * b[c] + 4.0f) * b[c]);
14652     else
14653       d = ctx_sqrtf(b[c]);
14654     blended[c] = (b[c] + (2.0f * s[c] - 1.0f) * (d - b[c]));
14655   }
14656 )
14657 
14658 
14659 ctx_float_blend_define(color,
14660   for (int i = 0; i < components; i++)
14661     blended[i] = s[i];
14662   ctx_float_set_lum(components, blended, ctx_float_get_lum (components, s));
14663 )
14664 
14665 ctx_float_blend_define(hue,
14666   float in_sat = ctx_float_get_sat(components, b);
14667   float in_lum = ctx_float_get_lum(components, b);
14668   for (int i = 0; i < components; i++)
14669     blended[i] = s[i];
14670   ctx_float_set_sat(components, blended, in_sat);
14671   ctx_float_set_lum(components, blended, in_lum);
14672 )
14673 
14674 ctx_float_blend_define(saturation,
14675   float in_sat = ctx_float_get_sat(components, s);
14676   float in_lum = ctx_float_get_lum(components, b);
14677   for (int i = 0; i < components; i++)
14678     blended[i] = b[i];
14679   ctx_float_set_sat(components, blended, in_sat);
14680   ctx_float_set_lum(components, blended, in_lum);
14681 )
14682 
14683 ctx_float_blend_define(luminosity,
14684   float in_lum = ctx_float_get_lum(components, s);
14685   for (int i = 0; i < components; i++)
14686     blended[i] = b[i];
14687   ctx_float_set_lum(components, blended, in_lum);
14688 )
14689 
14690 inline static void
ctx_float_blend(int components,CtxBlend blend,float * __restrict__ dst,float * src,float * blended)14691 ctx_float_blend (int components, CtxBlend blend, float * __restrict__ dst, float *src, float *blended)
14692 {
14693   switch (blend)
14694   {
14695     case CTX_BLEND_NORMAL:      ctx_float_blend_normal      (components, dst, src, blended); break;
14696     case CTX_BLEND_MULTIPLY:    ctx_float_blend_multiply    (components, dst, src, blended); break;
14697     case CTX_BLEND_SCREEN:      ctx_float_blend_screen      (components, dst, src, blended); break;
14698     case CTX_BLEND_OVERLAY:     ctx_float_blend_overlay     (components, dst, src, blended); break;
14699     case CTX_BLEND_DARKEN:      ctx_float_blend_darken      (components, dst, src, blended); break;
14700     case CTX_BLEND_LIGHTEN:     ctx_float_blend_lighten     (components, dst, src, blended); break;
14701     case CTX_BLEND_COLOR_DODGE: ctx_float_blend_color_dodge (components, dst, src, blended); break;
14702     case CTX_BLEND_COLOR_BURN:  ctx_float_blend_color_burn  (components, dst, src, blended); break;
14703     case CTX_BLEND_HARD_LIGHT:  ctx_float_blend_hard_light  (components, dst, src, blended); break;
14704     case CTX_BLEND_SOFT_LIGHT:  ctx_float_blend_soft_light  (components, dst, src, blended); break;
14705     case CTX_BLEND_DIFFERENCE:  ctx_float_blend_difference  (components, dst, src, blended); break;
14706     case CTX_BLEND_EXCLUSION:   ctx_float_blend_exclusion   (components, dst, src, blended); break;
14707     case CTX_BLEND_COLOR:       ctx_float_blend_color       (components, dst, src, blended); break;
14708     case CTX_BLEND_HUE:         ctx_float_blend_hue         (components, dst, src, blended); break;
14709     case CTX_BLEND_SATURATION:  ctx_float_blend_saturation  (components, dst, src, blended); break;
14710     case CTX_BLEND_LUMINOSITY:  ctx_float_blend_luminosity  (components, dst, src, blended); break;
14711     case CTX_BLEND_ADDITION:    ctx_float_blend_addition    (components, dst, src, blended); break;
14712     case CTX_BLEND_SUBTRACT:    ctx_float_blend_subtract    (components, dst, src, blended); break;
14713     case CTX_BLEND_DIVIDE:      ctx_float_blend_divide      (components, dst, src, blended); break;
14714   }
14715 }
14716 
14717 /* this is the grunt working function, when inlined code-path elimination makes
14718  * it produce efficient code.
14719  */
14720 CTX_INLINE static void
ctx_float_porter_duff(CtxRasterizer * rasterizer,int components,uint8_t * __restrict__ dst,uint8_t * __restrict__ src,int x0,uint8_t * __restrict__ coverage,int count,CtxCompositingMode compositing_mode,CtxFragment fragment,CtxBlend blend)14721 ctx_float_porter_duff (CtxRasterizer         *rasterizer,
14722                        int                    components,
14723                        uint8_t * __restrict__ dst,
14724                        uint8_t * __restrict__ src,
14725                        int                    x0,
14726                        uint8_t * __restrict__ coverage,
14727                        int                    count,
14728                        CtxCompositingMode     compositing_mode,
14729                        CtxFragment            fragment,
14730                        CtxBlend               blend)
14731 {
14732   float *dstf = (float*)dst;
14733 
14734   CtxPorterDuffFactor f_s, f_d;
14735   ctx_porter_duff_factors (compositing_mode, &f_s, &f_d);
14736   uint8_t global_alpha_u8 = rasterizer->state->gstate.global_alpha_u8;
14737   float   global_alpha_f = rasterizer->state->gstate.global_alpha_f;
14738 
14739   {
14740     float tsrc[components];
14741     float u0 = 0; float v0 = 0;
14742     float ud = 0; float vd = 0;
14743 
14744     ctx_init_uv (rasterizer, x0, count, &u0, &v0, &ud, &vd);
14745 
14746     while (count--)
14747     {
14748       uint8_t cov = *coverage;
14749 #if 1
14750       if (
14751         CTX_UNLIKELY((compositing_mode == CTX_COMPOSITE_DESTINATION_OVER && dst[components-1] == 1.0f)||
14752         (cov == 0 && (compositing_mode == CTX_COMPOSITE_SOURCE_OVER ||
14753         compositing_mode == CTX_COMPOSITE_XOR               ||
14754         compositing_mode == CTX_COMPOSITE_DESTINATION_OUT   ||
14755         compositing_mode == CTX_COMPOSITE_SOURCE_ATOP
14756         ))))
14757       {
14758         u0 += ud;
14759         v0 += vd;
14760         coverage ++;
14761         dstf+=components;
14762         continue;
14763       }
14764 #endif
14765 
14766       fragment (rasterizer, u0, v0, tsrc, 1, ud, vd);
14767       if (blend != CTX_BLEND_NORMAL)
14768         ctx_float_blend (components, blend, dstf, tsrc, tsrc);
14769       u0 += ud;
14770       v0 += vd;
14771       float covf = ctx_u8_to_float (cov);
14772 
14773       if (global_alpha_u8 != 255)
14774         covf = covf * global_alpha_f;
14775 
14776       if (covf != 1.0f)
14777       {
14778         for (int c = 0; c < components; c++)
14779           tsrc[c] *= covf;
14780       }
14781 
14782       for (int c = 0; c < components; c++)
14783       {
14784         float res;
14785         /* these switches and this whole function is written to be
14786          * inlined when compiled when the enum values passed in are
14787          * constants.
14788          */
14789         switch (f_s)
14790         {
14791           case CTX_PORTER_DUFF_0: res = 0.0f; break;
14792           case CTX_PORTER_DUFF_1:             res = (tsrc[c]); break;
14793           case CTX_PORTER_DUFF_ALPHA:         res = (tsrc[c] *       dstf[components-1]); break;
14794           case CTX_PORTER_DUFF_1_MINUS_ALPHA: res = (tsrc[c] * (1.0f-dstf[components-1])); break;
14795         }
14796         switch (f_d)
14797         {
14798           case CTX_PORTER_DUFF_0: dstf[c] = res; break;
14799           case CTX_PORTER_DUFF_1:             dstf[c] = res + (dstf[c]); break;
14800           case CTX_PORTER_DUFF_ALPHA:         dstf[c] = res + (dstf[c] *       tsrc[components-1]); break;
14801           case CTX_PORTER_DUFF_1_MINUS_ALPHA: dstf[c] = res + (dstf[c] * (1.0f-tsrc[components-1])); break;
14802         }
14803       }
14804       coverage ++;
14805       dstf     +=components;
14806     }
14807   }
14808 }
14809 
14810 /* generating one function per compositing_mode would be slightly more efficient,
14811  * but on embedded targets leads to slightly more code bloat,
14812  * here we trade off a slight amount of performance
14813  */
14814 #define ctx_float_porter_duff(compformat, components, source, fragment, blend) \
14815 static void \
14816 ctx_##compformat##_porter_duff_##source (CTX_COMPOSITE_ARGUMENTS) \
14817 { \
14818    switch (rasterizer->state->gstate.compositing_mode) \
14819    { \
14820      case CTX_COMPOSITE_SOURCE_ATOP: \
14821       ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count, \
14822         CTX_COMPOSITE_SOURCE_ATOP, fragment, blend);\
14823       break;\
14824      case CTX_COMPOSITE_DESTINATION_ATOP:\
14825       ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14826         CTX_COMPOSITE_DESTINATION_ATOP, fragment, blend);\
14827       break;\
14828      case CTX_COMPOSITE_DESTINATION_IN:\
14829       ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14830         CTX_COMPOSITE_DESTINATION_IN, fragment, blend);\
14831       break;\
14832      case CTX_COMPOSITE_DESTINATION:\
14833       ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14834         CTX_COMPOSITE_DESTINATION, fragment, blend);\
14835        break;\
14836      case CTX_COMPOSITE_SOURCE_OVER:\
14837       ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14838         CTX_COMPOSITE_SOURCE_OVER, fragment, blend);\
14839        break;\
14840      case CTX_COMPOSITE_DESTINATION_OVER:\
14841       ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14842         CTX_COMPOSITE_DESTINATION_OVER, fragment, blend);\
14843        break;\
14844      case CTX_COMPOSITE_XOR:\
14845       ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14846         CTX_COMPOSITE_XOR, fragment, blend);\
14847        break;\
14848      case CTX_COMPOSITE_DESTINATION_OUT:\
14849        ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14850         CTX_COMPOSITE_DESTINATION_OUT, fragment, blend);\
14851        break;\
14852      case CTX_COMPOSITE_SOURCE_OUT:\
14853        ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14854         CTX_COMPOSITE_SOURCE_OUT, fragment, blend);\
14855        break;\
14856      case CTX_COMPOSITE_SOURCE_IN:\
14857        ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14858         CTX_COMPOSITE_SOURCE_IN, fragment, blend);\
14859        break;\
14860      case CTX_COMPOSITE_COPY:\
14861        ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14862         CTX_COMPOSITE_COPY, fragment, blend);\
14863        break;\
14864      case CTX_COMPOSITE_CLEAR:\
14865        ctx_float_porter_duff (rasterizer, components, dst, src, x0, coverage, count,\
14866         CTX_COMPOSITE_CLEAR, fragment, blend);\
14867        break;\
14868    }\
14869 }
14870 #endif
14871 
14872 #if CTX_ENABLE_RGBAF
14873 
14874 ctx_float_porter_duff(RGBAF, 4,color,   rasterizer->fragment, rasterizer->state->gstate.blend_mode)
14875 ctx_float_porter_duff(RGBAF, 4,generic, rasterizer->fragment, rasterizer->state->gstate.blend_mode)
14876 
14877 #if CTX_INLINED_NORMAL
14878 #if CTX_GRADIENTS
14879 ctx_float_porter_duff(RGBAF, 4,linear_gradient, ctx_fragment_linear_gradient_RGBAF, rasterizer->state->gstate.blend_mode)
14880 ctx_float_porter_duff(RGBAF, 4,radial_gradient, ctx_fragment_radial_gradient_RGBAF, rasterizer->state->gstate.blend_mode)
14881 #endif
14882 ctx_float_porter_duff(RGBAF, 4,image,           ctx_fragment_image_RGBAF,           rasterizer->state->gstate.blend_mode)
14883 
14884 
14885 #if CTX_GRADIENTS
14886 #define ctx_float_porter_duff_blend(comp_name, components, blend_mode, blend_name)\
14887 ctx_float_porter_duff(comp_name, components,color_##blend_name,            rasterizer->fragment,                               blend_mode)\
14888 ctx_float_porter_duff(comp_name, components,generic_##blend_name,          rasterizer->fragment,               blend_mode)\
14889 ctx_float_porter_duff(comp_name, components,linear_gradient_##blend_name,  ctx_fragment_linear_gradient_RGBA8, blend_mode)\
14890 ctx_float_porter_duff(comp_name, components,radial_gradient_##blend_name,  ctx_fragment_radial_gradient_RGBA8, blend_mode)\
14891 ctx_float_porter_duff(comp_name, components,image_##blend_name,            ctx_fragment_image_RGBAF,           blend_mode)
14892 #else
14893 #define ctx_float_porter_duff_blend(comp_name, components, blend_mode, blend_name)\
14894 ctx_float_porter_duff(comp_name, components,color_##blend_name,            rasterizer->fragment,                               blend_mode)\
14895 ctx_float_porter_duff(comp_name, components,generic_##blend_name,          rasterizer->fragment,               blend_mode)\
14896 ctx_float_porter_duff(comp_name, components,image_##blend_name,            ctx_fragment_image_RGBAF,           blend_mode)
14897 #endif
14898 
14899 ctx_float_porter_duff_blend(RGBAF, 4, CTX_BLEND_NORMAL, normal)
14900 
14901 
14902 static void
ctx_RGBAF_copy_normal(CTX_COMPOSITE_ARGUMENTS)14903 ctx_RGBAF_copy_normal (CTX_COMPOSITE_ARGUMENTS)
14904 {
14905   ctx_float_copy_normal (4, rasterizer, dst, src, x0, coverage, count);
14906 }
14907 
14908 static void
ctx_RGBAF_clear_normal(CTX_COMPOSITE_ARGUMENTS)14909 ctx_RGBAF_clear_normal (CTX_COMPOSITE_ARGUMENTS)
14910 {
14911   ctx_float_clear_normal (4, rasterizer, dst, src, x0, coverage, count);
14912 }
14913 
14914 #if 0
14915 static void
14916 ctx_RGBAF_source_over_normal_color (CTX_COMPOSITE_ARGUMENTS)
14917 {
14918   ctx_float_source_over_normal_color (4, rasterizer, dst, rasterizer->color, x0, coverage, count);
14919 }
14920 #endif
14921 #endif
14922 
14923 static void
ctx_setup_RGBAF(CtxRasterizer * rasterizer)14924 ctx_setup_RGBAF (CtxRasterizer *rasterizer)
14925 {
14926   CtxGState *gstate = &rasterizer->state->gstate;
14927   int components = 4;
14928   rasterizer->fragment = ctx_rasterizer_get_fragment_RGBAF (rasterizer);
14929   rasterizer->comp = CTX_COV_PATH_FALLBACK;
14930 #if 1
14931   if (gstate->source_fill.type == CTX_SOURCE_COLOR)
14932     {
14933       rasterizer->comp_op = ctx_RGBAF_porter_duff_color;
14934       ctx_fragment_color_RGBAF (rasterizer, 0,0, rasterizer->color, 1, 0,0);
14935       if (gstate->global_alpha_u8 != 255)
14936         for (int c = 0; c < components; c ++)
14937           ((float*)rasterizer->color)[c] *= gstate->global_alpha_f;
14938     }
14939   else
14940 #endif
14941   {
14942     rasterizer->comp_op = ctx_RGBAF_porter_duff_generic;
14943   }
14944 
14945 #if CTX_INLINED_NORMAL
14946   if (gstate->compositing_mode == CTX_COMPOSITE_CLEAR)
14947     rasterizer->comp_op = ctx_RGBAF_clear_normal;
14948   else
14949     switch (gstate->blend_mode)
14950     {
14951       case CTX_BLEND_NORMAL:
14952         if (gstate->compositing_mode == CTX_COMPOSITE_COPY)
14953         {
14954           rasterizer->comp_op = ctx_RGBAF_copy_normal;
14955         }
14956         else if (gstate->global_alpha_u8 == 0)
14957         {
14958           rasterizer->comp_op = ctx_RGBA8_nop;
14959         }
14960         else
14961         switch (gstate->source_fill.type)
14962         {
14963           case CTX_SOURCE_COLOR:
14964             //if (gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
14965             //{
14966             //  rasterizer->comp_op = ctx_RGBAF_source_over_normal_color;
14967            // }
14968            // else
14969             {
14970               rasterizer->comp_op = ctx_RGBAF_porter_duff_color_normal;
14971             }
14972             break;
14973 #if CTX_GRADIENTS
14974           case CTX_SOURCE_LINEAR_GRADIENT:
14975             rasterizer->comp_op = ctx_RGBAF_porter_duff_linear_gradient_normal;
14976             break;
14977           case CTX_SOURCE_RADIAL_GRADIENT:
14978             rasterizer->comp_op = ctx_RGBAF_porter_duff_radial_gradient_normal;
14979             break;
14980 #endif
14981           case CTX_SOURCE_TEXTURE:
14982             rasterizer->comp_op = ctx_RGBAF_porter_duff_image_normal;
14983             break;
14984           default:
14985             rasterizer->comp_op = ctx_RGBAF_porter_duff_generic_normal;
14986             break;
14987         }
14988         break;
14989       default:
14990         switch (gstate->source_fill.type)
14991         {
14992           case CTX_SOURCE_COLOR:
14993             rasterizer->comp_op = ctx_RGBAF_porter_duff_color;
14994             //rasterizer->fragment = NULL;
14995             break;
14996 #if CTX_GRADIENTS
14997           case CTX_SOURCE_LINEAR_GRADIENT:
14998             rasterizer->comp_op = ctx_RGBAF_porter_duff_linear_gradient;
14999             break;
15000           case CTX_SOURCE_RADIAL_GRADIENT:
15001             rasterizer->comp_op = ctx_RGBAF_porter_duff_radial_gradient;
15002             break;
15003 #endif
15004           case CTX_SOURCE_TEXTURE:
15005             rasterizer->comp_op = ctx_RGBAF_porter_duff_image;
15006             break;
15007           default:
15008             rasterizer->comp_op = ctx_RGBAF_porter_duff_generic;
15009             break;
15010         }
15011         break;
15012     }
15013 #endif
15014 }
15015 
15016 #endif
15017 #if CTX_ENABLE_GRAYAF
15018 
15019 #if CTX_GRADIENTS
15020 static void
ctx_fragment_linear_gradient_GRAYAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)15021 ctx_fragment_linear_gradient_GRAYAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
15022 {
15023   float rgba[4];
15024   CtxSource *g = &rasterizer->state->gstate.source_fill;
15025   for (int i = 0 ; i < count; i++)
15026   {
15027   float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
15028                 g->linear_gradient.length) -
15029               g->linear_gradient.start) * (g->linear_gradient.rdelta);
15030   ctx_fragment_gradient_1d_RGBAF (rasterizer, v, 1.0, rgba);
15031   ((float*)out)[0] = ctx_float_color_rgb_to_gray (rasterizer->state, rgba);
15032   ((float*)out)[1] = rgba[3];
15033      out = ((float*)(out)) + 2;
15034      x += dx;
15035      y += dy;
15036   }
15037 }
15038 
15039 static void
ctx_fragment_radial_gradient_GRAYAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)15040 ctx_fragment_radial_gradient_GRAYAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
15041 {
15042   float rgba[4];
15043   CtxSource *g = &rasterizer->state->gstate.source_fill;
15044   for (int i = 0; i < count; i ++)
15045   {
15046   float v = 0.0f;
15047   if ((g->radial_gradient.r1-g->radial_gradient.r0) > 0.0f)
15048     {
15049       v = ctx_hypotf (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y);
15050       v = (v - g->radial_gradient.r0) / (g->radial_gradient.rdelta);
15051     }
15052   ctx_fragment_gradient_1d_RGBAF (rasterizer, v, 0.0, rgba);
15053   ((float*)out)[0] = ctx_float_color_rgb_to_gray (rasterizer->state, rgba);
15054   ((float*)out)[1] = rgba[3];
15055      out = ((float*)(out)) + 2;
15056      x += dx;
15057      y += dy;
15058   }
15059 }
15060 #endif
15061 
15062 static void
ctx_fragment_color_GRAYAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)15063 ctx_fragment_color_GRAYAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
15064 {
15065   CtxSource *g = &rasterizer->state->gstate.source_fill;
15066   for (int i = 0; i < count; i++)
15067   {
15068      ctx_color_get_graya (rasterizer->state, &g->color, (float*)out);
15069      out = ((float*)(out)) + 2;
15070      x += dx;
15071      y += dy;
15072   }
15073 }
15074 
ctx_fragment_image_GRAYAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)15075 static void ctx_fragment_image_GRAYAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
15076 {
15077   uint8_t rgba[4];
15078   float rgbaf[4];
15079   CtxGState *gstate = &rasterizer->state->gstate;
15080   CtxBuffer *buffer = gstate->source_fill.texture.buffer;
15081   switch (buffer->format->bpp)
15082     {
15083 #if CTX_FRAGMENT_SPECIALIZE
15084       case 1:  ctx_fragment_image_gray1_RGBA8 (rasterizer, x, y, rgba, count, dx, dy); break;
15085       case 24: ctx_fragment_image_rgb8_RGBA8 (rasterizer, x, y, rgba, count, dx, dy);  break;
15086       case 32: ctx_fragment_image_rgba8_RGBA8 (rasterizer, x, y, rgba, count, dx, dy); break;
15087 #endif
15088       default: ctx_fragment_image_RGBA8 (rasterizer, x, y, rgba, count, dx, dy);       break;
15089     }
15090   for (int c = 0; c < 2 * count; c ++) {
15091     rgbaf[c] = ctx_u8_to_float (rgba[c]);
15092     ((float*)out)[0] = ctx_float_color_rgb_to_gray (rasterizer->state, rgbaf);
15093     ((float*)out)[1] = rgbaf[3];
15094     out = ((float*)out) + 2;
15095   }
15096 }
15097 
ctx_rasterizer_get_fragment_GRAYAF(CtxRasterizer * rasterizer)15098 static CtxFragment ctx_rasterizer_get_fragment_GRAYAF (CtxRasterizer *rasterizer)
15099 {
15100   CtxGState *gstate = &rasterizer->state->gstate;
15101   switch (gstate->source_fill.type)
15102     {
15103       case CTX_SOURCE_TEXTURE:           return ctx_fragment_image_GRAYAF;
15104       case CTX_SOURCE_COLOR:           return ctx_fragment_color_GRAYAF;
15105 #if CTX_GRADIENTS
15106       case CTX_SOURCE_LINEAR_GRADIENT: return ctx_fragment_linear_gradient_GRAYAF;
15107       case CTX_SOURCE_RADIAL_GRADIENT: return ctx_fragment_radial_gradient_GRAYAF;
15108 #endif
15109     }
15110   return ctx_fragment_color_GRAYAF;
15111 }
15112 
15113 ctx_float_porter_duff(GRAYAF, 2,color,   rasterizer->fragment, rasterizer->state->gstate.blend_mode)
15114 ctx_float_porter_duff(GRAYAF, 2,generic, rasterizer->fragment, rasterizer->state->gstate.blend_mode)
15115 
15116 #if CTX_INLINED_NORMAL
15117 ctx_float_porter_duff(GRAYAF, 2,color_normal,   rasterizer->fragment, CTX_BLEND_NORMAL)
15118 ctx_float_porter_duff(GRAYAF, 2,generic_normal, rasterizer->fragment, CTX_BLEND_NORMAL)
15119 
15120 static void
ctx_GRAYAF_copy_normal(CTX_COMPOSITE_ARGUMENTS)15121 ctx_GRAYAF_copy_normal (CTX_COMPOSITE_ARGUMENTS)
15122 {
15123   ctx_float_copy_normal (2, rasterizer, dst, src, x0, coverage, count);
15124 }
15125 
15126 static void
ctx_GRAYAF_clear_normal(CTX_COMPOSITE_ARGUMENTS)15127 ctx_GRAYAF_clear_normal (CTX_COMPOSITE_ARGUMENTS)
15128 {
15129   ctx_float_clear_normal (2, rasterizer, dst, src, x0, coverage, count);
15130 }
15131 
15132 static void
ctx_GRAYAF_source_copy_normal_color(CTX_COMPOSITE_ARGUMENTS)15133 ctx_GRAYAF_source_copy_normal_color (CTX_COMPOSITE_ARGUMENTS)
15134 {
15135   ctx_float_source_copy_normal_color (2, rasterizer, dst, rasterizer->color, x0, coverage, count);
15136 }
15137 #endif
15138 
15139 static void
ctx_setup_GRAYAF(CtxRasterizer * rasterizer)15140 ctx_setup_GRAYAF (CtxRasterizer *rasterizer)
15141 {
15142   CtxGState *gstate = &rasterizer->state->gstate;
15143   int components = 2;
15144   rasterizer->fragment = ctx_rasterizer_get_fragment_GRAYAF (rasterizer);
15145   rasterizer->comp = CTX_COV_PATH_FALLBACK;
15146   if (gstate->source_fill.type == CTX_SOURCE_COLOR)
15147     {
15148       rasterizer->comp_op = ctx_GRAYAF_porter_duff_color;
15149   //  rasterizer->fragment = NULL;
15150       ctx_color_get_rgba (rasterizer->state, &gstate->source_fill.color, (float*)rasterizer->color);
15151       if (gstate->global_alpha_u8 != 255)
15152         for (int c = 0; c < components; c ++)
15153           ((float*)rasterizer->color)[c] *= gstate->global_alpha_f;
15154     }
15155   else
15156   {
15157     rasterizer->comp_op = ctx_GRAYAF_porter_duff_generic;
15158   }
15159 
15160 #if CTX_INLINED_NORMAL
15161   if (gstate->compositing_mode == CTX_COMPOSITE_CLEAR)
15162     rasterizer->comp_op = ctx_GRAYAF_clear_normal;
15163   else
15164     switch (gstate->blend_mode)
15165     {
15166       case CTX_BLEND_NORMAL:
15167         if (gstate->compositing_mode == CTX_COMPOSITE_COPY)
15168         {
15169           rasterizer->comp_op = ctx_GRAYAF_copy_normal;
15170         }
15171         else if (gstate->global_alpha_u8 == 0)
15172           rasterizer->comp_op = ctx_RGBA8_nop;
15173         else
15174         switch (gstate->source_fill.type)
15175         {
15176           case CTX_SOURCE_COLOR:
15177             if (gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
15178             {
15179               if (((float*)rasterizer->color)[components-1] == 0.0f)
15180                 rasterizer->comp_op = ctx_RGBA8_nop;
15181 #if 1
15182               else //if (((float*)rasterizer->color)[components-1] == 0.0f)
15183                 rasterizer->comp_op = ctx_GRAYAF_source_copy_normal_color;
15184 #endif
15185               //else
15186           //      rasterizer->comp_op = ctx_GRAYAF_porter_duff_color_normal;
15187 //            rasterizer->fragment = NULL;
15188             }
15189             else
15190             {
15191               rasterizer->comp_op = ctx_GRAYAF_porter_duff_color_normal;
15192 //            rasterizer->fragment = NULL;
15193             }
15194             break;
15195           default:
15196             rasterizer->comp_op = ctx_GRAYAF_porter_duff_generic_normal;
15197             break;
15198         }
15199         break;
15200       default:
15201         switch (gstate->source_fill.type)
15202         {
15203           case CTX_SOURCE_COLOR:
15204             rasterizer->comp_op = ctx_GRAYAF_porter_duff_color;
15205 //          rasterizer->fragment = NULL;
15206             break;
15207           default:
15208             rasterizer->comp_op = ctx_GRAYAF_porter_duff_generic;
15209             break;
15210         }
15211         break;
15212     }
15213 #endif
15214 }
15215 
15216 #endif
15217 #if CTX_ENABLE_GRAYF
15218 
15219 static void
ctx_composite_GRAYF(CTX_COMPOSITE_ARGUMENTS)15220 ctx_composite_GRAYF (CTX_COMPOSITE_ARGUMENTS)
15221 {
15222   float *dstf = (float*)dst;
15223 
15224   float temp[count*2];
15225   for (int i = 0; i < count; i++)
15226   {
15227     temp[i*2] = dstf[i];
15228     temp[i*2+1] = 1.0f;
15229   }
15230   rasterizer->comp_op (rasterizer, (uint8_t*)temp, rasterizer->color, x0, coverage, count);
15231   for (int i = 0; i < count; i++)
15232   {
15233     dstf[i] = temp[i*2];
15234   }
15235 }
15236 
15237 #endif
15238 #if CTX_ENABLE_BGRA8
15239 
15240 inline static void
ctx_swap_red_green(uint8_t * rgba)15241 ctx_swap_red_green (uint8_t *rgba)
15242 {
15243   uint32_t *buf  = (uint32_t *) rgba;
15244   uint32_t  orig = *buf;
15245   uint32_t  green_alpha = (orig & 0xff00ff00);
15246   uint32_t  red_blue    = (orig & 0x00ff00ff);
15247   uint32_t  red         = red_blue << 16;
15248   uint32_t  blue        = red_blue >> 16;
15249   *buf = green_alpha | red | blue;
15250 }
15251 
15252 static void
ctx_BGRA8_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15253 ctx_BGRA8_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15254 {
15255   uint32_t *srci = (uint32_t *) buf;
15256   uint32_t *dsti = (uint32_t *) rgba;
15257   while (count--)
15258     {
15259       uint32_t val = *srci++;
15260       ctx_swap_red_green ( (uint8_t *) &val);
15261       *dsti++      = val;
15262     }
15263 }
15264 
15265 static void
ctx_RGBA8_to_BGRA8(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15266 ctx_RGBA8_to_BGRA8 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15267 {
15268   ctx_BGRA8_to_RGBA8 (rasterizer, x, rgba, (uint8_t *) buf, count);
15269 }
15270 
15271 static void
ctx_composite_BGRA8(CTX_COMPOSITE_ARGUMENTS)15272 ctx_composite_BGRA8 (CTX_COMPOSITE_ARGUMENTS)
15273 {
15274   // for better performance, this could be done without a pre/post conversion,
15275   // by swapping R and B of source instead... as long as it is a color instead
15276   // of gradient or image
15277   //
15278   //
15279   uint8_t pixels[count * 4];
15280   ctx_BGRA8_to_RGBA8 (rasterizer, x0, dst, &pixels[0], count);
15281   rasterizer->comp_op (rasterizer, &pixels[0], rasterizer->color, x0, coverage, count);
15282   ctx_BGRA8_to_RGBA8  (rasterizer, x0, &pixels[0], dst, count);
15283 }
15284 
15285 
15286 #endif
15287 #if CTX_ENABLE_CMYKAF
15288 
15289 static void
ctx_fragment_other_CMYKAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)15290 ctx_fragment_other_CMYKAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
15291 {
15292   float *cmyka = (float*)out;
15293   float _rgba[4 * count];
15294   float *rgba = &_rgba[0];
15295   CtxGState *gstate = &rasterizer->state->gstate;
15296   switch (gstate->source_fill.type)
15297     {
15298       case CTX_SOURCE_TEXTURE:
15299         ctx_fragment_image_RGBAF (rasterizer, x, y, rgba, count, dx, dy);
15300         break;
15301       case CTX_SOURCE_COLOR:
15302         ctx_fragment_color_RGBAF (rasterizer, x, y, rgba, count, dx, dy);
15303         break;
15304 #if CTX_GRADIENTS
15305       case CTX_SOURCE_LINEAR_GRADIENT:
15306         ctx_fragment_linear_gradient_RGBAF (rasterizer, x, y, rgba, count, dx, dy);
15307         break;
15308       case CTX_SOURCE_RADIAL_GRADIENT:
15309         ctx_fragment_radial_gradient_RGBAF (rasterizer, x, y, rgba, count, dx, dy);
15310         break;
15311 #endif
15312       default:
15313         rgba[0]=rgba[1]=rgba[2]=rgba[3]=0.0f;
15314         break;
15315     }
15316   for (int i = 0; i < count; i++)
15317   {
15318     cmyka[4]=rgba[3];
15319     ctx_rgb_to_cmyk (rgba[0], rgba[1], rgba[2], &cmyka[0], &cmyka[1], &cmyka[2], &cmyka[3]);
15320     cmyka += 5;
15321     rgba += 4;
15322   }
15323 }
15324 
15325 static void
ctx_fragment_color_CMYKAF(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)15326 ctx_fragment_color_CMYKAF (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
15327 {
15328   CtxGState *gstate = &rasterizer->state->gstate;
15329   float *cmyka = (float*)out;
15330   float cmyka_in[5];
15331   ctx_color_get_cmyka (rasterizer->state, &gstate->source_fill.color, cmyka_in);
15332   for (int i = 0; i < count; i++)
15333   {
15334     for (int c = 0; c < 4; c ++)
15335     {
15336       cmyka[c] = (1.0f - cmyka_in[c]);
15337     }
15338     cmyka[4] = cmyka_in[4];
15339     cmyka += 5;
15340   }
15341 }
15342 
ctx_rasterizer_get_fragment_CMYKAF(CtxRasterizer * rasterizer)15343 static CtxFragment ctx_rasterizer_get_fragment_CMYKAF (CtxRasterizer *rasterizer)
15344 {
15345   CtxGState *gstate = &rasterizer->state->gstate;
15346   switch (gstate->source_fill.type)
15347     {
15348       case CTX_SOURCE_COLOR:
15349         return ctx_fragment_color_CMYKAF;
15350     }
15351   return ctx_fragment_other_CMYKAF;
15352 }
15353 
15354 ctx_float_porter_duff (CMYKAF, 5,color,           rasterizer->fragment, rasterizer->state->gstate.blend_mode)
15355 ctx_float_porter_duff (CMYKAF, 5,generic,         rasterizer->fragment, rasterizer->state->gstate.blend_mode)
15356 
15357 #if CTX_INLINED_NORMAL
15358 ctx_float_porter_duff (CMYKAF, 5,color_normal,            rasterizer->fragment, CTX_BLEND_NORMAL)
15359 ctx_float_porter_duff (CMYKAF, 5,generic_normal,          rasterizer->fragment, CTX_BLEND_NORMAL)
15360 
15361 static void
ctx_CMYKAF_copy_normal(CTX_COMPOSITE_ARGUMENTS)15362 ctx_CMYKAF_copy_normal (CTX_COMPOSITE_ARGUMENTS)
15363 {
15364   ctx_float_copy_normal (5, rasterizer, dst, src, x0, coverage, count);
15365 }
15366 
15367 static void
ctx_CMYKAF_clear_normal(CTX_COMPOSITE_ARGUMENTS)15368 ctx_CMYKAF_clear_normal (CTX_COMPOSITE_ARGUMENTS)
15369 {
15370   ctx_float_clear_normal (5, rasterizer, dst, src, x0, coverage, count);
15371 }
15372 
15373 static void
ctx_CMYKAF_source_copy_normal_color(CTX_COMPOSITE_ARGUMENTS)15374 ctx_CMYKAF_source_copy_normal_color (CTX_COMPOSITE_ARGUMENTS)
15375 {
15376   ctx_float_source_copy_normal_color (5, rasterizer, dst, rasterizer->color, x0, coverage, count);
15377 }
15378 #endif
15379 
15380 static void
ctx_setup_CMYKAF(CtxRasterizer * rasterizer)15381 ctx_setup_CMYKAF (CtxRasterizer *rasterizer)
15382 {
15383   CtxGState *gstate = &rasterizer->state->gstate;
15384   int components = 5;
15385   rasterizer->fragment = ctx_rasterizer_get_fragment_CMYKAF (rasterizer);
15386   rasterizer->comp = CTX_COV_PATH_FALLBACK;
15387   if (gstate->source_fill.type == CTX_SOURCE_COLOR)
15388     {
15389       rasterizer->comp_op = ctx_CMYKAF_porter_duff_color;
15390       rasterizer->comp_op = ctx_CMYKAF_porter_duff_generic;
15391  //     rasterizer->fragment = NULL;
15392       ctx_color_get_cmyka (rasterizer->state, &gstate->source_fill.color, (float*)rasterizer->color);
15393       if (gstate->global_alpha_u8 != 255)
15394         ((float*)rasterizer->color)[components-1] *= gstate->global_alpha_f;
15395     }
15396   else
15397   {
15398     rasterizer->comp_op = ctx_CMYKAF_porter_duff_generic;
15399   }
15400 
15401 #if CTX_INLINED_NORMAL
15402   if (gstate->compositing_mode == CTX_COMPOSITE_CLEAR)
15403     rasterizer->comp_op = ctx_CMYKAF_clear_normal;
15404 #if 1
15405   else
15406     switch (gstate->blend_mode)
15407     {
15408       case CTX_BLEND_NORMAL:
15409         if (gstate->compositing_mode == CTX_COMPOSITE_COPY)
15410         {
15411           rasterizer->comp_op = ctx_CMYKAF_copy_normal;
15412         }
15413         else if (gstate->global_alpha_u8 == 0)
15414           rasterizer->comp_op = ctx_RGBA8_nop;
15415         else
15416         switch (gstate->source_fill.type)
15417         {
15418           case CTX_SOURCE_COLOR:
15419             if (gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
15420             {
15421               if (((float*)rasterizer->color)[components-1] == 0.0f)
15422                 rasterizer->comp_op = ctx_RGBA8_nop;
15423 #if 1
15424               else //if (((float*)rasterizer->color)[components-1] == 1.0f)
15425                 rasterizer->comp_op = ctx_CMYKAF_source_copy_normal_color;
15426    //           else
15427    //             rasterizer->comp_op = ctx_CMYKAF_porter_duff_color_normal;
15428               rasterizer->fragment = NULL;
15429 #endif
15430             }
15431             else
15432             {
15433               rasterizer->comp_op = ctx_CMYKAF_porter_duff_color_normal;
15434    //         rasterizer->fragment = NULL;
15435             }
15436             break;
15437           default:
15438             rasterizer->comp_op = ctx_CMYKAF_porter_duff_generic_normal;
15439             break;
15440         }
15441         break;
15442       default:
15443         switch (gstate->source_fill.type)
15444         {
15445           case CTX_SOURCE_COLOR:
15446             rasterizer->comp_op = ctx_CMYKAF_porter_duff_color;
15447     //      rasterizer->fragment = NULL;
15448             break;
15449           default:
15450             rasterizer->comp_op = ctx_CMYKAF_porter_duff_generic;
15451             break;
15452         }
15453         break;
15454     }
15455 #endif
15456 #endif
15457 }
15458 
15459 #endif
15460 #if CTX_ENABLE_CMYKA8
15461 
15462 static void
ctx_CMYKA8_to_CMYKAF(CtxRasterizer * rasterizer,uint8_t * src,float * dst,int count)15463 ctx_CMYKA8_to_CMYKAF (CtxRasterizer *rasterizer, uint8_t *src, float *dst, int count)
15464 {
15465   for (int i = 0; i < count; i ++)
15466     {
15467       for (int c = 0; c < 4; c ++)
15468         { dst[c] = ctx_u8_to_float ( (255-src[c]) ); }
15469       dst[4] = ctx_u8_to_float (src[4]);
15470       for (int c = 0; c < 4; c++)
15471         { dst[c] *= dst[4]; }
15472       src += 5;
15473       dst += 5;
15474     }
15475 }
15476 static void
ctx_CMYKAF_to_CMYKA8(CtxRasterizer * rasterizer,float * src,uint8_t * dst,int count)15477 ctx_CMYKAF_to_CMYKA8 (CtxRasterizer *rasterizer, float *src, uint8_t *dst, int count)
15478 {
15479   for (int i = 0; i < count; i ++)
15480     {
15481       int a = ctx_float_to_u8 (src[4]);
15482       if (a != 0 && a != 255)
15483       {
15484         float recip = 1.0f/src[4];
15485         for (int c = 0; c < 4; c++)
15486         {
15487           dst[c] = ctx_float_to_u8 (1.0f - src[c] * recip);
15488         }
15489       }
15490       else
15491       {
15492         for (int c = 0; c < 4; c++)
15493           dst[c] = 255 - ctx_float_to_u8 (src[c]);
15494       }
15495       dst[4]=a;
15496 
15497       src += 5;
15498       dst += 5;
15499     }
15500 }
15501 
15502 static void
ctx_composite_CMYKA8(CTX_COMPOSITE_ARGUMENTS)15503 ctx_composite_CMYKA8 (CTX_COMPOSITE_ARGUMENTS)
15504 {
15505   float pixels[count * 5];
15506   ctx_CMYKA8_to_CMYKAF (rasterizer, dst, &pixels[0], count);
15507   rasterizer->comp_op (rasterizer, (uint8_t *) &pixels[0], rasterizer->color, x0, coverage, count);
15508   ctx_CMYKAF_to_CMYKA8 (rasterizer, &pixels[0], dst, count);
15509 }
15510 
15511 #endif
15512 #if CTX_ENABLE_CMYK8
15513 
15514 static void
ctx_CMYK8_to_CMYKAF(CtxRasterizer * rasterizer,uint8_t * src,float * dst,int count)15515 ctx_CMYK8_to_CMYKAF (CtxRasterizer *rasterizer, uint8_t *src, float *dst, int count)
15516 {
15517   for (int i = 0; i < count; i ++)
15518     {
15519       dst[0] = ctx_u8_to_float (255-src[0]);
15520       dst[1] = ctx_u8_to_float (255-src[1]);
15521       dst[2] = ctx_u8_to_float (255-src[2]);
15522       dst[3] = ctx_u8_to_float (255-src[3]);
15523       dst[4] = 1.0f;
15524       src += 4;
15525       dst += 5;
15526     }
15527 }
15528 static void
ctx_CMYKAF_to_CMYK8(CtxRasterizer * rasterizer,float * src,uint8_t * dst,int count)15529 ctx_CMYKAF_to_CMYK8 (CtxRasterizer *rasterizer, float *src, uint8_t *dst, int count)
15530 {
15531   for (int i = 0; i < count; i ++)
15532     {
15533       float c = src[0];
15534       float m = src[1];
15535       float y = src[2];
15536       float k = src[3];
15537       float a = src[4];
15538       if (a != 0.0f && a != 1.0f)
15539         {
15540           float recip = 1.0f/a;
15541           c *= recip;
15542           m *= recip;
15543           y *= recip;
15544           k *= recip;
15545         }
15546       c = 1.0 - c;
15547       m = 1.0 - m;
15548       y = 1.0 - y;
15549       k = 1.0 - k;
15550       dst[0] = ctx_float_to_u8 (c);
15551       dst[1] = ctx_float_to_u8 (m);
15552       dst[2] = ctx_float_to_u8 (y);
15553       dst[3] = ctx_float_to_u8 (k);
15554       src += 5;
15555       dst += 4;
15556     }
15557 }
15558 
15559 static void
ctx_composite_CMYK8(CTX_COMPOSITE_ARGUMENTS)15560 ctx_composite_CMYK8 (CTX_COMPOSITE_ARGUMENTS)
15561 {
15562   float pixels[count * 5];
15563   ctx_CMYK8_to_CMYKAF (rasterizer, dst, &pixels[0], count);
15564   rasterizer->comp_op (rasterizer, (uint8_t *) &pixels[0], src, x0, coverage, count);
15565   ctx_CMYKAF_to_CMYK8 (rasterizer, &pixels[0], dst, count);
15566 }
15567 #endif
15568 
15569 #if CTX_ENABLE_RGB8
15570 
15571 inline static void
ctx_RGB8_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15572 ctx_RGB8_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15573 {
15574   const uint8_t *pixel = (const uint8_t *) buf;
15575   while (count--)
15576     {
15577       rgba[0] = pixel[0];
15578       rgba[1] = pixel[1];
15579       rgba[2] = pixel[2];
15580       rgba[3] = 255;
15581       pixel+=3;
15582       rgba +=4;
15583     }
15584 }
15585 
15586 inline static void
ctx_RGBA8_to_RGB8(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15587 ctx_RGBA8_to_RGB8 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15588 {
15589   uint8_t *pixel = (uint8_t *) buf;
15590   while (count--)
15591     {
15592       pixel[0] = rgba[0];
15593       pixel[1] = rgba[1];
15594       pixel[2] = rgba[2];
15595       pixel+=3;
15596       rgba +=4;
15597     }
15598 }
15599 
15600 #endif
15601 #if CTX_ENABLE_GRAY1
15602 
15603 #if CTX_NATIVE_GRAYA8
15604 inline static void
ctx_GRAY1_to_GRAYA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15605 ctx_GRAY1_to_GRAYA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15606 {
15607   const uint8_t *pixel = (uint8_t *) buf;
15608   while (count--)
15609     {
15610       rgba[0] = 255 * (*pixel & (1<< (x&7) ) );
15611       rgba[1] = 255;
15612       pixel+= ( (x&7) ==7);
15613       x++;
15614       rgba +=2;
15615     }
15616 }
15617 
15618 inline static void
ctx_GRAYA8_to_GRAY1(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15619 ctx_GRAYA8_to_GRAY1 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15620 {
15621   uint8_t *pixel = (uint8_t *) buf;
15622   *pixel = 0;
15623   while (count--)
15624     {
15625       int gray = rgba[0];
15626       //gray += ctx_dither_mask_a (x, rasterizer->scanline/aa, 0, 127);
15627       if (gray >= 127)
15628         {
15629           *pixel = *pixel | ((1<< (x&7) ) * (gray >= 127));
15630         }
15631 #if 0
15632       else
15633       {
15634           *pixel = *pixel & (~ (1<< (x&7) ) );
15635       }
15636 #endif
15637       if ( (x&7) ==7)
15638         { pixel+=1;
15639           if(count>0)*pixel = 0;
15640         }
15641       x++;
15642       rgba +=2;
15643     }
15644 }
15645 
15646 #else
15647 
15648 inline static void
ctx_GRAY1_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15649 ctx_GRAY1_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15650 {
15651   const uint8_t *pixel = (uint8_t *) buf;
15652   while (count--)
15653     {
15654       *((uint32_t*)(rgba))=0xff000000 + 0x00ffffff * ((*pixel & (1<< (x&7) ) )!=0);
15655       pixel+= ( (x&7) ==7);
15656       x++;
15657       rgba +=4;
15658     }
15659 }
15660 
15661 inline static void
ctx_RGBA8_to_GRAY1(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15662 ctx_RGBA8_to_GRAY1 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15663 {
15664   uint8_t *pixel = (uint8_t *) buf;
15665   *pixel = 0;
15666   while (count--)
15667     {
15668       int gray = ctx_u8_color_rgb_to_gray (rasterizer->state, rgba);
15669       //gray += ctx_dither_mask_a (x, rasterizer->scanline/aa, 0, 127);
15670       if (gray <= 127)
15671         {
15672           //*pixel = *pixel & (~ (1<< (x&7) ) );
15673         }
15674       else
15675         {
15676           *pixel = *pixel | (1<< (x&7) );
15677         }
15678       if ( (x&7) ==7)
15679         { pixel+=1;
15680           if(count>0)*pixel = 0;
15681         }
15682       x++;
15683       rgba +=4;
15684     }
15685 }
15686 #endif
15687 
15688 #endif
15689 #if CTX_ENABLE_GRAY2
15690 
15691 #if CTX_NATIVE_GRAYA8
15692 inline static void
ctx_GRAY2_to_GRAYA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15693 ctx_GRAY2_to_GRAYA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15694 {
15695   const uint8_t *pixel = (uint8_t *) buf;
15696   while (count--)
15697     {
15698       int val = (*pixel & (3 << ( (x & 3) <<1) ) ) >> ( (x&3) <<1);
15699       val <<= 6;
15700       rgba[0] = val;
15701       rgba[1] = 255;
15702       if ( (x&3) ==3)
15703         { pixel+=1; }
15704       x++;
15705       rgba +=2;
15706     }
15707 }
15708 
15709 inline static void
ctx_GRAYA8_to_GRAY2(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15710 ctx_GRAYA8_to_GRAY2 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15711 {
15712   uint8_t *pixel = (uint8_t *) buf;
15713   while (count--)
15714     {
15715       int val = rgba[0];
15716       val >>= 6;
15717       *pixel = *pixel & (~ (3 << ( (x&3) <<1) ) );
15718       *pixel = *pixel | ( (val << ( (x&3) <<1) ) );
15719       if ( (x&3) ==3)
15720         { pixel+=1; }
15721       x++;
15722       rgba +=2;
15723     }
15724 }
15725 #else
15726 
15727 inline static void
ctx_GRAY2_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15728 ctx_GRAY2_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15729 {
15730   const uint8_t *pixel = (uint8_t *) buf;
15731   while (count--)
15732     {
15733       int val = (*pixel & (3 << ( (x & 3) <<1) ) ) >> ( (x&3) <<1);
15734       val <<= 6;
15735       rgba[0] = val;
15736       rgba[1] = val;
15737       rgba[2] = val;
15738       rgba[3] = 255;
15739       if ( (x&3) ==3)
15740         { pixel+=1; }
15741       x++;
15742       rgba +=4;
15743     }
15744 }
15745 
15746 inline static void
ctx_RGBA8_to_GRAY2(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15747 ctx_RGBA8_to_GRAY2 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15748 {
15749   uint8_t *pixel = (uint8_t *) buf;
15750   while (count--)
15751     {
15752       int val = ctx_u8_color_rgb_to_gray (rasterizer->state, rgba);
15753       val >>= 6;
15754       *pixel = *pixel & (~ (3 << ( (x&3) <<1) ) );
15755       *pixel = *pixel | ( (val << ( (x&3) <<1) ) );
15756       if ( (x&3) ==3)
15757         { pixel+=1; }
15758       x++;
15759       rgba +=4;
15760     }
15761 }
15762 #endif
15763 
15764 #endif
15765 #if CTX_ENABLE_GRAY4
15766 
15767 #if CTX_NATIVE_GRAYA8
15768 inline static void
ctx_GRAY4_to_GRAYA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15769 ctx_GRAY4_to_GRAYA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15770 {
15771   const uint8_t *pixel = (uint8_t *) buf;
15772   while (count--)
15773     {
15774       int val = (*pixel & (15 << ( (x & 1) <<2) ) ) >> ( (x&1) <<2);
15775       val <<= 4;
15776       rgba[0] = val;
15777       rgba[1] = 255;
15778       if ( (x&1) ==1)
15779         { pixel+=1; }
15780       x++;
15781       rgba +=2;
15782     }
15783 }
15784 
15785 inline static void
ctx_GRAYA8_to_GRAY4(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15786 ctx_GRAYA8_to_GRAY4 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15787 {
15788   uint8_t *pixel = (uint8_t *) buf;
15789   while (count--)
15790     {
15791       int val = rgba[0];
15792       val >>= 4;
15793       *pixel = *pixel & (~ (15 << ( (x&1) <<2) ) );
15794       *pixel = *pixel | ( (val << ( (x&1) <<2) ) );
15795       if ( (x&1) ==1)
15796         { pixel+=1; }
15797       x++;
15798       rgba +=2;
15799     }
15800 }
15801 #else
15802 inline static void
ctx_GRAY4_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15803 ctx_GRAY4_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15804 {
15805   const uint8_t *pixel = (uint8_t *) buf;
15806   while (count--)
15807     {
15808       int val = (*pixel & (15 << ( (x & 1) <<2) ) ) >> ( (x&1) <<2);
15809       val <<= 4;
15810       rgba[0] = val;
15811       rgba[1] = val;
15812       rgba[2] = val;
15813       rgba[3] = 255;
15814       if ( (x&1) ==1)
15815         { pixel+=1; }
15816       x++;
15817       rgba +=4;
15818     }
15819 }
15820 
15821 inline static void
ctx_RGBA8_to_GRAY4(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15822 ctx_RGBA8_to_GRAY4 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15823 {
15824   uint8_t *pixel = (uint8_t *) buf;
15825   while (count--)
15826     {
15827       int val = ctx_u8_color_rgb_to_gray (rasterizer->state, rgba);
15828       val >>= 4;
15829       *pixel = *pixel & (~ (15 << ( (x&1) <<2) ) );
15830       *pixel = *pixel | ( (val << ( (x&1) <<2) ) );
15831       if ( (x&1) ==1)
15832         { pixel+=1; }
15833       x++;
15834       rgba +=4;
15835     }
15836 }
15837 #endif
15838 
15839 #endif
15840 #if CTX_ENABLE_GRAY8
15841 
15842 #if CTX_NATIVE_GRAYA8
15843 inline static void
ctx_GRAY8_to_GRAYA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15844 ctx_GRAY8_to_GRAYA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15845 {
15846   const uint8_t *pixel = (uint8_t *) buf;
15847   while (count--)
15848     {
15849       rgba[0] = pixel[0];
15850       rgba[1] = 255;
15851       pixel+=1;
15852       rgba +=2;
15853     }
15854 }
15855 
15856 inline static void
ctx_GRAYA8_to_GRAY8(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15857 ctx_GRAYA8_to_GRAY8 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15858 {
15859   uint8_t *pixel = (uint8_t *) buf;
15860   while (count--)
15861     {
15862       pixel[0] = rgba[0];
15863       pixel+=1;
15864       rgba +=2;
15865     }
15866 }
15867 #else
15868 inline static void
ctx_GRAY8_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15869 ctx_GRAY8_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15870 {
15871   const uint8_t *pixel = (uint8_t *) buf;
15872   while (count--)
15873     {
15874       rgba[0] = pixel[0];
15875       rgba[1] = pixel[0];
15876       rgba[2] = pixel[0];
15877       rgba[3] = 255;
15878       pixel+=1;
15879       rgba +=4;
15880     }
15881 }
15882 
15883 inline static void
ctx_RGBA8_to_GRAY8(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15884 ctx_RGBA8_to_GRAY8 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15885 {
15886   uint8_t *pixel = (uint8_t *) buf;
15887   for (int i = 0; i < count; i ++)
15888     {
15889       pixel[i] = ctx_u8_color_rgb_to_gray (rasterizer->state, rgba + i * 4);
15890     }
15891 }
15892 #endif
15893 
15894 #endif
15895 #if CTX_ENABLE_GRAYA8
15896 
15897 inline static void
ctx_GRAYA8_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)15898 ctx_GRAYA8_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
15899 {
15900   const uint8_t *pixel = (const uint8_t *) buf;
15901   while (count--)
15902     {
15903       rgba[0] = pixel[0];
15904       rgba[1] = pixel[0];
15905       rgba[2] = pixel[0];
15906       rgba[3] = pixel[1];
15907       pixel+=2;
15908       rgba +=4;
15909     }
15910 }
15911 
15912 inline static void
ctx_RGBA8_to_GRAYA8(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)15913 ctx_RGBA8_to_GRAYA8 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
15914 {
15915   uint8_t *pixel = (uint8_t *) buf;
15916   while (count--)
15917     {
15918       pixel[0] = ctx_u8_color_rgb_to_gray (rasterizer->state, rgba);
15919       pixel[1] = rgba[3];
15920       pixel+=2;
15921       rgba +=4;
15922     }
15923 }
15924 
15925 #if CTX_NATIVE_GRAYA8
ctx_rgba_to_graya_u8(CtxState * state,uint8_t * in,uint8_t * out)15926 CTX_INLINE static void ctx_rgba_to_graya_u8 (CtxState *state, uint8_t *in, uint8_t *out)
15927 {
15928   out[0] = ctx_u8_color_rgb_to_gray (state, in);
15929   out[1] = in[3];
15930 }
15931 
15932 #if CTX_GRADIENTS
15933 static void
ctx_fragment_linear_gradient_GRAYA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)15934 ctx_fragment_linear_gradient_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
15935 {
15936   CtxSource *g = &rasterizer->state->gstate.source_fill;
15937         uint8_t *dst = (uint8_t*)out;
15938   for (int i = 0; i < count;i ++)
15939   {
15940   float v = ( ( (g->linear_gradient.dx * x + g->linear_gradient.dy * y) /
15941                 g->linear_gradient.length) -
15942               g->linear_gradient.start) * (g->linear_gradient.rdelta);
15943   {
15944     uint8_t rgba[4];
15945     ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 1.0, rgba);
15946     ctx_rgba_to_graya_u8 (rasterizer->state, rgba, dst);
15947 
15948   }
15949 
15950 
15951 #if CTX_DITHER
15952   ctx_dither_graya_u8 ((uint8_t*)dst, x, y, rasterizer->format->dither_red_blue,
15953                       rasterizer->format->dither_green);
15954 #endif
15955   dst += 2;
15956   x += dx;
15957   y += dy;
15958   }
15959 }
15960 
15961 #if 0
15962 static void
15963 ctx_fragment_radial_gradient_RGBA8 (CtxRasterizer *rasterizer, float x, float y, void *out)
15964 {
15965   uint8_t *rgba = (uint8_t *) out;
15966   CtxSource *g = &rasterizer->state->gstate.source_fill;
15967   float v = (ctx_hypotf (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y) -
15968               g->radial_gradient.r0) * (g->radial_gradient.rdelta);
15969   ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 0.0, rgba);
15970 #if CTX_DITHER
15971   ctx_dither_rgba_u8 (rgba, x, y, rasterizer->format->dither_red_blue,
15972                       rasterizer->format->dither_green);
15973 #endif
15974 }
15975 #endif
15976 
15977 
15978 static void
ctx_fragment_radial_gradient_GRAYA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)15979 ctx_fragment_radial_gradient_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
15980 {
15981         uint8_t *dst = (uint8_t*)out;
15982   for (int i = 0; i < count;i ++)
15983   {
15984   CtxSource *g = &rasterizer->state->gstate.source_fill;
15985   float v = (ctx_hypotf (g->radial_gradient.x0 - x, g->radial_gradient.y0 - y) -
15986               g->radial_gradient.r0) * (g->radial_gradient.rdelta);
15987   {
15988     uint8_t rgba[4];
15989     ctx_fragment_gradient_1d_RGBA8 (rasterizer, v, 1.0, rgba);
15990     ctx_rgba_to_graya_u8 (rasterizer->state, rgba, dst);
15991   }
15992 #if CTX_DITHER
15993   ctx_dither_graya_u8 ((uint8_t*)dst, x, y, rasterizer->format->dither_red_blue,
15994                       rasterizer->format->dither_green);
15995 #endif
15996   dst += 2;
15997   x += dx;
15998   y += dy;
15999   }
16000 }
16001 #endif
16002 
16003 static void
ctx_fragment_color_GRAYA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)16004 ctx_fragment_color_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
16005 {
16006   CtxSource *g = &rasterizer->state->gstate.source_fill;
16007   uint16_t *dst = (uint16_t*)out;
16008   uint16_t pix;
16009   ctx_color_get_graya_u8 (rasterizer->state, &g->color, (void*)&pix);
16010   for (int i = 0; i <count; i++)
16011   {
16012     dst[i]=pix;
16013   }
16014 }
16015 
ctx_fragment_image_GRAYA8(CtxRasterizer * rasterizer,float x,float y,void * out,int count,float dx,float dy)16016 static void ctx_fragment_image_GRAYA8 (CtxRasterizer *rasterizer, float x, float y, void *out, int count, float dx, float dy)
16017 {
16018   uint8_t rgba[4*count];
16019   CtxGState *gstate = &rasterizer->state->gstate;
16020   CtxBuffer *buffer = gstate->source_fill.texture.buffer;
16021   switch (buffer->format->bpp)
16022     {
16023 #if CTX_FRAGMENT_SPECIALIZE
16024       case 1:  ctx_fragment_image_gray1_RGBA8 (rasterizer, x, y, rgba, count, dx, dy); break;
16025       case 24: ctx_fragment_image_rgb8_RGBA8 (rasterizer, x, y, rgba, count, dx, dy);  break;
16026       case 32: ctx_fragment_image_rgba8_RGBA8 (rasterizer, x, y, rgba, count, dx, dy); break;
16027 #endif
16028       default: ctx_fragment_image_RGBA8 (rasterizer, x, y, rgba, count, dx, dy);       break;
16029     }
16030   for (int i = 0; i < count; i++)
16031     ctx_rgba_to_graya_u8 (rasterizer->state, &rgba[i*4], &((uint8_t*)out)[i*2]);
16032 }
16033 
ctx_rasterizer_get_fragment_GRAYA8(CtxRasterizer * rasterizer)16034 static CtxFragment ctx_rasterizer_get_fragment_GRAYA8 (CtxRasterizer *rasterizer)
16035 {
16036   CtxGState *gstate = &rasterizer->state->gstate;
16037   switch (gstate->source_fill.type)
16038     {
16039       case CTX_SOURCE_TEXTURE:           return ctx_fragment_image_GRAYA8;
16040       case CTX_SOURCE_COLOR:           return ctx_fragment_color_GRAYA8;
16041 #if CTX_GRADIENTS
16042       case CTX_SOURCE_LINEAR_GRADIENT: return ctx_fragment_linear_gradient_GRAYA8;
16043       case CTX_SOURCE_RADIAL_GRADIENT: return ctx_fragment_radial_gradient_GRAYA8;
16044 #endif
16045     }
16046   return ctx_fragment_color_GRAYA8;
16047 }
16048 
16049 //ctx_u8_porter_duff(GRAYA8, 2,color,   rasterizer->fragment, rasterizer->state->gstate.blend_mode)
16050 ctx_u8_porter_duff(GRAYA8, 2,generic, rasterizer->fragment, rasterizer->state->gstate.blend_mode)
16051 
16052 #if CTX_INLINED_NORMAL
16053 //ctx_u8_porter_duff(GRAYA8, 2,color_normal,   rasterizer->fragment, CTX_BLEND_NORMAL)
16054 ctx_u8_porter_duff(GRAYA8, 2,generic_normal, rasterizer->fragment, CTX_BLEND_NORMAL)
16055 
16056 static void
ctx_GRAYA8_copy_normal(CTX_COMPOSITE_ARGUMENTS)16057 ctx_GRAYA8_copy_normal (CTX_COMPOSITE_ARGUMENTS)
16058 {
16059   ctx_u8_copy_normal (2, rasterizer, dst, src, x0, coverage, count);
16060 }
16061 
16062 static void
ctx_GRAYA8_clear_normal(CTX_COMPOSITE_ARGUMENTS)16063 ctx_GRAYA8_clear_normal (CTX_COMPOSITE_ARGUMENTS)
16064 {
16065   ctx_u8_clear_normal (2, rasterizer, dst, src, x0, coverage, count);
16066 }
16067 
16068 static void
ctx_GRAYA8_source_over_normal_color(CTX_COMPOSITE_ARGUMENTS)16069 ctx_GRAYA8_source_over_normal_color (CTX_COMPOSITE_ARGUMENTS)
16070 {
16071   ctx_u8_source_over_normal_color (2, rasterizer, dst, rasterizer->color, x0, coverage, count);
16072 }
16073 
16074 static void
ctx_GRAYA8_source_copy_normal_color(CTX_COMPOSITE_ARGUMENTS)16075 ctx_GRAYA8_source_copy_normal_color (CTX_COMPOSITE_ARGUMENTS)
16076 {
16077   ctx_u8_source_copy_normal_color (2, rasterizer, dst, rasterizer->color, x0, coverage, count);
16078 }
16079 #endif
16080 
16081 inline static int
ctx_is_opaque_color(CtxRasterizer * rasterizer)16082 ctx_is_opaque_color (CtxRasterizer *rasterizer)
16083 {
16084   CtxGState *gstate = &rasterizer->state->gstate;
16085   if (gstate->global_alpha_u8 != 255)
16086     return 0;
16087   if (gstate->source_fill.type == CTX_SOURCE_COLOR)
16088   {
16089     uint8_t ga[2];
16090     ctx_color_get_graya_u8 (rasterizer->state, &gstate->source_fill.color, ga);
16091     return ga[1] == 255;
16092   }
16093   return 0;
16094 }
16095 
16096 static void
ctx_setup_GRAYA8(CtxRasterizer * rasterizer)16097 ctx_setup_GRAYA8 (CtxRasterizer *rasterizer)
16098 {
16099   CtxGState *gstate = &rasterizer->state->gstate;
16100   int components = 2;
16101   rasterizer->fragment = ctx_rasterizer_get_fragment_GRAYA8 (rasterizer);
16102   rasterizer->comp_op  = ctx_GRAYA8_porter_duff_generic;
16103   rasterizer->comp = CTX_COV_PATH_FALLBACK;
16104   if (gstate->source_fill.type == CTX_SOURCE_COLOR)
16105     {
16106       ctx_fragment_color_GRAYA8 (rasterizer, 0,0, rasterizer->color, 1, 0,0);
16107       if (gstate->global_alpha_u8 != 255)
16108         for (int c = 0; c < components; c ++)
16109           rasterizer->color[c] = (rasterizer->color[c] * gstate->global_alpha_u8)/255;
16110     }
16111 
16112 #if CTX_INLINED_NORMAL
16113   if (gstate->compositing_mode == CTX_COMPOSITE_CLEAR)
16114     rasterizer->comp_op = ctx_GRAYA8_clear_normal;
16115   else
16116     switch (gstate->blend_mode)
16117     {
16118       case CTX_BLEND_NORMAL:
16119         if (gstate->compositing_mode == CTX_COMPOSITE_COPY)
16120         {
16121           rasterizer->comp_op = ctx_GRAYA8_copy_normal;
16122         }
16123         else if (gstate->global_alpha_u8 == 0)
16124           rasterizer->comp_op = ctx_RGBA8_nop;
16125         else
16126         switch (gstate->source_fill.type)
16127         {
16128           case CTX_SOURCE_COLOR:
16129             if (gstate->compositing_mode == CTX_COMPOSITE_SOURCE_OVER)
16130             {
16131               if (rasterizer->color[components-1] == 0)
16132                 rasterizer->comp_op = ctx_RGBA8_nop;
16133               else if (rasterizer->color[components-1] == 255)
16134                 rasterizer->comp_op = ctx_GRAYA8_source_copy_normal_color;
16135               else
16136                 rasterizer->comp_op = ctx_GRAYA8_source_over_normal_color;
16137             }
16138             else
16139             {
16140               rasterizer->comp_op = ctx_GRAYA8_porter_duff_generic_normal;
16141             }
16142             break;
16143           default:
16144             rasterizer->comp_op = ctx_GRAYA8_porter_duff_generic_normal;
16145             break;
16146         }
16147         break;
16148       default:
16149         rasterizer->comp_op = ctx_GRAYA8_porter_duff_generic;
16150         break;
16151     }
16152 #endif
16153 }
16154 #endif
16155 
16156 #endif
16157 #if CTX_ENABLE_RGB332
16158 
16159 inline static void
ctx_332_unpack(uint8_t pixel,uint8_t * red,uint8_t * green,uint8_t * blue)16160 ctx_332_unpack (uint8_t pixel,
16161                 uint8_t *red,
16162                 uint8_t *green,
16163                 uint8_t *blue)
16164 {
16165   *blue   = (pixel & 3) <<6;
16166   *green = ( (pixel >> 2) & 7) <<5;
16167   *red   = ( (pixel >> 5) & 7) <<5;
16168   if (*blue > 223)  { *blue  = 255; }
16169   if (*green > 223) { *green = 255; }
16170   if (*red > 223)   { *red   = 255; }
16171 }
16172 
16173 static inline uint8_t
ctx_332_pack(uint8_t red,uint8_t green,uint8_t blue)16174 ctx_332_pack (uint8_t red,
16175               uint8_t green,
16176               uint8_t blue)
16177 {
16178   uint8_t c  = (red >> 5) << 5;
16179   c |= (green >> 5) << 2;
16180   c |= (blue >> 6);
16181   return c;
16182 }
16183 
16184 static inline void
ctx_RGB332_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)16185 ctx_RGB332_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
16186 {
16187   const uint8_t *pixel = (uint8_t *) buf;
16188   while (count--)
16189     {
16190       ctx_332_unpack (*pixel, &rgba[0], &rgba[1], &rgba[2]);
16191 #if CTX_RGB332_ALPHA
16192       if (rgba[0]==255 && rgba[2] == 255 && rgba[1]==0)
16193         { rgba[3] = 0; }
16194       else
16195 #endif
16196         { rgba[3] = 255; }
16197       pixel+=1;
16198       rgba +=4;
16199     }
16200 }
16201 
16202 static inline void
ctx_RGBA8_to_RGB332(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)16203 ctx_RGBA8_to_RGB332 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
16204 {
16205   uint8_t *pixel = (uint8_t *) buf;
16206   while (count--)
16207     {
16208 #if CTX_RGB332_ALPHA
16209       if (rgba[3]==0)
16210         { pixel[0] = ctx_332_pack (255, 0, 255); }
16211       else
16212 #endif
16213         { pixel[0] = ctx_332_pack (rgba[0], rgba[1], rgba[2]); }
16214       pixel+=1;
16215       rgba +=4;
16216     }
16217 }
16218 
16219 #endif
16220 #if CTX_ENABLE_RGB565 | CTX_ENABLE_RGB565_BYTESWAPPED
16221 
16222 static inline void
ctx_565_unpack(const uint16_t pixel,uint8_t * red,uint8_t * green,uint8_t * blue,const int byteswap)16223 ctx_565_unpack (const uint16_t pixel,
16224                 uint8_t *red,
16225                 uint8_t *green,
16226                 uint8_t *blue,
16227                 const int byteswap)
16228 {
16229   uint16_t byteswapped;
16230   if (byteswap)
16231     { byteswapped = (pixel>>8) | (pixel<<8); }
16232   else
16233     { byteswapped  = pixel; }
16234   *blue   =  (byteswapped & 31) <<3;
16235   *green = ( (byteswapped>>5) & 63) <<2;
16236   *red   = ( (byteswapped>>11) & 31) <<3;
16237 #if 0
16238   if (*blue > 248) { *blue = 255; }
16239   if (*green > 248) { *green = 255; }
16240   if (*red > 248) { *red = 255; }
16241 #endif
16242 }
16243 
16244 static inline uint32_t
ctx_565_unpack_32(const uint16_t pixel,const int byteswap)16245 ctx_565_unpack_32 (const uint16_t pixel,
16246                    const int byteswap)
16247 {
16248   uint16_t byteswapped;
16249   if (byteswap)
16250     { byteswapped = (pixel>>8) | (pixel<<8); }
16251   else
16252     { byteswapped  = pixel; }
16253   uint8_t blue   = (byteswapped & 31) <<3;
16254   uint8_t green = ( (byteswapped>>5) & 63) <<2;
16255   uint8_t red   = ( (byteswapped>>11) & 31) <<3;
16256 #if 0
16257   if (*blue > 248) { *blue = 255; }
16258   if (*green > 248) { *green = 255; }
16259   if (*red > 248) { *red = 255; }
16260 #endif
16261   return red +  (green << 8) + (blue << 16) + (0xff << 24);
16262 }
16263 
16264 static inline uint16_t
ctx_565_pack(const uint8_t red,const uint8_t green,const uint8_t blue,const int byteswap)16265 ctx_565_pack (const uint8_t  red,
16266               const uint8_t  green,
16267               const uint8_t  blue,
16268               const int      byteswap)
16269 {
16270   uint32_t c = (red >> 3) << 11;
16271   c |= (green >> 2) << 5;
16272   c |= blue >> 3;
16273   if (byteswap)
16274     { return (c>>8) | (c<<8); } /* swap bytes */
16275   return c;
16276 }
16277 
16278 static inline uint16_t
ctx_888_to_565(uint32_t in,int byteswap)16279 ctx_888_to_565 (uint32_t in, int byteswap)
16280 {
16281   uint8_t *rgb=(uint8_t*)(&in);
16282   return ctx_565_pack (rgb[0],rgb[1],rgb[2], byteswap);
16283 }
16284 
16285 static inline uint32_t
ctx_565_to_888(uint16_t in,int byteswap)16286 ctx_565_to_888 (uint16_t in, int byteswap)
16287 {
16288   uint32_t ret = 0;
16289   uint8_t *rgba=(uint8_t*)&ret;
16290   ctx_565_unpack (in,
16291                   &rgba[0],
16292                   &rgba[1],
16293                   &rgba[2],
16294                   byteswap);
16295   return ret;
16296 }
16297 
16298 #endif
16299 #if CTX_ENABLE_RGB565
16300 
16301 
16302 static inline void
ctx_RGB565_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)16303 ctx_RGB565_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
16304 {
16305   const uint16_t *pixel = (uint16_t *) buf;
16306   while (count--)
16307     {
16308       ((uint32_t*)(rgba))[0] = ctx_565_unpack_32 (*pixel, 0);
16309 #if CTX_RGB565_ALPHA
16310       if (rgba[0]==255 && rgba[2] == 255 && rgba[1]==0)
16311         { rgba[3] = 0; }
16312 #endif
16313       pixel+=1;
16314       rgba +=4;
16315     }
16316 }
16317 
16318 static inline void
ctx_RGBA8_to_RGB565(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)16319 ctx_RGBA8_to_RGB565 (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
16320 {
16321   uint16_t *pixel = (uint16_t *) buf;
16322   while (count--)
16323     {
16324 #if CTX_RGB565_ALPHA
16325       if (rgba[3]==0)
16326         { pixel[0] = ctx_565_pack (255, 0, 255, 0); }
16327       else
16328 #endif
16329         { pixel[0] = ctx_565_pack (rgba[0], rgba[1], rgba[2], 0); }
16330       pixel+=1;
16331       rgba +=4;
16332     }
16333 }
16334 
16335 static void
16336 ctx_RGBA8_source_over_normal_color (CTX_COMPOSITE_ARGUMENTS);
16337 static void
16338 ctx_RGBA8_source_copy_normal_color (CTX_COMPOSITE_ARGUMENTS);
16339 
16340 static void
ctx_composite_RGB565(CTX_COMPOSITE_ARGUMENTS)16341 ctx_composite_RGB565 (CTX_COMPOSITE_ARGUMENTS)
16342 {
16343 #if 0
16344   if (CTX_LIKELY(rasterizer->comp_op == ctx_RGBA8_source_over_normal_color))
16345   {
16346      int byteswap = 0;
16347      uint32_t si    = *((uint32_t*)(src));
16348      uint16_t si_16 = ctx_888_to_565 (si, byteswap);
16349      uint32_t sval  = (si_16 & ( (31 << 11 ) | 31));
16350      uint32_t sg = (si_16 & (63 << 5)) >> 5;
16351      uint32_t si_a = si >> (24 + 3);
16352      while (count--)
16353      {
16354         uint32_t di_16 = *((uint16_t*)(dst));
16355         uint32_t cov = (*coverage) >> 3;
16356         uint32_t racov = (32-((31+si_a*cov)>>5));
16357         uint32_t dval = (di_16 & ( (31 << 11 ) | 31));
16358         uint32_t dg = (di_16 >> 5) & 63; // faster outside than
16359                                          // remerged as part of dval
16360         *((uint16_t*)(dst)) =
16361                 ((
16362                   (((sval * cov) + (dval * racov)) >> 5)
16363                  ) & ((31 << 11 )|31)) |
16364                   ((((sg * cov) + (dg * racov)) & 63) );
16365 
16366      }
16367      return;
16368   }
16369 #endif
16370   uint8_t pixels[count * 4];
16371   ctx_RGB565_to_RGBA8 (rasterizer, x0, dst, &pixels[0], count);
16372   rasterizer->comp_op (rasterizer, &pixels[0], rasterizer->color, x0, coverage, count);
16373   ctx_RGBA8_to_RGB565 (rasterizer, x0, &pixels[0], dst, count);
16374 }
16375 #endif
16376 #if CTX_ENABLE_RGB565_BYTESWAPPED
16377 
16378 static inline void
ctx_RGB565_BS_to_RGBA8(CtxRasterizer * rasterizer,int x,const void * buf,uint8_t * rgba,int count)16379 ctx_RGB565_BS_to_RGBA8 (CtxRasterizer *rasterizer, int x, const void *buf, uint8_t *rgba, int count)
16380 {
16381   const uint16_t *pixel = (uint16_t *) buf;
16382   while (count--)
16383     {
16384       //ctx_565_unpack (*pixel, &rgba[0], &rgba[1], &rgba[2], 1);
16385       ((uint32_t*)(rgba))[0] = ctx_565_unpack_32 (*pixel, 1);
16386 #if CTX_RGB565_ALPHA
16387       if (rgba[0]==255 && rgba[2] == 255 && rgba[1]==0)
16388         { rgba[3] = 0; }
16389       else
16390         { rgba[3] = 255; }
16391 #endif
16392       pixel+=1;
16393       rgba +=4;
16394     }
16395 }
16396 
16397 static inline void
ctx_RGBA8_to_RGB565_BS(CtxRasterizer * rasterizer,int x,const uint8_t * rgba,void * buf,int count)16398 ctx_RGBA8_to_RGB565_BS (CtxRasterizer *rasterizer, int x, const uint8_t *rgba, void *buf, int count)
16399 {
16400   uint16_t *pixel = (uint16_t *) buf;
16401   while (count--)
16402     {
16403 #if CTX_RGB565_ALPHA
16404       if (rgba[3]==0)
16405         { pixel[0] = ctx_565_pack (255, 0, 255, 1); }
16406       else
16407 #endif
16408         { pixel[0] = ctx_565_pack (rgba[0], rgba[1], rgba[2], 1); }
16409       pixel+=1;
16410       rgba +=4;
16411     }
16412 }
16413 
16414 static void
ctx_composite_RGB565_BS(CTX_COMPOSITE_ARGUMENTS)16415 ctx_composite_RGB565_BS (CTX_COMPOSITE_ARGUMENTS)
16416 {
16417   uint8_t pixels[count * 4];
16418   ctx_RGB565_BS_to_RGBA8 (rasterizer, x0, dst, &pixels[0], count);
16419   rasterizer->comp_op (rasterizer, &pixels[0], rasterizer->color, x0, coverage, count);
16420   ctx_RGBA8_to_RGB565_BS (rasterizer, x0, &pixels[0], dst, count);
16421 }
16422 #endif
16423 
16424 static CtxPixelFormatInfo ctx_pixel_formats[]=
16425 {
16426 #if CTX_ENABLE_RGBA8
16427   {
16428     CTX_FORMAT_RGBA8, 4, 32, 4, 0, 0, CTX_FORMAT_RGBA8,
16429     NULL, NULL, NULL, ctx_setup_RGBA8
16430   },
16431 #endif
16432 #if CTX_ENABLE_BGRA8
16433   {
16434     CTX_FORMAT_BGRA8, 4, 32, 4, 0, 0, CTX_FORMAT_RGBA8,
16435     ctx_BGRA8_to_RGBA8, ctx_RGBA8_to_BGRA8, ctx_composite_BGRA8, ctx_setup_RGBA8,
16436   },
16437 #endif
16438 #if CTX_ENABLE_GRAYF
16439   {
16440     CTX_FORMAT_GRAYF, 1, 32, 4 * 2, 0, 0, CTX_FORMAT_GRAYAF,
16441     NULL, NULL, ctx_composite_GRAYF, ctx_setup_GRAYAF,
16442   },
16443 #endif
16444 #if CTX_ENABLE_GRAYAF
16445   {
16446     CTX_FORMAT_GRAYAF, 2, 64, 4 * 2, 0, 0, CTX_FORMAT_GRAYAF,
16447     NULL, NULL, NULL, ctx_setup_GRAYAF,
16448   },
16449 #endif
16450 #if CTX_ENABLE_RGBAF
16451   {
16452     CTX_FORMAT_RGBAF, 4, 128, 4 * 4, 0, 0, CTX_FORMAT_RGBAF,
16453     NULL, NULL, NULL, ctx_setup_RGBAF,
16454   },
16455 #endif
16456 #if CTX_ENABLE_RGB8
16457   {
16458     CTX_FORMAT_RGB8, 3, 24, 4, 0, 0, CTX_FORMAT_RGBA8,
16459     ctx_RGB8_to_RGBA8, ctx_RGBA8_to_RGB8, ctx_composite_convert, ctx_setup_RGBA8,
16460   },
16461 #endif
16462 #if CTX_ENABLE_GRAY1
16463   {
16464 #if CTX_NATIVE_GRAYA8
16465     CTX_FORMAT_GRAY1, 1, 1, 2, 1, 1, CTX_FORMAT_GRAYA8,
16466     ctx_GRAY1_to_GRAYA8, ctx_GRAYA8_to_GRAY1, ctx_composite_convert, ctx_setup_GRAYA8,
16467 #else
16468     CTX_FORMAT_GRAY1, 1, 1, 4, 1, 1, CTX_FORMAT_RGBA8,
16469     ctx_GRAY1_to_RGBA8, ctx_RGBA8_to_GRAY1, ctx_composite_convert, ctx_setup_RGBA8,
16470 #endif
16471   },
16472 #endif
16473 #if CTX_ENABLE_GRAY2
16474   {
16475 #if CTX_NATIVE_GRAYA8
16476     CTX_FORMAT_GRAY2, 1, 2, 2, 4, 4, CTX_FORMAT_GRAYA8,
16477     ctx_GRAY2_to_GRAYA8, ctx_GRAYA8_to_GRAY2, ctx_composite_convert, ctx_setup_GRAYA8,
16478 #else
16479     CTX_FORMAT_GRAY2, 1, 2, 4, 4, 4, CTX_FORMAT_RGBA8,
16480     ctx_GRAY2_to_RGBA8, ctx_RGBA8_to_GRAY2, ctx_composite_convert, ctx_setup_RGBA8,
16481 #endif
16482   },
16483 #endif
16484 #if CTX_ENABLE_GRAY4
16485   {
16486 #if CTX_NATIVE_GRAYA8
16487     CTX_FORMAT_GRAY4, 1, 4, 2, 16, 16, CTX_FORMAT_GRAYA8,
16488     ctx_GRAY4_to_GRAYA8, ctx_GRAYA8_to_GRAY4, ctx_composite_convert, ctx_setup_GRAYA8,
16489 #else
16490     CTX_FORMAT_GRAY4, 1, 4, 4, 16, 16, CTX_FORMAT_GRAYA8,
16491     ctx_GRAY4_to_RGBA8, ctx_RGBA8_to_GRAY4, ctx_composite_convert, ctx_setup_RGBA8,
16492 #endif
16493   },
16494 #endif
16495 #if CTX_ENABLE_GRAY8
16496   {
16497 #if CTX_NATIVE_GRAYA8
16498     CTX_FORMAT_GRAY8, 1, 8, 2, 0, 0, CTX_FORMAT_GRAYA8,
16499     ctx_GRAY8_to_GRAYA8, ctx_GRAYA8_to_GRAY8, ctx_composite_convert, ctx_setup_GRAYA8,
16500 #else
16501     CTX_FORMAT_GRAY8, 1, 8, 4, 0, 0, CTX_FORMAT_RGBA8,
16502     ctx_GRAY8_to_RGBA8, ctx_RGBA8_to_GRAY8, ctx_composite_convert, ctx_setup_RGBA8,
16503 #endif
16504   },
16505 #endif
16506 #if CTX_ENABLE_GRAYA8
16507   {
16508 #if CTX_NATIVE_GRAYA8
16509     CTX_FORMAT_GRAYA8, 2, 16, 2, 0, 0, CTX_FORMAT_GRAYA8,
16510     ctx_GRAYA8_to_RGBA8, ctx_RGBA8_to_GRAYA8, NULL, ctx_setup_GRAYA8,
16511 #else
16512     CTX_FORMAT_GRAYA8, 2, 16, 4, 0, 0, CTX_FORMAT_RGBA8,
16513     ctx_GRAYA8_to_RGBA8, ctx_RGBA8_to_GRAYA8, ctx_composite_convert, ctx_setup_RGBA8,
16514 #endif
16515   },
16516 #endif
16517 #if CTX_ENABLE_RGB332
16518   {
16519     CTX_FORMAT_RGB332, 3, 8, 4, 10, 12, CTX_FORMAT_RGBA8,
16520     ctx_RGB332_to_RGBA8, ctx_RGBA8_to_RGB332,
16521     ctx_composite_convert, ctx_setup_RGBA8,
16522   },
16523 #endif
16524 #if CTX_ENABLE_RGB565
16525   {
16526     CTX_FORMAT_RGB565, 3, 16, 4, 32, 64, CTX_FORMAT_RGBA8,
16527     ctx_RGB565_to_RGBA8, ctx_RGBA8_to_RGB565,
16528     ctx_composite_RGB565, ctx_setup_RGBA8,
16529   },
16530 #endif
16531 #if CTX_ENABLE_RGB565_BYTESWAPPED
16532   {
16533     CTX_FORMAT_RGB565_BYTESWAPPED, 3, 16, 4, 32, 64, CTX_FORMAT_RGBA8,
16534     ctx_RGB565_BS_to_RGBA8,
16535     ctx_RGBA8_to_RGB565_BS,
16536     ctx_composite_RGB565_BS, ctx_setup_RGBA8,
16537   },
16538 #endif
16539 #if CTX_ENABLE_CMYKAF
16540   {
16541     CTX_FORMAT_CMYKAF, 5, 160, 4 * 5, 0, 0, CTX_FORMAT_CMYKAF,
16542     NULL, NULL, NULL, ctx_setup_CMYKAF,
16543   },
16544 #endif
16545 #if CTX_ENABLE_CMYKA8
16546   {
16547     CTX_FORMAT_CMYKA8, 5, 40, 4 * 5, 0, 0, CTX_FORMAT_CMYKAF,
16548     NULL, NULL, ctx_composite_CMYKA8, ctx_setup_CMYKAF,
16549   },
16550 #endif
16551 #if CTX_ENABLE_CMYK8
16552   {
16553     CTX_FORMAT_CMYK8, 5, 32, 4 * 5, 0, 0, CTX_FORMAT_CMYKAF,
16554     NULL, NULL, ctx_composite_CMYK8, ctx_setup_CMYKAF,
16555   },
16556 #endif
16557 #if CTX_ENABLE_YUV420
16558   {
16559     CTX_FORMAT_YUV420, 1, 8, 4, 0, 0, CTX_FORMAT_RGBA8,
16560     NULL, NULL, ctx_composite_convert, ctx_setup_RGBA8,
16561   },
16562 #endif
16563   {
16564     CTX_FORMAT_NONE
16565   }
16566 };
16567 
16568 
16569 CtxPixelFormatInfo *
ctx_pixel_format_info(CtxPixelFormat format)16570 ctx_pixel_format_info (CtxPixelFormat format)
16571 {
16572   for (unsigned int i = 0; ctx_pixel_formats[i].pixel_format; i++)
16573     {
16574       if (ctx_pixel_formats[i].pixel_format == format)
16575         {
16576           return &ctx_pixel_formats[i];
16577         }
16578     }
16579   return NULL;
16580 }
16581 
16582 #endif
16583 #if CTX_RASTERIZER
16584 #define CTX_AA_HALFSTEP2   (CTX_FULL_AA/2)
16585 #define CTX_AA_HALFSTEP    ((CTX_FULL_AA/2)+1)
16586 
16587 static void
16588 ctx_gradient_cache_prime (CtxRasterizer *rasterizer);
16589 
16590 static inline void
_ctx_setup_compositor(CtxRasterizer * rasterizer)16591 _ctx_setup_compositor (CtxRasterizer *rasterizer)
16592 {
16593   if (CTX_UNLIKELY (rasterizer->comp_op==0))
16594   {
16595     rasterizer->format->setup (rasterizer);
16596 #if CTX_GRADIENTS
16597 #if CTX_GRADIENT_CACHE
16598   switch (rasterizer->state->gstate.source_fill.type)
16599   {
16600     case CTX_SOURCE_LINEAR_GRADIENT:
16601     case CTX_SOURCE_RADIAL_GRADIENT:
16602       ctx_gradient_cache_prime (rasterizer);
16603       break;
16604     case CTX_SOURCE_TEXTURE:
16605 
16606       _ctx_matrix_multiply (&rasterizer->state->gstate.source_fill.transform,
16607                             &rasterizer->state->gstate.source_fill.set_transform,
16608                             &rasterizer->state->gstate.transform);
16609 
16610       ctx_matrix_invert (&rasterizer->state->gstate.source_fill.transform);
16611 
16612       if (!rasterizer->state->gstate.source_fill.texture.buffer->color_managed)
16613         _ctx_texture_prepare_color_management (rasterizer,
16614         rasterizer->state->gstate.source_fill.texture.buffer);
16615       break;
16616   }
16617 #endif
16618 #endif
16619   }
16620 }
16621 
16622 #define CTX_FULL_AA 15
16623 inline static void
ctx_rasterizer_apply_coverage(CtxRasterizer * rasterizer,uint8_t * dst,int x,uint8_t * coverage,int count)16624 ctx_rasterizer_apply_coverage (CtxRasterizer *rasterizer,
16625                                uint8_t * dst,
16626                                int       x,
16627                                uint8_t * coverage,
16628                                int       count)
16629 {
16630   if (CTX_UNLIKELY(rasterizer->format->apply_coverage))
16631     rasterizer->format->apply_coverage(rasterizer, dst, rasterizer->color, x, coverage, count);
16632   else
16633     /* it is faster to dispatch in this condition, than using a shared
16634      * direct trampoline
16635      */
16636     rasterizer->comp_op (rasterizer, dst, rasterizer->color, x, coverage, count);
16637 }
16638 
16639 static void
ctx_rasterizer_gradient_add_stop(CtxRasterizer * rasterizer,float pos,float * rgba)16640 ctx_rasterizer_gradient_add_stop (CtxRasterizer *rasterizer, float pos, float *rgba)
16641 {
16642   /* FIXME XXX we only have one gradient, but might need separate gradients
16643    * for fill/stroke !
16644    *
16645    */
16646   CtxGradient *gradient = &rasterizer->state->gradient;
16647   CtxGradientStop *stop = &gradient->stops[gradient->n_stops];
16648   stop->pos = pos;
16649   ctx_color_set_rgba (rasterizer->state, & (stop->color), rgba[0], rgba[1], rgba[2], rgba[3]);
16650   if (gradient->n_stops < 15) //we'll keep overwriting the last when out of stops
16651     { gradient->n_stops++; }
16652 }
16653 
ctx_rasterizer_add_point(CtxRasterizer * rasterizer,int x1,int y1)16654 static inline int ctx_rasterizer_add_point (CtxRasterizer *rasterizer, int x1, int y1)
16655 {
16656   CtxSegment entry = {CTX_EDGE, {{0},}};
16657   rasterizer->scan_min = ctx_mini (y1, rasterizer->scan_min);
16658   rasterizer->scan_max = ctx_maxi (y1, rasterizer->scan_max);
16659 
16660   rasterizer->col_min = ctx_mini (x1, rasterizer->col_min);
16661   rasterizer->col_max = ctx_maxi (x1, rasterizer->col_max);
16662 
16663   entry.data.s16[0]=rasterizer->inner_x;
16664   entry.data.s16[1]=rasterizer->inner_y;
16665 
16666   entry.data.s16[2]=x1;
16667   entry.data.s16[3]=y1;
16668 
16669   rasterizer->inner_x = x1;
16670   rasterizer->inner_y = y1;
16671 #if 0
16672   if (entry.data.s16[3] < entry.data.s16[1])
16673   {
16674     entry = ctx_segment_s16 (CTX_EDGE_FLIPPED,
16675                             entry.data.s16[2], entry.data.s16[3],
16676                             entry.data.s16[0], entry.data.s16[1]);
16677   }
16678 #endif
16679 
16680   return ctx_edgelist_add_single (&rasterizer->edge_list, (CtxEntry*)&entry);
16681 }
16682 
16683 #if 0
16684 #define CTX_SHAPE_CACHE_PRIME1   7853
16685 #define CTX_SHAPE_CACHE_PRIME2   4129
16686 #define CTX_SHAPE_CACHE_PRIME3   3371
16687 #define CTX_SHAPE_CACHE_PRIME4   4221
16688 #else
16689 #define CTX_SHAPE_CACHE_PRIME1   283
16690 #define CTX_SHAPE_CACHE_PRIME2   599
16691 #define CTX_SHAPE_CACHE_PRIME3   101
16692 #define CTX_SHAPE_CACHE_PRIME4   661
16693 #endif
16694 
16695 float ctx_shape_cache_rate = 0.0;
16696 #if CTX_SHAPE_CACHE
16697 int   _ctx_shape_cache_enabled = 1;
16698 
16699 //static CtxShapeCache ctx_cache = {{NULL,}, 0};
16700 
16701 static long ctx_shape_cache_hits   = 0;
16702 static long ctx_shape_cache_misses = 0;
16703 
16704 
16705 /* this returns the buffer to use for rendering, it always
16706    succeeds..
16707  */
ctx_shape_entry_find(CtxRasterizer * rasterizer,uint32_t hash,int width,int height)16708 static inline CtxShapeEntry *ctx_shape_entry_find (CtxRasterizer *rasterizer, uint32_t hash, int width, int height)
16709 {
16710   /* use both some high and some low bits  */
16711   int entry_no = ( (hash >> 10) ^ (hash & 1023) ) % CTX_SHAPE_CACHE_ENTRIES;
16712   int i;
16713   {
16714     static int i = 0;
16715     i++;
16716     if (i>1000)
16717       {
16718         ctx_shape_cache_rate = ctx_shape_cache_hits * 100.0  / (ctx_shape_cache_hits+ctx_shape_cache_misses);
16719         i = 0;
16720         ctx_shape_cache_hits = 0;
16721         ctx_shape_cache_misses = 0;
16722       }
16723   }
16724 // XXX : this 1 one is needed  to silence a false positive:
16725 // ==90718== Invalid write of size 1
16726 // ==90718==    at 0x1189EF: ctx_rasterizer_generate_coverage (ctx.h:4786)
16727 // ==90718==    by 0x118E57: ctx_rasterizer_rasterize_edges (ctx.h:4907)
16728 //
16729   int size = sizeof (CtxShapeEntry) + width * height + 1;
16730 
16731   i = entry_no;
16732   if (rasterizer->shape_cache.entries[i])
16733     {
16734       CtxShapeEntry *entry = rasterizer->shape_cache.entries[i];
16735       int old_size = sizeof (CtxShapeEntry) + width + height + 1;
16736       if (entry->hash == hash &&
16737           entry->width == width &&
16738           entry->height == height)
16739         {
16740           if (entry->uses < 1<<30)
16741             { entry->uses++; }
16742           ctx_shape_cache_hits ++;
16743           return entry;
16744         }
16745 
16746       if (old_size >= size)
16747       {
16748       }
16749       else
16750       {
16751         rasterizer->shape_cache.entries[i] = NULL;
16752         rasterizer->shape_cache.size -= entry->width * entry->height;
16753         rasterizer->shape_cache.size -= sizeof (CtxShapeEntry);
16754         free (entry);
16755         rasterizer->shape_cache.entries[i] = (CtxShapeEntry *) calloc (size, 1);
16756       }
16757     }
16758   else
16759     {
16760         rasterizer->shape_cache.entries[i] = (CtxShapeEntry *) calloc (size, 1);
16761     }
16762 
16763   ctx_shape_cache_misses ++;
16764   rasterizer->shape_cache.size              += size;
16765   rasterizer->shape_cache.entries[i]->hash   = hash;
16766   rasterizer->shape_cache.entries[i]->width  = width;
16767   rasterizer->shape_cache.entries[i]->height = height;
16768   rasterizer->shape_cache.entries[i]->uses = 0;
16769   return rasterizer->shape_cache.entries[i];
16770 }
16771 
16772 #endif
16773 
ctx_rasterizer_poly_to_hash(CtxRasterizer * rasterizer)16774 static uint32_t ctx_rasterizer_poly_to_hash (CtxRasterizer *rasterizer)
16775 {
16776   int x = 0;
16777   int y = 0;
16778 
16779   CtxSegment *entry = (CtxSegment*)&rasterizer->edge_list.entries[0];
16780 
16781   int ox = entry->data.s16[2];
16782   int oy = entry->data.s16[3];
16783   uint32_t hash = rasterizer->edge_list.count;
16784   hash = ox;//(ox % CTX_SUBDIV);
16785   hash *= CTX_SHAPE_CACHE_PRIME1;
16786   hash += oy; //(oy % CTX_RASTERIZER_AA);
16787   for (int i = 0; i < rasterizer->edge_list.count; i++)
16788     {
16789       CtxSegment *entry = &(((CtxSegment*)(rasterizer->edge_list.entries)))[i];
16790       x = entry->data.s16[2];
16791       y = entry->data.s16[3];
16792       int dx = x-ox;
16793       int dy = y-oy;
16794       ox = x;
16795       oy = y;
16796       hash *= CTX_SHAPE_CACHE_PRIME3;
16797       hash += dx;
16798       hash *= CTX_SHAPE_CACHE_PRIME4;
16799       hash += dy;
16800     }
16801   return hash;
16802 }
16803 
ctx_rasterizer_poly_to_edges(CtxRasterizer * rasterizer)16804 static uint32_t ctx_rasterizer_poly_to_edges (CtxRasterizer *rasterizer)
16805 {
16806 #if CTX_SHAPE_CACHE
16807   int x = 0;
16808   int y = 0;
16809 #endif
16810   int count = rasterizer->edge_list.count;
16811   if (CTX_UNLIKELY (count == 0))
16812      return 0;
16813   CtxSegment *entry = (CtxSegment*)&rasterizer->edge_list.entries[0];
16814 #if CTX_SHAPE_CACHE
16815 #if 1
16816   int ox = entry->data.s16[2];
16817   int oy = entry->data.s16[3];
16818 #endif
16819   uint32_t hash = rasterizer->edge_list.count;
16820   hash = (ox & CTX_SUBDIV);
16821   hash *= CTX_SHAPE_CACHE_PRIME1;
16822   hash += (oy & CTX_SUBDIV);
16823 #endif
16824   //CtxSegment *entry = &(((CtxSegment*)(rasterizer->edge_list.entries)))[0];
16825   for (int i = 0; i < count; i++)
16826     {
16827 #if CTX_SHAPE_CACHE
16828       x = entry->data.s16[2];
16829       y = entry->data.s16[3];
16830       int dx = x-ox;
16831       int dy = y-oy;
16832       ox = x;
16833       oy = y;
16834       hash *= CTX_SHAPE_CACHE_PRIME3;
16835       hash += dx;
16836       hash *= CTX_SHAPE_CACHE_PRIME4;
16837       hash += dy;
16838 #endif
16839 #if 1
16840       if (entry->data.s16[3] < entry->data.s16[1])
16841         {
16842           *entry = ctx_segment_s16 (CTX_EDGE_FLIPPED,
16843                             entry->data.s16[2], entry->data.s16[3],
16844                             entry->data.s16[0], entry->data.s16[1]);
16845         }
16846 #endif
16847       entry++;
16848     }
16849 #if CTX_SHAPE_CACHE
16850   return hash;
16851 #else
16852   return 0;
16853 #endif
16854 }
16855 
ctx_rasterizer_finish_shape(CtxRasterizer * rasterizer)16856 static inline void ctx_rasterizer_finish_shape (CtxRasterizer *rasterizer)
16857 {
16858   if (rasterizer->has_shape && rasterizer->has_prev)
16859     {
16860       ctx_rasterizer_line_to (rasterizer, rasterizer->first_x, rasterizer->first_y);
16861       rasterizer->has_prev = 0;
16862     }
16863 }
16864 
ctx_rasterizer_move_to(CtxRasterizer * rasterizer,float x,float y)16865 static inline void ctx_rasterizer_move_to (CtxRasterizer *rasterizer, float x, float y)
16866 {
16867   float tx = x; float ty = y;
16868   int aa = 15;//rasterizer->aa;
16869   rasterizer->x        = x;
16870   rasterizer->y        = y;
16871   rasterizer->first_x  = x;
16872   rasterizer->first_y  = y;
16873   rasterizer->has_prev = -1;
16874   if (rasterizer->uses_transforms)
16875     {
16876       _ctx_user_to_device (rasterizer->state, &tx, &ty);
16877     }
16878 
16879   tx = (tx - rasterizer->blit_x) * CTX_SUBDIV;
16880   ty = ty * aa;
16881 
16882   rasterizer->inner_x = tx;
16883   rasterizer->inner_y = ty;
16884 
16885   rasterizer->scan_min = ctx_mini (ty, rasterizer->scan_min);
16886   rasterizer->scan_max = ctx_maxi (ty, rasterizer->scan_max);
16887 
16888   rasterizer->col_min = ctx_mini (tx, rasterizer->col_min);
16889   rasterizer->col_max = ctx_maxi (tx, rasterizer->col_max);
16890 }
16891 
ctx_rasterizer_line_to(CtxRasterizer * rasterizer,float x,float y)16892 static inline void ctx_rasterizer_line_to (CtxRasterizer *rasterizer, float x, float y)
16893 {
16894   float tx = x;
16895   float ty = y;
16896   //float ox = rasterizer->x;
16897   //float oy = rasterizer->y;
16898   if (rasterizer->uses_transforms)
16899     {
16900       _ctx_user_to_device (rasterizer->state, &tx, &ty);
16901     }
16902   tx -= rasterizer->blit_x;
16903 #define MIN_Y -1000
16904 #define MAX_Y 1400
16905 
16906   ty = ctx_maxf (MIN_Y, ty);
16907   ty = ctx_minf (MAX_Y, ty);
16908 
16909   ctx_rasterizer_add_point (rasterizer, tx * CTX_SUBDIV, ty * CTX_FULL_AA);//rasterizer->aa);
16910 
16911   if (CTX_UNLIKELY(rasterizer->has_prev<=0))
16912     {
16913 #if 0
16914       if (rasterizer->uses_transforms)
16915       {
16916         // storing transformed would save some processing for a tiny
16917         // amount of runtime RAM XXX
16918         _ctx_user_to_device (rasterizer->state, &ox, &oy);
16919       }
16920 #endif
16921       //ox -= rasterizer->blit_x;
16922       //oy = ctx_maxf (oy, MIN_Y);
16923       //oy = ctx_minf (oy, MAX_Y);
16924       CtxSegment *entry = & ((CtxSegment*)rasterizer->edge_list.entries)[rasterizer->edge_list.count-1];
16925       //entry->data.s16[0] = ox * CTX_SUBDIV;
16926       //entry->data.s16[1] = oy * CTX_FULL_AA;
16927       entry->code = CTX_NEW_EDGE;
16928       rasterizer->has_prev = 1;
16929     }
16930   rasterizer->has_shape = 1;
16931   rasterizer->y         = y;
16932   rasterizer->x         = x;
16933 }
16934 
16935 
16936 CTX_INLINE static float
ctx_bezier_sample_1d(float x0,float x1,float x2,float x3,float dt)16937 ctx_bezier_sample_1d (float x0, float x1, float x2, float x3, float dt)
16938 {
16939   float ab   = ctx_lerpf (x0, x1, dt);
16940   float bc   = ctx_lerpf (x1, x2, dt);
16941   float cd   = ctx_lerpf (x2, x3, dt);
16942   float abbc = ctx_lerpf (ab, bc, dt);
16943   float bccd = ctx_lerpf (bc, cd, dt);
16944   return ctx_lerpf (abbc, bccd, dt);
16945 }
16946 
16947 CTX_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)16948 ctx_bezier_sample (float x0, float y0,
16949                    float x1, float y1,
16950                    float x2, float y2,
16951                    float x3, float y3,
16952                    float dt, float *x, float *y)
16953 {
16954   *x = ctx_bezier_sample_1d (x0, x1, x2, x3, dt);
16955   *y = ctx_bezier_sample_1d (y0, y1, y2, y3, dt);
16956 }
16957 
16958 static inline 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)16959 ctx_rasterizer_bezier_divide (CtxRasterizer *rasterizer,
16960                               float ox, float oy,
16961                               float x0, float y0,
16962                               float x1, float y1,
16963                               float x2, float y2,
16964                               float sx, float sy,
16965                               float ex, float ey,
16966                               float s,
16967                               float e,
16968                               int   iteration,
16969                               float tolerance)
16970 {
16971   float t = (s + e) * 0.5f;
16972   float x, y, lx, ly, dx, dy;
16973   ctx_bezier_sample (ox, oy, x0, y0, x1, y1, x2, y2, t, &x, &y);
16974   if (iteration)
16975     {
16976       lx = ctx_lerpf (sx, ex, t);
16977       ly = ctx_lerpf (sy, ey, t);
16978       dx = lx - x;
16979       dy = ly - y;
16980       if (CTX_UNLIKELY( (dx*dx+dy*dy) < tolerance))
16981         /* bailing - because for the mid-point straight line difference is
16982            tiny */
16983         { return; }
16984       dx = sx - ex;
16985       dy = ey - ey;
16986       if (CTX_UNLIKELY( (dx*dx+dy*dy) < tolerance))
16987         /* bailing on tiny segments */
16988         { return; }
16989     }
16990   if (iteration < 8)
16991   {
16992   ctx_rasterizer_bezier_divide (rasterizer, ox, oy, x0, y0, x1, y1, x2, y2,
16993                                 sx, sy, x, y, s, t, iteration + 1,
16994                                 tolerance);
16995   ctx_rasterizer_line_to (rasterizer, x, y);
16996   ctx_rasterizer_bezier_divide (rasterizer, ox, oy, x0, y0, x1, y1, x2, y2,
16997                                 x, y, ex, ey, t, e, iteration + 1,
16998                                 tolerance);
16999   }
17000 }
17001 
17002 static void
ctx_rasterizer_curve_to(CtxRasterizer * rasterizer,float x0,float y0,float x1,float y1,float x2,float y2)17003 ctx_rasterizer_curve_to (CtxRasterizer *rasterizer,
17004                          float x0, float y0,
17005                          float x1, float y1,
17006                          float x2, float y2)
17007 {
17008   //float tolerance =
17009   //  1.0f*(ctx_pow2 (rasterizer->state->gstate.transform.m[0][0]) +
17010   //  ctx_pow2 (rasterizer->state->gstate.transform.m[1][1]));
17011   float tolerance = ctx_matrix_get_scale (&rasterizer->state->gstate.transform);
17012   float ox = rasterizer->x;
17013   float oy = rasterizer->y;
17014   //tolerance *= tolerance;
17015   tolerance = 2.0/(tolerance*tolerance);
17016   ox = rasterizer->state->x;
17017   oy = rasterizer->state->y;
17018   //tolerance = 10.0/(tolerance*tolerance);
17019   //tolerance = 10.0f/tolerance;
17020 #if 0 // skipping this to preserve hash integrity
17021   if (tolerance == 1.0f || 1)
17022   {
17023   float maxx = ctx_maxf (x1,x2);
17024   maxx = ctx_maxf (maxx, ox);
17025   maxx = ctx_maxf (maxx, x0);
17026   float maxy = ctx_maxf (y1,y2);
17027   maxy = ctx_maxf (maxy, oy);
17028   maxy = ctx_maxf (maxy, y0);
17029   float minx = ctx_minf (x1,x2);
17030   minx = ctx_minf (minx, ox);
17031   minx = ctx_minf (minx, x0);
17032   float miny = ctx_minf (y1,y2);
17033   miny = ctx_minf (miny, oy);
17034   miny = ctx_minf (miny, y0);
17035 
17036   _ctx_user_to_device (rasterizer->state, &minx, &miny);
17037   _ctx_user_to_device (rasterizer->state, &maxx, &maxy);
17038 #if 1
17039     if(
17040         (minx > rasterizer->blit_x + rasterizer->blit_width) ||
17041         (miny > rasterizer->blit_y + rasterizer->blit_height) ||
17042         (maxx < rasterizer->blit_x) ||
17043         (maxy < rasterizer->blit_y) )
17044     {
17045     }
17046     else
17047 #endif
17048     {
17049       ctx_rasterizer_bezier_divide (rasterizer,
17050                                     ox, oy, x0, y0,
17051                                     x1, y1, x2, y2,
17052                                     ox, oy, x2, y2,
17053                                     0.0f, 1.0f, 0.0f, tolerance);
17054     }
17055   }
17056   else
17057 #endif
17058     {
17059       ctx_rasterizer_bezier_divide (rasterizer,
17060                                     ox, oy, x0, y0,
17061                                     x1, y1, x2, y2,
17062                                     ox, oy, x2, y2,
17063                                     0.0f, 1.0f, 0.0f, tolerance);
17064     }
17065   ctx_rasterizer_line_to (rasterizer, x2, y2);
17066 }
17067 
17068 static void
ctx_rasterizer_rel_move_to(CtxRasterizer * rasterizer,float x,float y)17069 ctx_rasterizer_rel_move_to (CtxRasterizer *rasterizer, float x, float y)
17070 {
17071   //if (CTX_UNLIKELY(x == 0.f && y == 0.f))
17072   //{ return; }
17073   x += rasterizer->x;
17074   y += rasterizer->y;
17075   ctx_rasterizer_move_to (rasterizer, x, y);
17076 }
17077 
17078 static void
ctx_rasterizer_rel_line_to(CtxRasterizer * rasterizer,float x,float y)17079 ctx_rasterizer_rel_line_to (CtxRasterizer *rasterizer, float x, float y)
17080 {
17081   //if (CTX_UNLIKELY(x== 0.f && y==0.f))
17082   //  { return; }
17083   x += rasterizer->x;
17084   y += rasterizer->y;
17085   ctx_rasterizer_line_to (rasterizer, x, y);
17086 }
17087 
17088 static void
ctx_rasterizer_rel_curve_to(CtxRasterizer * rasterizer,float x0,float y0,float x1,float y1,float x2,float y2)17089 ctx_rasterizer_rel_curve_to (CtxRasterizer *rasterizer,
17090                              float x0, float y0, float x1, float y1, float x2, float y2)
17091 {
17092   x0 += rasterizer->x;
17093   y0 += rasterizer->y;
17094   x1 += rasterizer->x;
17095   y1 += rasterizer->y;
17096   x2 += rasterizer->x;
17097   y2 += rasterizer->y;
17098   ctx_rasterizer_curve_to (rasterizer, x0, y0, x1, y1, x2, y2);
17099 }
17100 
17101 
17102 static int
ctx_rasterizer_find_texture(CtxRasterizer * rasterizer,const char * eid)17103 ctx_rasterizer_find_texture (CtxRasterizer *rasterizer,
17104                              const char *eid)
17105 {
17106   int no;
17107   for (no = 0; no < CTX_MAX_TEXTURES; no++)
17108   {
17109     if (rasterizer->texture_source->texture[no].data &&
17110         rasterizer->texture_source->texture[no].eid &&
17111         !strcmp (rasterizer->texture_source->texture[no].eid, eid))
17112       return no;
17113   }
17114   return -1;
17115 }
17116 
17117 static void
ctx_rasterizer_set_texture(CtxRasterizer * rasterizer,const char * eid,float x,float y)17118 ctx_rasterizer_set_texture (CtxRasterizer *rasterizer,
17119                             const char *eid,
17120                             float x,
17121                             float y)
17122 {
17123   int is_stroke = (rasterizer->state->source != 0);
17124   CtxSource *source = is_stroke && (rasterizer->state->gstate.source_stroke.type != CTX_SOURCE_INHERIT_FILL)?
17125                         &rasterizer->state->gstate.source_stroke:
17126                         &rasterizer->state->gstate.source_fill;
17127   rasterizer->state->source = 0;
17128 
17129   int no = ctx_rasterizer_find_texture (rasterizer, eid);
17130   if (no < 0 || no >= CTX_MAX_TEXTURES) { no = 0; }
17131   if (rasterizer->texture_source->texture[no].data == NULL)
17132     {
17133       fprintf (stderr, "ctx tex fail %p %s %i\n", rasterizer->texture_source, eid, no);
17134       return;
17135     }
17136   else
17137   {
17138     rasterizer->texture_source->texture[no].frame = rasterizer->texture_source->frame;
17139   }
17140   source->type = CTX_SOURCE_TEXTURE;
17141   source->texture.buffer = &rasterizer->texture_source->texture[no];
17142   ctx_matrix_identity (&source->set_transform);
17143   ctx_matrix_translate (&source->set_transform, x, y);
17144 }
17145 
17146 
ctx_rasterizer_define_texture(CtxRasterizer * rasterizer,const char * eid,int width,int height,int format,char unsigned * data)17147 static void ctx_rasterizer_define_texture (CtxRasterizer *rasterizer,
17148                                            const char *eid,
17149                                            int width,
17150                                            int height,
17151                                            int format,
17152                                            char unsigned *data)
17153 {
17154   _ctx_texture_lock (); // we're using the same texture_source from all threads, keeping allocaitons down
17155                         // need synchronizing (it could be better to do a pre-pass)
17156   ctx_texture_init (rasterizer->texture_source,
17157                     eid,
17158                     width,
17159                     height,
17160                     ctx_pixel_format_get_stride ((CtxPixelFormat)format, width),
17161                     (CtxPixelFormat)format,
17162 #if CTX_ENABLE_CM
17163                     (void*)rasterizer->state->gstate.texture_space,
17164 #else
17165                     NULL,
17166 #endif
17167                     data,
17168                     ctx_buffer_pixels_free, (void*)23);
17169                     /*  when userdata for ctx_buffer_pixels_free is 23, texture_init dups the data on
17170                      *  use
17171                      */
17172 
17173   ctx_rasterizer_set_texture (rasterizer, eid, 0.0, 0.0);
17174   _ctx_texture_unlock ();
17175 }
17176 
17177 
ctx_compare_edges(const void * ap,const void * bp)17178 CTX_INLINE static int ctx_compare_edges (const void *ap, const void *bp)
17179 {
17180   const CtxSegment *a = (const CtxSegment *) ap;
17181   const CtxSegment *b = (const CtxSegment *) bp;
17182   return a->data.s16[1] - b->data.s16[1];
17183 }
17184 
ctx_edge_qsort_partition(CtxSegment * A,int low,int high)17185 CTX_INLINE static int ctx_edge_qsort_partition (CtxSegment *A, int low, int high)
17186 {
17187   CtxSegment pivot = A[ (high+low) /2];
17188   int i = low;
17189   int j = high;
17190   while (i <= j)
17191     {
17192       while (ctx_compare_edges (&A[i], &pivot) < 0) { i ++; }
17193       while (ctx_compare_edges (&pivot, &A[j]) < 0) { j --; }
17194       if (i <= j)
17195         {
17196           CtxSegment tmp = A[i];
17197           A[i] = A[j];
17198           A[j] = tmp;
17199           i++;
17200           j--;
17201         }
17202     }
17203   return i;
17204 }
17205 
ctx_edge_qsort(CtxSegment * entries,int low,int high)17206 static inline void ctx_edge_qsort (CtxSegment *entries, int low, int high)
17207 {
17208   {
17209     int p = ctx_edge_qsort_partition (entries, low, high);
17210     if (low < p -1 )
17211       { ctx_edge_qsort (entries, low, p - 1); }
17212     if (low < high)
17213       { ctx_edge_qsort (entries, p, high); }
17214   }
17215 }
17216 
ctx_rasterizer_sort_edges(CtxRasterizer * rasterizer)17217 static CTX_INLINE void ctx_rasterizer_sort_edges (CtxRasterizer *rasterizer)
17218 {
17219   ctx_edge_qsort ((CtxSegment*)& (rasterizer->edge_list.entries[0]), 0, rasterizer->edge_list.count-1);
17220 }
17221 
ctx_rasterizer_discard_edges(CtxRasterizer * rasterizer)17222 static inline void ctx_rasterizer_discard_edges (CtxRasterizer *rasterizer)
17223 {
17224   int scanline = rasterizer->scanline;
17225   int next_scanline = rasterizer->scanline + CTX_FULL_AA;
17226   int limit3 = CTX_RASTERIZER_AA_SLOPE_LIMIT3;
17227   //if (rasterizer->fast_aa)
17228     limit3 = CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA;
17229   CtxSegment *segments = &((CtxSegment*)(rasterizer->edge_list.entries))[0];
17230   int *edges = rasterizer->edges;
17231   for (int i = 0; i < rasterizer->active_edges; i++)
17232     {
17233       CtxSegment *segment = segments + edges[i];
17234       int edge_end = segment->data.s16[3]-1;
17235       if (edge_end < scanline)
17236         {
17237 
17238           int dx_dy = abs(segment->delta);
17239           rasterizer->needs_aa3  -= (dx_dy > limit3);
17240           rasterizer->needs_aa5  -= (dx_dy > CTX_RASTERIZER_AA_SLOPE_LIMIT5);
17241           rasterizer->needs_aa15 -= (dx_dy > CTX_RASTERIZER_AA_SLOPE_LIMIT15);
17242           rasterizer->edges[i] = rasterizer->edges[rasterizer->active_edges-1];
17243           rasterizer->active_edges--;
17244           i--;
17245         }
17246       else if (edge_end < next_scanline)
17247         rasterizer->ending_edges++;
17248     }
17249 #if 0
17250   // we should - but for 99% of the cases we do not need to, so we skip it
17251   for (int i = 0; i < rasterizer->pending_edges; i++)
17252     {
17253       int edge_end = ((CtxSegment*)(rasterizer->edge_list.entries))[rasterizer->edges[CTX_MAX_EDGES-1-i]].data.s16[3]-1;
17254       if (edge_end < scanline + CTX_FULL_AA)
17255         rasterizer->ending_edges++;
17256     }
17257 #endif
17258 }
17259 
ctx_rasterizer_increment_edges(CtxRasterizer * rasterizer,int count)17260 inline static void ctx_rasterizer_increment_edges (CtxRasterizer *rasterizer, int count)
17261 {
17262   rasterizer->scanline += count;
17263   CtxSegment *segments = &((CtxSegment*)(rasterizer->edge_list.entries))[0];
17264   for (int i = 0; i < rasterizer->active_edges; i++)
17265     {
17266       CtxSegment *segment = segments + rasterizer->edges[i];
17267       segment->val += segment->delta * count;
17268     }
17269   for (int i = 0; i < rasterizer->pending_edges; i++)
17270     {
17271       CtxSegment *segment = segments + rasterizer->edges[CTX_MAX_EDGES-1-i];
17272       segment->val += segment->delta * count;
17273     }
17274 }
17275 
17276 /* feeds up to rasterizer->scanline,
17277    keeps a pending buffer of edges - that encompass
17278    the full incoming scanline,
17279    feed until the start of the scanline and check for need for aa
17280    in all of pending + active edges, then
17281    again feed_edges until middle of scanline if doing non-AA
17282    or directly render when doing AA
17283 */
ctx_edge2_insertion_sort(CtxSegment * segments,int * entries,int count)17284 CTX_INLINE static void ctx_edge2_insertion_sort (CtxSegment *segments, int *entries, int count)
17285 {
17286   for(int i=1; i<count; i++)
17287    {
17288      int temp = entries[i];
17289      int j = i-1;
17290      while (j >= 0 && segments[temp].val - segments[entries[j]].val < 0)
17291      {
17292        entries[j+1] = entries[j];
17293        j--;
17294      }
17295      entries[j+1] = temp;
17296    }
17297 }
17298 
ctx_edge2_compare2(CtxSegment * segments,int a,int b)17299 CTX_INLINE static int ctx_edge2_compare2 (CtxSegment *segments, int a, int b)
17300 {
17301   CtxSegment *seg_a = &segments[a];
17302   CtxSegment *seg_b = &segments[b];
17303   int minval_a = ctx_mini (seg_a->val - seg_a->delta * CTX_AA_HALFSTEP2, seg_a->val + seg_a->delta * CTX_AA_HALFSTEP);
17304   int minval_b = ctx_mini (seg_b->val - seg_b->delta * CTX_AA_HALFSTEP2, seg_b->val + seg_b->delta * CTX_AA_HALFSTEP);
17305   return minval_a - minval_b;
17306 }
17307 
ctx_edge2_insertion_sort2(CtxSegment * segments,int * entries,int count)17308 CTX_INLINE static void ctx_edge2_insertion_sort2 (CtxSegment *segments, int *entries, int count)
17309 {
17310   for(int i=1; i<count; i++)
17311    {
17312      int temp = entries[i];
17313      int j = i-1;
17314      while (j >= 0 && ctx_edge2_compare2 (segments, temp, entries[j]) < 0)
17315      {
17316        entries[j+1] = entries[j];
17317        j--;
17318      }
17319      entries[j+1] = temp;
17320    }
17321 }
17322 
ctx_rasterizer_feed_edges(CtxRasterizer * rasterizer,int apply2_sort)17323 inline static void ctx_rasterizer_feed_edges (CtxRasterizer *rasterizer, int apply2_sort)
17324 {
17325   int miny;
17326   CtxSegment *entries = (CtxSegment*)&rasterizer->edge_list.entries[0];
17327   rasterizer->horizontal_edges = 0;
17328   rasterizer->ending_edges = 0;
17329   for (int i = 0; i < rasterizer->pending_edges; i++)
17330     {
17331       if (entries[rasterizer->edges[CTX_MAX_EDGES-1-i]].data.s16[1] - 1 <= rasterizer->scanline)
17332         {
17333           if (CTX_LIKELY(rasterizer->active_edges < CTX_MAX_EDGES-2))
17334             {
17335               int no = rasterizer->active_edges;
17336               rasterizer->active_edges++;
17337               rasterizer->edges[no] = rasterizer->edges[CTX_MAX_EDGES-1-i];
17338               rasterizer->edges[CTX_MAX_EDGES-1-i] =
17339                 rasterizer->edges[CTX_MAX_EDGES-1-rasterizer->pending_edges + 1];
17340               rasterizer->pending_edges--;
17341               i--;
17342             }
17343         }
17344     }
17345   int limit3 = CTX_RASTERIZER_AA_SLOPE_LIMIT3;
17346   //if (rasterizer->fast_aa)
17347     limit3 = CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA;
17348   int scanline = rasterizer->scanline;
17349   int next_scanline = scanline + CTX_FULL_AA;
17350   int edge_pos = rasterizer->edge_pos;
17351   int edge_count = rasterizer->edge_list.count;
17352   int *edges = rasterizer->edges;
17353   while ((edge_pos < edge_count &&
17354          (miny=entries[edge_pos].data.s16[1]-1)  <= next_scanline))
17355     {
17356       int maxy=entries[edge_pos].data.s16[3]-1;
17357       if (rasterizer->active_edges < CTX_MAX_EDGES-2 &&
17358           maxy >= scanline)
17359         {
17360           int dy = (entries[edge_pos].data.s16[3] - 1 - miny);
17361           if (dy)
17362             {
17363               int yd = scanline - miny;
17364               int no = rasterizer->active_edges;
17365               rasterizer->active_edges++;
17366               int index = edges[no] = edge_pos;
17367               int x0 = entries[index].data.s16[0];
17368               int x1 = entries[index].data.s16[2];
17369               int dx_dy = CTX_RASTERIZER_EDGE_MULTIPLIER * (x1 - x0) / dy;
17370               entries[index].delta = dx_dy;
17371               entries[index].val = x0 * CTX_RASTERIZER_EDGE_MULTIPLIER +
17372                                          (yd * dx_dy);
17373 
17374               {
17375                 int abs_dx_dy = abs(dx_dy);
17376                 rasterizer->needs_aa3  += (abs_dx_dy > limit3);
17377                 rasterizer->needs_aa5  += (abs_dx_dy > CTX_RASTERIZER_AA_SLOPE_LIMIT5);
17378                 rasterizer->needs_aa15 += (abs_dx_dy > CTX_RASTERIZER_AA_SLOPE_LIMIT15);
17379               }
17380 
17381               if (miny > scanline)
17382                 {
17383                   /* it is a pending edge - we add it to the end of the array
17384                      and keep a different count for items stored here, like
17385                      a heap and stack growing against each other
17386                   */
17387                   if (rasterizer->pending_edges < CTX_MAX_PENDING-1)
17388                   {
17389                     edges[CTX_MAX_EDGES-1-rasterizer->pending_edges] =
17390                     rasterizer->edges[no];
17391                     rasterizer->pending_edges++;
17392                     rasterizer->active_edges--;
17393                   }
17394                 }
17395             }
17396           else
17397             rasterizer->horizontal_edges ++;
17398         }
17399       edge_pos++;
17400     }
17401     rasterizer->edge_pos = edge_pos;
17402     ctx_rasterizer_discard_edges (rasterizer);
17403     if (apply2_sort)
17404       ctx_edge2_insertion_sort2 ((CtxSegment*)rasterizer->edge_list.entries, rasterizer->edges, rasterizer->active_edges);
17405     else
17406       ctx_edge2_insertion_sort ((CtxSegment*)rasterizer->edge_list.entries, rasterizer->edges, rasterizer->active_edges);
17407 }
17408 
17409 
17410 #undef CTX_CMPSWP
17411 
ctx_coverage_post_process(CtxRasterizer * rasterizer,int minx,int maxx,uint8_t * coverage,int * first_col,int * last_col)17412 static inline void ctx_coverage_post_process (CtxRasterizer *rasterizer, int minx, int maxx, uint8_t *coverage, int *first_col, int *last_col)
17413 {
17414   int scanline     = rasterizer->scanline - CTX_FULL_AA; // we do the
17415                                                  // post process after
17416                                                  // coverage generation icnrement
17417 #if CTX_ENABLE_SHADOW_BLUR
17418   if (CTX_UNLIKELY(rasterizer->in_shadow))
17419   {
17420     float radius = rasterizer->state->gstate.shadow_blur;
17421     int dim = 2 * radius + 1;
17422     if (CTX_UNLIKELY (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM))
17423       dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
17424     {
17425       uint16_t temp[maxx-minx+1];
17426       memset (temp, 0, sizeof (temp));
17427       for (int x = dim/2; x < maxx-minx + 1 - dim/2; x ++)
17428         for (int u = 0; u < dim; u ++)
17429         {
17430           temp[x] += coverage[minx+x+u-dim/2] * rasterizer->kernel[u] * 256;
17431         }
17432       for (int x = 0; x < maxx-minx + 1; x ++)
17433         coverage[minx+x] = temp[x] >> 8;
17434     }
17435   }
17436 #endif
17437 
17438 #if CTX_ENABLE_CLIP
17439   if (CTX_UNLIKELY(rasterizer->clip_buffer &&  !rasterizer->clip_rectangle))
17440   {
17441     /* perhaps not working right for clear? */
17442     int y = scanline / CTX_FULL_AA;//rasterizer->aa;
17443     uint8_t *clip_line = &((uint8_t*)(rasterizer->clip_buffer->data))[rasterizer->blit_width*y];
17444     // XXX SIMD candidate
17445     for (int x = minx; x <= maxx; x ++)
17446     {
17447 #if CTX_1BIT_CLIP
17448        coverage[x] = (coverage[x] * ((clip_line[x/8]&(1<<(x&8)))?255:0))/255;
17449 #else
17450        coverage[x] = (255 + coverage[x] * clip_line[x-rasterizer->blit_x])>>8;
17451 #endif
17452     }
17453   }
17454   if (CTX_UNLIKELY(rasterizer->aa == 1))
17455   {
17456     for (int x = minx; x <= maxx; x ++)
17457      coverage[x] = coverage[x] > 127?255:0;
17458   }
17459 #endif
17460 }
17461 
17462 #define CTX_EDGE(no)      entries[edges[no]]
17463 #define CTX_EDGE_YMIN     (segment->data.s16[1]-1)
17464 
17465 #define UPDATE_PARITY \
17466         { \
17467           if (scanline!=CTX_EDGE_YMIN)\
17468             parity = (is_winding)? \
17469              parity + -1+2*(segment->code == CTX_EDGE_FLIPPED) : \
17470                         1 - parity;\
17471         }
17472 
17473 inline static void
ctx_rasterizer_generate_coverage(CtxRasterizer * rasterizer,int minx,int maxx,uint8_t * coverage,int is_winding,const uint8_t aa_factor)17474 ctx_rasterizer_generate_coverage (CtxRasterizer *rasterizer,
17475                                   int            minx,
17476                                   int            maxx,
17477                                   uint8_t       *coverage,
17478                                   int            is_winding,
17479                                   const uint8_t  aa_factor)
17480 {
17481   CtxSegment *entries      = (CtxSegment*)(&rasterizer->edge_list.entries[0]);
17482   int        *edges        = rasterizer->edges;
17483   int         scanline     = rasterizer->scanline;
17484   int         active_edges = rasterizer->active_edges;
17485   int         parity       = 0;
17486   coverage -= minx;
17487   uint8_t fraction = 255/aa_factor;
17488   for (int t = 0; t < active_edges -1;t++)
17489     {
17490       CtxSegment *segment = &entries[edges[t]];
17491       UPDATE_PARITY;
17492 
17493       if (parity)
17494         {
17495           CtxSegment *next_segment = &entries[edges[t+1]];
17496           const int x0 = segment->val;
17497           const int x1 = next_segment->val;
17498           int graystart = x0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
17499           int grayend   = x1 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
17500           int first     = graystart >> 8;
17501           int last      = grayend   >> 8;
17502 
17503           if (first < minx)
17504           {
17505             first = minx;
17506             graystart=0;
17507           }
17508           if (last > maxx)
17509           {
17510             last = maxx;
17511             grayend=255;
17512           }
17513 
17514           graystart = fraction- (graystart&0xff)/aa_factor;
17515           grayend   = (grayend & 0xff) / aa_factor;
17516 
17517           if (first < last)
17518           {
17519               coverage[first] += graystart;
17520               for (int x = first + 1; x < last; x++)
17521                 coverage[x]  += fraction;
17522               coverage[last] += grayend;
17523           }
17524           else if (first == last)
17525             coverage[first] += (graystart-(fraction-grayend));
17526         }
17527    }
17528 }
17529 
17530 inline static void
ctx_rasterizer_generate_coverage_set(CtxRasterizer * rasterizer,int minx,int maxx,uint8_t * coverage,int is_winding)17531 ctx_rasterizer_generate_coverage_set (CtxRasterizer *rasterizer,
17532                                       int            minx,
17533                                       int            maxx,
17534                                       uint8_t       *coverage,
17535                                       int            is_winding)
17536 {
17537   CtxSegment *entries = (CtxSegment*)(&rasterizer->edge_list.entries[0]);
17538   int      *edges = rasterizer->edges;
17539   int scanline     = rasterizer->scanline;
17540   int active_edges = rasterizer->active_edges;
17541   int parity = 0;
17542   coverage -= minx;
17543   for (int t = 0; t < active_edges -1;t++)
17544     {
17545       CtxSegment *segment = &entries[edges[t]];
17546       UPDATE_PARITY;
17547 
17548       if (parity)
17549         {
17550           CtxSegment *next_segment = &entries[edges[t+1]];
17551           const int x0        = segment->val;
17552           const int x1        = next_segment->val;
17553           int graystart = x0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
17554           int grayend   = x1 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
17555           int first     = graystart >> 8;
17556           int last      = grayend   >> 8;
17557 
17558           if (first < minx)
17559           {
17560             first = minx;
17561             graystart=0;
17562           }
17563           if (last > maxx)
17564           {
17565             last = maxx;
17566             grayend=255;
17567           }
17568 
17569           graystart = 255 - (graystart&0xff);
17570           grayend   = (grayend & 0xff);
17571 
17572           if (first < last)
17573           {
17574               coverage[first] += graystart;
17575 #if 0
17576               for (int x = first + 1; x < last; x++)
17577                 coverage[x] = 255;
17578 #else
17579               memset(&coverage[first+1], 255, last-(first+1));
17580 #endif
17581               coverage[last]  += grayend;
17582           }
17583           else if (first == last)
17584             coverage[first] += (graystart-(255-grayend));
17585         }
17586    }
17587 }
17588 
17589 static inline uint32_t
ctx_over_RGBA8(uint32_t dst,uint32_t src,uint32_t cov)17590 ctx_over_RGBA8 (uint32_t dst, uint32_t src, uint32_t cov)
17591 {
17592   uint32_t si_ga = (src & 0xff00ff00) >> 8;
17593   uint32_t si_rb = src & 0x00ff00ff;
17594   uint32_t si_a  = si_ga >> 16;
17595   uint32_t rcov  = ((255+si_a * cov)>>8)^255;
17596   uint32_t di_ga = ( dst & 0xff00ff00) >> 8;
17597   uint32_t di_rb = dst & 0x00ff00ff;
17598   return
17599      ((((si_rb * cov) + 0xff00ff + (di_rb * rcov)) & 0xff00ff00) >> 8)  |
17600       (((si_ga * cov) + 0xff00ff + (di_ga * rcov)) & 0xff00ff00);
17601 }
17602 
17603 
17604 static inline uint32_t
ctx_over_RGBA8_full(uint32_t dst,uint32_t src)17605 ctx_over_RGBA8_full (uint32_t dst, uint32_t src)
17606 {
17607   uint32_t si_ga = (src & 0xff00ff00) >> 8;
17608   uint32_t si_rb = src & 0x00ff00ff;
17609   uint32_t si_a  = si_ga >> 16;
17610   uint32_t rcov  = si_a^255;
17611   uint32_t di_ga = (dst & 0xff00ff00) >> 8;
17612   uint32_t di_rb = dst & 0x00ff00ff;
17613   return
17614      ((((si_rb * 255) + 0xff00ff + (di_rb * rcov)) & 0xff00ff00) >> 8)  |
17615       (((si_ga * 255) + 0xff00ff + (di_ga * rcov)) & 0xff00ff00);
17616 }
17617 
17618 static inline uint32_t
ctx_over_RGBA8_2(uint32_t dst,uint32_t si_ga,uint32_t si_rb,uint32_t si_a,uint32_t cov)17619 ctx_over_RGBA8_2 (uint32_t dst, uint32_t si_ga, uint32_t si_rb, uint32_t si_a, uint32_t cov)
17620 {
17621   uint32_t rcov  = ((si_a * cov)/255)^255;
17622   uint32_t di_ga = (dst & 0xff00ff00) >> 8;
17623   uint32_t di_rb = dst & 0x00ff00ff;
17624   return
17625      ((((si_rb * cov) + 0xff00ff + (di_rb * rcov)) & 0xff00ff00) >> 8)  |
17626       (((si_ga * cov) + 0xff00ff + (di_ga * rcov)) & 0xff00ff00);
17627 }
17628 
17629 static inline uint32_t
ctx_over_RGBA8_full_2(uint32_t dst,uint32_t si_ga_full,uint32_t si_rb_full,uint32_t si_a)17630 ctx_over_RGBA8_full_2 (uint32_t dst, uint32_t si_ga_full, uint32_t si_rb_full, uint32_t si_a)
17631 {
17632   uint32_t rcov = si_a^255;
17633   uint32_t di_ga = ( dst & 0xff00ff00) >> 8;
17634   uint32_t di_rb = dst & 0x00ff00ff;
17635   return
17636      ((((si_rb_full) + (di_rb * rcov)) & 0xff00ff00) >> 8)  |
17637       (((si_ga_full) + (di_ga * rcov)) & 0xff00ff00);
17638 }
17639 
ctx_span_set_color(uint32_t * dst_pix,uint32_t val,int count)17640 static inline void ctx_span_set_color (uint32_t *dst_pix, uint32_t val, int count)
17641 {
17642   if (count>0)
17643   while(count--)
17644     *dst_pix++=val;
17645 }
17646 
17647 inline static void
ctx_rasterizer_generate_coverage_apply(CtxRasterizer * rasterizer,int minx,int maxx,uint8_t * coverage,int is_winding,CtxCovPath comp)17648 ctx_rasterizer_generate_coverage_apply (CtxRasterizer *rasterizer,
17649                                         int            minx,
17650                                         int            maxx,
17651                                         uint8_t       *coverage,
17652                                         int            is_winding,
17653                                         CtxCovPath     comp)
17654 {
17655   CtxSegment *entries = (CtxSegment*)(&rasterizer->edge_list.entries[0]);
17656   int *edges  = rasterizer->edges;
17657   int scanline        = rasterizer->scanline;
17658   const int bpp             = rasterizer->format->bpp/8;
17659   int active_edges    = rasterizer->active_edges;
17660   int parity        = 0;
17661   const uint32_t src_pix    = ((uint32_t*)rasterizer->color)[0];
17662   const uint32_t si_ga = ((uint32_t*)rasterizer->color)[1];
17663   const uint32_t si_rb = ((uint32_t*)rasterizer->color)[2];
17664   const uint32_t si_ga_full = ((uint32_t*)rasterizer->color)[3];
17665   const uint32_t si_rb_full = ((uint32_t*)rasterizer->color)[4];
17666   const uint32_t si_a  = si_ga >> 16;
17667 
17668   uint8_t *dst = ( (uint8_t *) rasterizer->buf) +
17669          (rasterizer->blit_stride * (scanline / CTX_FULL_AA));
17670   int accumulator_x=0;
17671   uint8_t accumulated = 0;
17672   for (int t = 0; t < active_edges -1;t++)
17673     {
17674       CtxSegment *segment = &entries[edges[t]];
17675       UPDATE_PARITY;
17676 
17677        if (parity)
17678         {
17679           CtxSegment   *next_segment = &entries[edges[t+1]];
17680           const int x0        = segment->val;
17681           const int x1        = next_segment->val;
17682           int graystart = x0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
17683           int grayend   = x1 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
17684           int first     = graystart >> 8;
17685           int last      = grayend   >> 8;
17686 
17687           if (first < minx)
17688           {
17689             first = minx;
17690             graystart=0;
17691           }
17692           if (last > maxx)
17693           {
17694             last = maxx;
17695             grayend=255;
17696           }
17697 
17698           graystart = 255 - (graystart&0xff);
17699           grayend   = (grayend & 0xff);
17700 
17701           if (accumulated)
17702           {
17703             if (accumulator_x == first)
17704             {
17705               graystart += accumulated;
17706             }
17707             else
17708             {
17709               uint32_t* dst_pix = (uint32_t*)(&dst[(accumulator_x*bpp)]);
17710               switch (comp)
17711               {
17712                 case CTX_COV_PATH_COPY:
17713                   *dst_pix = ctx_lerp_RGBA8_2(*dst_pix, si_ga, si_rb, accumulated);
17714                   break;
17715                 case CTX_COV_PATH_OVER:
17716                   *dst_pix = ctx_over_RGBA8_2(*dst_pix, si_ga, si_rb, si_a, accumulated);
17717                   break;
17718                 default:
17719                   ctx_rasterizer_apply_coverage (rasterizer, (uint8_t*)dst_pix, accumulator_x, &accumulated, 1);
17720               }
17721             }
17722             accumulated = 0;
17723           }
17724 
17725           if (first < last)
17726           {
17727             switch (comp)
17728             {
17729               case CTX_COV_PATH_COPY:
17730             {
17731               uint32_t* dst_pix = (uint32_t*)(&dst[(first *bpp)]);
17732               *dst_pix = ctx_lerp_RGBA8_2(*dst_pix, si_ga, si_rb, graystart);
17733 
17734               dst_pix++;
17735               ctx_span_set_color (dst_pix, src_pix, last - first - 1);
17736 #if 0
17737               for (int i = first + 1; i < last; i++)
17738               {
17739                 *dst_pix = src_pix;
17740                 dst_pix++;
17741               }
17742 #endif
17743             }
17744             break;
17745               case CTX_COV_PATH_OVER:
17746             {
17747               uint32_t* dst_pix = (uint32_t*)(&dst[(first *bpp)]);
17748               *dst_pix = ctx_over_RGBA8_2(*dst_pix, si_ga, si_rb, si_a, graystart);
17749               dst_pix++;
17750               for (int i = first + 1; i < last; i++)
17751               {
17752                 *dst_pix = ctx_over_RGBA8_full_2(*dst_pix, si_ga_full, si_rb_full, si_a);
17753                 dst_pix++;
17754               }
17755             }
17756             break;
17757               case CTX_COV_PATH_COPY_FRAGMENT:
17758             {
17759               float u0 = 0; float v0 = 0;
17760               float ud = 0; float vd = 0;
17761               uint8_t gs = graystart;
17762               ctx_RGBA8_source_copy_normal_fragment (rasterizer, &dst[(first * bpp)], NULL, first, &gs, 1);
17763               ctx_init_uv (rasterizer, first+1, last-first-1, &u0, &v0, &ud, &vd);
17764               rasterizer->fragment (rasterizer, u0, v0, &dst[(first+1)*bpp], last-first-1, ud, vd);
17765             }
17766             break;
17767               case CTX_COV_PATH_OVER_FRAGMENT:
17768             {
17769               uint8_t gs = graystart;
17770               ctx_RGBA8_source_over_normal_fragment (rasterizer, &dst[(first * bpp)], NULL, first, &gs, 1);
17771               ctx_RGBA8_source_over_normal_full_cov_fragment (rasterizer,
17772                                                      &dst[((first+1)*bpp)], NULL, first + 1, NULL, last-first-1);
17773             }
17774             break;
17775               default:
17776             {
17777               uint8_t opaque[last-first];
17778               memset (opaque, 255, sizeof (opaque));
17779               opaque[0] = graystart;
17780               ctx_rasterizer_apply_coverage (rasterizer,
17781                                              &dst[(first * bpp)], first, opaque, last-first);
17782             }
17783             }
17784             accumulated = grayend;
17785           }
17786           else if (first == last)
17787           {
17788             accumulated = (graystart-(255-grayend));
17789           }
17790           accumulator_x = last;
17791         }
17792    }
17793 
17794    if (accumulated)
17795    {
17796      uint32_t* dst_pix = (uint32_t*)(&dst[(accumulator_x*bpp)]);
17797      switch (comp)
17798      {
17799        case CTX_COV_PATH_COPY:
17800          *dst_pix = ctx_lerp_RGBA8_2(*dst_pix, si_ga, si_rb, accumulated);
17801          break;
17802        case CTX_COV_PATH_OVER:
17803          *dst_pix = ctx_over_RGBA8_2(*dst_pix, si_ga, si_rb, si_a, accumulated);
17804          break;
17805        default:
17806          ctx_rasterizer_apply_coverage (rasterizer, (uint8_t*)dst_pix, accumulator_x, &accumulated, 1);
17807      }
17808    }
17809 }
17810 
ctx_rasterizer_is_simple(CtxRasterizer * rasterizer)17811 inline static int ctx_rasterizer_is_simple (CtxRasterizer *rasterizer)
17812 {
17813   if (rasterizer->fast_aa == 0 ||
17814       rasterizer->ending_edges ||
17815       rasterizer->pending_edges)
17816    return 0;
17817   int *edges  = rasterizer->edges;
17818   CtxSegment *segments = &((CtxSegment*)(rasterizer->edge_list.entries))[0];
17819 
17820   int active_edges = rasterizer->active_edges;
17821   for (int t = 0; t < active_edges -1;t++)
17822     {
17823       CtxSegment *segment0 = segments + edges[t];
17824       CtxSegment *segment1 = segments + edges[t+1];
17825       const int delta0    = segment0->delta;
17826       const int delta1    = segment1->delta;
17827       const int x0        = segment0->val;
17828       const int x1        = segment1->val;
17829       int x0_end   = x0 + delta0 * CTX_AA_HALFSTEP;
17830       int x1_end   = x1 + delta1 * CTX_AA_HALFSTEP;
17831       int x0_start = x0 - delta0 * CTX_AA_HALFSTEP2;
17832       int x1_start = x1 - delta1 * CTX_AA_HALFSTEP2;
17833       if (x1_end < x0_end   ||
17834           x1_start < x0_end ||
17835           x1_end < x0_start
17836          )
17837          return 0;
17838     }
17839   return 1;
17840 }
17841 
17842 
17843 inline static void
ctx_rasterizer_generate_coverage_set2(CtxRasterizer * rasterizer,int minx,int maxx,uint8_t * coverage,int is_winding)17844 ctx_rasterizer_generate_coverage_set2 (CtxRasterizer *rasterizer,
17845                                          int            minx,
17846                                          int            maxx,
17847                                          uint8_t       *coverage,
17848                                          int            is_winding)
17849 {
17850   CtxSegment *entries = (CtxSegment*)(&rasterizer->edge_list.entries[0]);
17851   int *edges  = rasterizer->edges;
17852   int scanline        = rasterizer->scanline;
17853   int active_edges    = rasterizer->active_edges;
17854   int parity        = 0;
17855 
17856   coverage -= minx;
17857 
17858   const int minx_ = minx * CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV;
17859   const int maxx_ = maxx * CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV;
17860 
17861   for (int t = 0; t < active_edges -1;t++)
17862     {
17863       CtxSegment   *segment = &entries[edges[t]];
17864       UPDATE_PARITY;
17865 
17866        if (parity)
17867         {
17868           CtxSegment   *next_segment = &entries[edges[t+1]];
17869           const int x0        = segment->val;
17870           const int x1        = next_segment->val;
17871           const int delta0    = segment->delta;
17872           const int delta1    = next_segment->delta;
17873 
17874           int x0_start = x0 - delta0 * CTX_AA_HALFSTEP2;
17875           int x1_start = x1 - delta1 * CTX_AA_HALFSTEP2;
17876           int x0_end   = x0 + delta0 * CTX_AA_HALFSTEP;
17877           int x1_end   = x1 + delta1 * CTX_AA_HALFSTEP;
17878 
17879           int graystart = x0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
17880           int grayend   = x1 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
17881           int first     = graystart >> 8;
17882           int last      = grayend   >> 8;
17883 
17884           first = ctx_maxi (first, minx);
17885           last  = ctx_mini (last, maxx);
17886 
17887           if (first < last)
17888           {
17889             int pre = 1;
17890             int post = 1;
17891 
17892             if (abs(delta0) < CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA)
17893             {
17894               graystart = 255 - (graystart&0xff);
17895               coverage[first] += graystart;
17896             }
17897             else
17898             {
17899               int u0 = ctx_mini (x0_start, x0_end);
17900               int u1 = ctx_maxi (x0_start, x0_end);
17901               u0 = ctx_maxi (u0, minx_);
17902               u1 = ctx_mini (u1, maxx_);
17903               u1 = ctx_maxi (u1, minx_);
17904               u0 = ctx_mini (u0, maxx_);
17905 
17906               int us = u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV);
17907               int count = 0;
17908 
17909               int mod = (255-(u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256) % 256)) *
17910                          (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/255);
17911               int sum = ((u1-u0+CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV)/255);
17912 
17913               for (int u = u0; u < u1; u+= CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV)
17914               {
17915                 coverage[us + count] = (u - u0 + mod) / sum;
17916                 count++;
17917               }
17918               pre = (us+count-1)-first+1;
17919             }
17920 
17921             if (abs(delta1) < CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA)
17922             {
17923                grayend   = (grayend & 0xff);
17924                coverage[last] += grayend;
17925             }
17926             else
17927             {
17928               int u0 = ctx_mini (x1_start, x1_end);
17929               int u1 = ctx_maxi (x1_start, x1_end);
17930               u0 = ctx_maxi (u0, minx_);
17931               u1 = ctx_mini (u1, maxx_);
17932               u1 = ctx_maxi (u1, minx_);
17933               u0 = ctx_mini (u0, maxx_);
17934               int us = u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV);
17935               int count = 0;
17936               int mod = ((255-(u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256) % 256)+64) *
17937                     (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/255));
17938               int sum = ((u1-u0+CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV * 1.25)/255);
17939               for (int u = u0; u < u1; u+= CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV)
17940               {
17941                 coverage[us + count] = 255-((u - u0 + mod)/ sum);
17942                 count++;
17943               }
17944               post = last-us+1;
17945             }
17946             for (int i = first + pre; i <= last - post; i++)
17947               coverage[i] = 255;
17948           }
17949           else if (first == last)
17950           {
17951             graystart = 255 - (graystart&0xff);
17952             grayend   = (grayend & 0xff);
17953             coverage[last]+=(graystart-(255-grayend));
17954           }
17955         }
17956    }
17957 }
17958 
17959 
17960 inline static void
ctx_rasterizer_generate_coverage_apply2(CtxRasterizer * rasterizer,int minx,int maxx,uint8_t * coverage,int is_winding,CtxCovPath comp)17961 ctx_rasterizer_generate_coverage_apply2 (CtxRasterizer *rasterizer,
17962                                          int            minx,
17963                                          int            maxx,
17964                                          uint8_t       *coverage,
17965                                          int            is_winding,
17966                                          CtxCovPath     comp)
17967 {
17968   CtxSegment *entries = (CtxSegment*)(&rasterizer->edge_list.entries[0]);
17969   int *edges          = rasterizer->edges;
17970   int  scanline       = rasterizer->scanline;
17971   const int  bpp      = rasterizer->format->bpp/8;
17972   int  active_edges   = rasterizer->active_edges;
17973   int  parity         = 0;
17974 
17975   const uint32_t src_pix    = ((uint32_t*)rasterizer->color)[0];
17976   const uint32_t si_ga      = ((uint32_t*)rasterizer->color)[1];
17977   const uint32_t si_rb      = ((uint32_t*)rasterizer->color)[2];
17978   const uint32_t si_ga_full = ((uint32_t*)rasterizer->color)[3];
17979   const uint32_t si_rb_full = ((uint32_t*)rasterizer->color)[4];
17980   const uint32_t si_a  = src_pix >> 24;
17981 
17982   uint8_t *dst = ( (uint8_t *) rasterizer->buf) +
17983          (rasterizer->blit_stride * (scanline / CTX_FULL_AA));
17984 
17985   coverage -= minx;
17986 
17987   const int minx_ = minx * CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV;
17988   const int maxx_ = maxx * CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV;
17989 
17990   int accumulated_x0 = 65538;
17991   int accumulated_x1 = 65536;
17992 
17993   for (int t = 0; t < active_edges -1;t++)
17994     {
17995       CtxSegment   *segment = &entries[edges[t]];
17996       UPDATE_PARITY;
17997 
17998        if (parity)
17999         {
18000           CtxSegment   *next_segment = &entries[edges[t+1]];
18001           const int x0        = segment->val;
18002           const int x1        = next_segment->val;
18003           const int delta0    = segment->delta;
18004           const int delta1    = next_segment->delta;
18005 
18006           int x0_start = x0 - delta0 * CTX_AA_HALFSTEP2;
18007           int x1_start = x1 - delta1 * CTX_AA_HALFSTEP2;
18008           int x0_end   = x0 + delta0 * CTX_AA_HALFSTEP;
18009           int x1_end   = x1 + delta1 * CTX_AA_HALFSTEP;
18010 
18011           int graystart = x0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
18012           int grayend   = x1 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256);
18013           int first     = graystart >> 8;
18014           int last      = grayend   >> 8;
18015 
18016           first = ctx_maxi (first, minx);
18017           last = ctx_mini (last, maxx);
18018           graystart = 255 - (graystart&0xff);
18019           grayend   = (grayend & 0xff);
18020 
18021           if (first < last)
18022           {
18023             int pre = 1;
18024             int post = 1;
18025 
18026           if (abs(delta0) < CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA)
18027           {
18028              coverage[first] += graystart;
18029 
18030             accumulated_x1 = first;
18031             accumulated_x0 = ctx_mini (accumulated_x0, first);
18032           }
18033           else
18034           {
18035             int u0 = ctx_mini (x0_start, x0_end);
18036             int u1 = ctx_maxi (x0_start, x0_end);
18037             u0 = ctx_maxi (u0, minx_);
18038             u1 = ctx_mini (u1, maxx_);
18039             u1 = ctx_maxi (u1, minx_);
18040             u0 = ctx_mini (u0, maxx_);
18041 
18042             int mod = (255-(u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256) % 256)) *
18043                     (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/255);
18044             int sum = ((u1-u0+CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV)/255);
18045 
18046             int us = u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV);
18047             int count = 0;
18048             for (int u = u0; u < u1; u+= CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV)
18049             {
18050               coverage[us + count] = (u - u0 + mod) / sum;
18051               count++;
18052             }
18053             pre = (us+count-1)-first+1;
18054 
18055 #if 0 // the CTX_UNLIKELY helps - but this is a big constant overhead
18056       // which ends up penalizing us in benchmarks, it needs to be
18057       // a shape with really large interior emptiness for this
18058       // to be worthwhile
18059           if (CTX_UNLIKELY(
18060               us - accumulated_x1 > 16 &&
18061               accumulated_x1-accumulated_x0>=0
18062                           ))
18063           {
18064              switch (comp)
18065              {
18066                 case CTX_COV_PATH_OVER:
18067                 {
18068                   uint32_t *dst_i = (uint32_t*)&dst[((accumulated_x0) * bpp)];
18069                   for (int i = 0; i < accumulated_x1-accumulated_x0+1; i++)
18070                     {
18071                       *dst_i = ctx_over_RGBA8_2 (*dst_i, si_ga, si_rb, si_a, coverage[accumulated_x0+i]);
18072                       dst_i++;
18073                     }
18074                 }
18075                 break;
18076                 case CTX_COV_PATH_COPY:
18077                 {
18078                   uint32_t *dst_i = (uint32_t*)&dst[((accumulated_x0) * bpp)];
18079                   for (int i = 0; i < accumulated_x1-accumulated_x0+1; i++)
18080                   {
18081                     *dst_i = ctx_lerp_RGBA8_2 (*dst_i, si_ga, si_rb, coverage[accumulated_x0+i]);
18082                     dst_i++;
18083                   }
18084                 }
18085                   break;
18086                 default:
18087                 ctx_rasterizer_apply_coverage (rasterizer,
18088                           &dst[((accumulated_x0) * bpp)],
18089                           accumulated_x0,
18090                           &coverage[accumulated_x0],
18091                           accumulated_x1-accumulated_x0+1);
18092              }
18093           }
18094 #endif
18095 
18096             accumulated_x0 = ctx_mini (accumulated_x0, us);
18097             accumulated_x1 = us + count - 1;
18098           }
18099 
18100    if (accumulated_x1-accumulated_x0>=0)
18101           {
18102              switch (comp)
18103              {
18104                 case CTX_COV_PATH_OVER:
18105                 {
18106                   uint32_t *dst_i = (uint32_t*)&dst[((accumulated_x0) * bpp)];
18107                   for (int i = 0; i < accumulated_x1-accumulated_x0+1; i++)
18108                     {
18109                       *dst_i = ctx_over_RGBA8_2 (*dst_i, si_ga, si_rb, si_a, coverage[accumulated_x0+i]);
18110                       dst_i++;
18111                     }
18112                 }
18113                 break;
18114                 case CTX_COV_PATH_COPY:
18115                 {
18116                   uint32_t *dst_i = (uint32_t*)&dst[((accumulated_x0) * bpp)];
18117                   for (int i = 0; i < accumulated_x1-accumulated_x0+1; i++)
18118                   {
18119                     *dst_i = ctx_lerp_RGBA8_2 (*dst_i, si_ga, si_rb, coverage[accumulated_x0+i]);
18120                     dst_i++;
18121                   }
18122                 }
18123                   break;
18124                 default:
18125                 ctx_rasterizer_apply_coverage (rasterizer,
18126                           &dst[((accumulated_x0) * bpp)],
18127                           accumulated_x0,
18128                           &coverage[accumulated_x0],
18129                           accumulated_x1-accumulated_x0+1);
18130              }
18131              accumulated_x0 = 65538;
18132              accumulated_x1 = 65536;
18133           }
18134 
18135           if (abs(delta1) < CTX_RASTERIZER_AA_SLOPE_LIMIT3_FAST_AA)
18136           {
18137              coverage[last] += grayend;
18138              accumulated_x1 = last;
18139              accumulated_x0 = last;
18140           }
18141           else
18142           {
18143             int u0 = ctx_mini (x1_start, x1_end);
18144             int u1 = ctx_maxi (x1_start, x1_end);
18145             u0 = ctx_maxi (u0, minx_);
18146             u1 = ctx_mini (u1, maxx_);
18147             u1 = ctx_maxi (u1, minx_);
18148             u0 = ctx_mini (u0, maxx_);
18149             int us = u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV);
18150             int count = 0;
18151 
18152             int mod = ((255-(u0 / (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/256) % 256)+64) *
18153                     (CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV/255));
18154             int sum = ((u1-u0+CTX_RASTERIZER_EDGE_MULTIPLIER * CTX_SUBDIV * 1.25)/255);
18155 
18156             for (int u = u0; u < u1; u+= CTX_RASTERIZER_EDGE_MULTIPLIER*CTX_SUBDIV)
18157             {
18158                 coverage[us + count] = 255-((u - u0 + mod)/ sum);
18159               count++;
18160             }
18161             post = last-us+1;
18162 
18163             accumulated_x1 = us + count;
18164             accumulated_x0 = us;
18165           }
18166             switch (comp)
18167             {
18168               case CTX_COV_PATH_COPY:
18169             {
18170               uint32_t* dst_pix = (uint32_t*)(&dst[(first *bpp)]);
18171               dst_pix+=pre;
18172               ctx_span_set_color (dst_pix, src_pix, last-first-pre-post + 1);
18173             }
18174             break;
18175               case CTX_COV_PATH_OVER:
18176             {
18177               uint32_t* dst_pix = (uint32_t*)(&dst[(first *bpp)]);
18178               dst_pix+=pre;
18179               for (int i = first + pre; i <= last - post; i++)
18180               {
18181                 *dst_pix = ctx_over_RGBA8_full_2(*dst_pix, si_ga_full, si_rb_full, si_a);
18182                 dst_pix++;
18183               }
18184             }
18185             break;
18186               case CTX_COV_PATH_COPY_FRAGMENT:
18187               {
18188               int width = last-first-pre-post+1;
18189             if (width>0)
18190             {
18191               {
18192                 float u0 = 0; float v0 = 0;
18193                 float ud = 0; float vd = 0;
18194                 ctx_init_uv (rasterizer, first+pre, width, &u0, &v0, &ud, &vd);
18195                 rasterizer->fragment (rasterizer, u0, v0, &dst[(first+pre)*bpp],                                      width, ud, vd);
18196               }
18197             }
18198               }
18199             break;
18200               case CTX_COV_PATH_OVER_FRAGMENT:
18201               {
18202                 int width = last-first-pre-post+1;
18203                 if (width>0)
18204                 ctx_RGBA8_source_over_normal_full_cov_fragment (rasterizer,
18205                                &dst[((first+pre)*bpp)],
18206                                NULL,
18207                                first + pre,
18208                                NULL,
18209                                width);
18210               }
18211               break;
18212               default:
18213               {
18214                 int width = last-first-pre-post+1;
18215                 if (width > 0)
18216                 {
18217                 uint8_t opaque[width];
18218                 memset (opaque, 255, sizeof (opaque));
18219                 ctx_rasterizer_apply_coverage (rasterizer,
18220                             &dst[((first + pre) * bpp)],
18221                             first + pre,
18222                             opaque,
18223                             width);
18224                 }
18225               }
18226             }
18227             //}
18228           }
18229           else if (first == last)
18230           {
18231             coverage[last]+=(graystart-(255-grayend));
18232 
18233             accumulated_x1 = last;
18234             accumulated_x0 = ctx_mini (accumulated_x0, last);
18235           }
18236         }
18237    }
18238 
18239    if (accumulated_x1-accumulated_x0>=0)
18240    {
18241              switch (comp)
18242              {
18243                 case CTX_COV_PATH_OVER:
18244                 {
18245                   uint32_t *dst_i = (uint32_t*)&dst[((accumulated_x0) * bpp)];
18246                   for (int i = 0; i < accumulated_x1-accumulated_x0+1; i++)
18247                     {
18248                       *dst_i = ctx_over_RGBA8_2 (*dst_i, si_ga, si_rb, si_a, coverage[accumulated_x0+i]);
18249                       dst_i++;
18250                     }
18251                 }
18252                 break;
18253                 case CTX_COV_PATH_COPY:
18254                 {
18255                   uint32_t *dst_i = (uint32_t*)&dst[((accumulated_x0) * bpp)];
18256                   for (int i = 0; i < accumulated_x1-accumulated_x0+1; i++)
18257                   {
18258                     *dst_i = ctx_lerp_RGBA8_2 (*dst_i, si_ga, si_rb, coverage[accumulated_x0+i]);
18259                     dst_i++;
18260                   }
18261                 }
18262                   break;
18263                 default:
18264                 ctx_rasterizer_apply_coverage (rasterizer,
18265                           &dst[((accumulated_x0) * bpp)],
18266                           accumulated_x0,
18267                           &coverage[accumulated_x0],
18268                           accumulated_x1-accumulated_x0+1);
18269              }
18270    }
18271 }
18272 
18273 #undef CTX_EDGE_Y0
18274 #undef CTX_EDGE
18275 
18276 static inline void
ctx_rasterizer_reset(CtxRasterizer * rasterizer)18277 ctx_rasterizer_reset (CtxRasterizer *rasterizer)
18278 {
18279   rasterizer->pending_edges   = 0;
18280   rasterizer->active_edges    = 0;
18281   rasterizer->has_shape       = 0;
18282   rasterizer->has_prev        = 0;
18283   rasterizer->edge_list.count = 0; // ready for new edges
18284   rasterizer->edge_pos        = 0;
18285   rasterizer->scanline        = 0;
18286   if (CTX_LIKELY(!rasterizer->preserve))
18287   {
18288     rasterizer->scan_min      = 5000;
18289     rasterizer->scan_max      = -5000;
18290     rasterizer->col_min       = 5000;
18291     rasterizer->col_max       = -5000;
18292   }
18293   //rasterizer->comp_op       = NULL; // keep comp_op cached
18294   //     between rasterizations where rendering attributes are
18295   //     nonchanging
18296 }
18297 
18298 static void
ctx_rasterizer_rasterize_edges(CtxRasterizer * rasterizer,const int fill_rule,CtxShapeEntry * shape)18299 ctx_rasterizer_rasterize_edges (CtxRasterizer *rasterizer, const int fill_rule
18300 #if CTX_SHAPE_CACHE
18301                                 ,CtxShapeEntry *shape
18302 #endif
18303                                )
18304 {
18305   int      is_winding = fill_rule == CTX_FILL_RULE_WINDING;
18306   const CtxCovPath comp = rasterizer->comp;
18307   const int real_aa = rasterizer->aa;
18308   uint8_t *dst = ( (uint8_t *) rasterizer->buf);
18309 
18310 
18311   int scan_start = rasterizer->blit_y * CTX_FULL_AA;
18312   int scan_end   = scan_start + (rasterizer->blit_height - 1) * CTX_FULL_AA;
18313   const int blit_width = rasterizer->blit_width;
18314   const int blit_max_x = rasterizer->blit_x + blit_width;
18315   int minx       = rasterizer->col_min / CTX_SUBDIV - rasterizer->blit_x;
18316   int maxx       = (rasterizer->col_max + CTX_SUBDIV-1) / CTX_SUBDIV - rasterizer->blit_x;
18317   const int blit_stride = rasterizer->blit_stride;
18318 
18319   rasterizer->prev_active_edges = -1;
18320   if (
18321 #if CTX_SHAPE_CACHE
18322     !shape &&
18323 #endif
18324     maxx > blit_max_x - 1)
18325     { maxx = blit_max_x - 1; }
18326 
18327   minx = ctx_maxi (rasterizer->state->gstate.clip_min_x, minx);
18328   maxx = ctx_mini (rasterizer->state->gstate.clip_max_x, maxx);
18329   minx = ctx_maxi (0, minx); // redundant?
18330   if (minx >= maxx)
18331     {
18332       ctx_rasterizer_reset (rasterizer);
18333       return;
18334     }
18335 #if CTX_SHAPE_CACHE
18336   uint8_t _coverage[shape?2:maxx-minx+1];
18337 #else
18338   uint8_t _coverage[maxx-minx+1];
18339 #endif
18340   uint8_t *coverage = &_coverage[0];
18341 
18342   int coverage_size =
18343 #if CTX_SHAPE_CACHE
18344                   shape?shape->width:
18345 #endif
18346                   sizeof (_coverage);
18347 
18348 #if CTX_SHAPE_CACHE
18349   if (shape)
18350     {
18351       coverage = &shape->data[0];
18352     }
18353 #endif
18354   //ctx_assert (coverage);
18355   rasterizer->scan_min -= (rasterizer->scan_min % CTX_FULL_AA);
18356 #if CTX_SHAPE_CACHE
18357   if (shape)
18358     {
18359       scan_start = rasterizer->scan_min;
18360       scan_end   = rasterizer->scan_max;
18361     }
18362   else
18363 #endif
18364     {
18365       if (rasterizer->scan_min > scan_start)
18366         {
18367           dst += (rasterizer->blit_stride * (rasterizer->scan_min-scan_start) / CTX_FULL_AA);
18368           scan_start = rasterizer->scan_min;
18369         }
18370       scan_end = ctx_mini (rasterizer->scan_max, scan_end);
18371     }
18372   if (CTX_UNLIKELY(rasterizer->state->gstate.clip_min_y * CTX_FULL_AA > scan_start ))
18373     {
18374        dst += (rasterizer->blit_stride * (rasterizer->state->gstate.clip_min_y * CTX_FULL_AA -scan_start) / CTX_FULL_AA);
18375        scan_start = rasterizer->state->gstate.clip_min_y * CTX_FULL_AA;
18376     }
18377   scan_end = ctx_mini (rasterizer->state->gstate.clip_max_y * CTX_FULL_AA, scan_end);
18378   if (CTX_UNLIKELY(scan_start > scan_end ||
18379       (scan_start > (rasterizer->blit_y + (rasterizer->blit_height-1)) * CTX_FULL_AA) ||
18380       (scan_end < (rasterizer->blit_y) * CTX_FULL_AA)))
18381   {
18382     /* not affecting this rasterizers scanlines */
18383     ctx_rasterizer_reset (rasterizer);
18384     return;
18385   }
18386 
18387   rasterizer->horizontal_edges = 0;
18388   {
18389     rasterizer->needs_aa3  = 0;
18390     rasterizer->needs_aa5  = 0;
18391     rasterizer->needs_aa15 = 0;
18392     ctx_rasterizer_sort_edges (rasterizer);
18393     rasterizer->scanline = scan_start;
18394     ctx_rasterizer_feed_edges (rasterizer, 0);
18395 
18396       int avoid_direct = (0
18397 #if CTX_ENABLE_CLIP
18398          || rasterizer->clip_buffer
18399 #endif
18400 #if CTX_ENABLE_SHADOW_BLUR
18401          || rasterizer->in_shadow
18402 #endif
18403 #if CTX_SHAPE_CACHE
18404          || shape != NULL
18405 #endif
18406          );
18407 
18408   for (; rasterizer->scanline <= scan_end;)
18409     {
18410 
18411       int needs_full_aa =
18412           ( (rasterizer->horizontal_edges!=0)
18413           | (rasterizer->active_edges != rasterizer->prev_active_edges)
18414           | (rasterizer->active_edges + rasterizer->pending_edges == rasterizer->ending_edges)
18415           );
18416 
18417     if (needs_full_aa)
18418     {
18419         int increment = CTX_FULL_AA/real_aa;
18420         memset (coverage, 0, coverage_size);
18421         for (int i = 0; i < real_aa; i++)
18422         {
18423           ctx_rasterizer_feed_edges (rasterizer, 0);
18424           ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, is_winding, real_aa);
18425           ctx_rasterizer_increment_edges (rasterizer, increment);
18426         }
18427     }
18428     else if (! avoid_direct & (rasterizer->needs_aa3 == 0))
18429     {
18430       ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP2);
18431       ctx_rasterizer_feed_edges (rasterizer, 0);
18432 
18433       ctx_rasterizer_generate_coverage_apply (rasterizer, minx, maxx, coverage, is_winding,
18434                       comp);
18435       ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP);
18436 
18437       dst += blit_stride;
18438       rasterizer->prev_active_edges = rasterizer->active_edges;
18439       continue;
18440     }
18441     else if (avoid_direct & (rasterizer->needs_aa3 == 0))
18442     {
18443       ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP2);
18444       ctx_rasterizer_feed_edges (rasterizer, 0);
18445 
18446       memset (coverage, 0, coverage_size);
18447       ctx_rasterizer_generate_coverage_set (rasterizer, minx, maxx, coverage, is_winding);
18448       ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP);
18449     }
18450     else if (ctx_rasterizer_is_simple (rasterizer))
18451     {
18452       ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP2);
18453       ctx_rasterizer_feed_edges (rasterizer, 1);
18454       memset (coverage, 0, coverage_size);
18455       if (!avoid_direct)
18456       {
18457 
18458         ctx_rasterizer_generate_coverage_apply2 (rasterizer, minx, maxx, coverage, is_winding,
18459                       comp);
18460         ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP);
18461 
18462         dst += blit_stride;
18463         rasterizer->prev_active_edges = rasterizer->active_edges;
18464         continue;
18465       }
18466       ctx_rasterizer_generate_coverage_set2 (rasterizer, minx, maxx, coverage, is_winding);
18467       ctx_rasterizer_increment_edges (rasterizer, CTX_AA_HALFSTEP);
18468     }
18469     else
18470     {
18471       int aa = 3;
18472       if (rasterizer->needs_aa5 && real_aa >=5)
18473       {
18474          aa = 5;
18475          if (rasterizer->needs_aa15 && real_aa >=15)
18476            aa = 15;
18477       }
18478       int scanline_increment = 15/aa;
18479 
18480       memset (coverage, 0, coverage_size);
18481       for (int i = 0; i < CTX_FULL_AA; i+= scanline_increment)
18482       {
18483         ctx_rasterizer_feed_edges (rasterizer, 0);
18484         ctx_rasterizer_generate_coverage (rasterizer, minx, maxx, coverage, is_winding, aa);
18485         ctx_rasterizer_increment_edges (rasterizer, scanline_increment);
18486       }
18487     }
18488 
18489   ctx_coverage_post_process (rasterizer, minx, maxx, coverage - minx,
18490                   NULL, NULL);
18491 #if CTX_SHAPE_CACHE
18492   if (shape == NULL)
18493 #endif
18494   {
18495     ctx_rasterizer_apply_coverage (rasterizer,
18496                          &dst[(minx * rasterizer->format->bpp) /8],
18497                          minx,
18498                          coverage,
18499                          maxx-minx+ 1);
18500   }
18501 #if CTX_SHAPE_CACHE
18502       if (shape)
18503         {
18504           coverage += shape->width;
18505         }
18506 #endif
18507       dst += blit_stride;
18508       rasterizer->prev_active_edges = rasterizer->active_edges;
18509     }
18510   }
18511 
18512   if (CTX_UNLIKELY(rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_OUT ||
18513       rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_IN ||
18514       rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_DESTINATION_IN ||
18515       rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_DESTINATION_ATOP ||
18516       rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_CLEAR))
18517   {
18518      /* fill in the rest of the blitrect when compositing mode permits it */
18519      uint8_t nocoverage[rasterizer->blit_width];
18520      //int gscan_start = rasterizer->state->gstate.clip_min_y * CTX_FULL_AA;
18521      int gscan_start = rasterizer->state->gstate.clip_min_y * CTX_FULL_AA;
18522      int gscan_end = rasterizer->state->gstate.clip_max_y * CTX_FULL_AA;
18523      memset (nocoverage, 0, sizeof(nocoverage));
18524      int startx   = rasterizer->state->gstate.clip_min_x;
18525      int endx     = rasterizer->state->gstate.clip_max_x;
18526      int clipw    = endx-startx + 1;
18527      uint8_t *dst = ( (uint8_t *) rasterizer->buf);
18528 
18529      dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (gscan_start / CTX_FULL_AA);
18530      for (rasterizer->scanline = gscan_start; rasterizer->scanline < scan_start;)
18531      {
18532        ctx_rasterizer_apply_coverage (rasterizer,
18533                                       &dst[ (startx * rasterizer->format->bpp) /8],
18534                                       0,
18535                                       nocoverage, clipw);
18536        rasterizer->scanline += CTX_FULL_AA;
18537        dst += rasterizer->blit_stride;
18538      }
18539      if (minx < startx)
18540      {
18541      dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_start / CTX_FULL_AA);
18542      for (rasterizer->scanline = scan_start; rasterizer->scanline < scan_end;)
18543      {
18544        ctx_rasterizer_apply_coverage (rasterizer,
18545                                       &dst[ (startx * rasterizer->format->bpp) /8],
18546                                       0,
18547                                       nocoverage, minx-startx);
18548        dst += blit_stride;
18549      }
18550      }
18551 
18552      if (endx > maxx)
18553      {
18554      dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_start / CTX_FULL_AA);
18555      for (rasterizer->scanline = scan_start; rasterizer->scanline < scan_end;)
18556      {
18557        ctx_rasterizer_apply_coverage (rasterizer,
18558                                       &dst[ (maxx * rasterizer->format->bpp) /8],
18559                                       0,
18560                                       nocoverage, endx-maxx);
18561 
18562        rasterizer->scanline += CTX_FULL_AA;
18563        dst += rasterizer->blit_stride;
18564      }
18565      }
18566 #if 1
18567      dst = (uint8_t*)(rasterizer->buf) + rasterizer->blit_stride * (scan_end / CTX_FULL_AA);
18568      // XXX valgrind/asan this
18569      if(0)for (rasterizer->scanline = scan_end; rasterizer->scanline/CTX_FULL_AA < gscan_end-1;)
18570      {
18571        ctx_rasterizer_apply_coverage (rasterizer,
18572                                       &dst[ (startx * rasterizer->format->bpp) /8],
18573                                       0,
18574                                       nocoverage, clipw-1);
18575 
18576        rasterizer->scanline += CTX_FULL_AA;
18577        dst += blit_stride;
18578      }
18579 #endif
18580   }
18581   ctx_rasterizer_reset (rasterizer);
18582 }
18583 
18584 inline static int
ctx_is_transparent(CtxRasterizer * rasterizer,int stroke)18585 ctx_is_transparent (CtxRasterizer *rasterizer, int stroke)
18586 {
18587   CtxGState *gstate = &rasterizer->state->gstate;
18588   if (gstate->global_alpha_u8 == 0)
18589     return 1;
18590   if (gstate->source_fill.type == CTX_SOURCE_COLOR)
18591   {
18592     uint8_t ga[2];
18593     ctx_color_get_graya_u8 (rasterizer->state, &gstate->source_fill.color, ga);
18594     if (ga[1] == 0)
18595       return 1;
18596   }
18597   return 0;
18598 }
18599 
18600 #define CTX_RECT_FILL 1
18601 
18602 #if CTX_RECT_FILL
18603 static void
ctx_rasterizer_fill_rect(CtxRasterizer * rasterizer,int x0,int y0,int x1,int y1,uint8_t cov)18604 ctx_rasterizer_fill_rect (CtxRasterizer *rasterizer,
18605                           int          x0,
18606                           int          y0,
18607                           int          x1,
18608                           int          y1,
18609                           uint8_t      cov)
18610 {
18611   int blit_x = rasterizer->blit_x;
18612   int blit_y = rasterizer->blit_y;
18613   int blit_width = rasterizer->blit_width;
18614   int blit_height = rasterizer->blit_height;
18615   int blit_stride = rasterizer->blit_stride;
18616   x0 = ctx_maxi (x0, blit_x);
18617   x1 = ctx_mini (x1, blit_x + blit_width);
18618 
18619   int width = x1 - x0;
18620 
18621   if (CTX_UNLIKELY(width <=0))
18622     return;
18623 
18624   void (*comp_op)(CTX_COMPOSITE_ARGUMENTS) = rasterizer->comp_op;
18625 
18626   y0 = ctx_maxi (y0, blit_y);
18627   y1 = ctx_mini (y1, blit_y + blit_height);
18628   rasterizer->scanline = y0 * CTX_FULL_AA;
18629   _ctx_setup_compositor (rasterizer);
18630   uint8_t *dst = ( (uint8_t *) rasterizer->buf);
18631 
18632   dst += (y0 - blit_y) * blit_stride;
18633   dst += (x0) * rasterizer->format->bpp/8;
18634 
18635   if (cov == 255)
18636   {
18637     if (comp_op == ctx_RGBA8_source_copy_normal_color)
18638     {
18639       uint32_t color = *((uint32_t*)rasterizer->color);
18640       if (width == 1)
18641       {
18642         for (int y = y0; y < y1; y++)
18643         {
18644           uint32_t *dst_i = (uint32_t*)&dst[0];
18645           *dst_i = color;
18646           dst += blit_stride;
18647         }
18648         return;
18649       }
18650       else
18651       {
18652         for (int y = y0; y < y1; y++)
18653         {
18654           ctx_span_set_color ((uint32_t*)&dst[0], color, width);
18655           dst += blit_stride;
18656         }
18657         return;
18658       }
18659     }
18660     else if (comp_op == ctx_RGBA8_source_over_normal_color)
18661     {
18662       uint32_t si_ga_full = ((uint32_t*)rasterizer->color)[3];
18663       uint32_t si_rb_full = ((uint32_t*)rasterizer->color)[4];
18664       uint32_t si_a  = rasterizer->color[3];
18665 
18666       if (width == 1)
18667       {
18668         for (int y = y0; y < y1; y++)
18669         {
18670           ((uint32_t*)(dst))[0] = ctx_over_RGBA8_full_2 (
18671              ((uint32_t*)(dst))[0], si_ga_full, si_rb_full, si_a);
18672           dst += blit_stride;
18673         }
18674         return;
18675       }
18676       else
18677       {
18678         for (int y = y0; y < y1; y++)
18679         {
18680           uint32_t *dst_i = (uint32_t*)&dst[0];
18681           for (int i = 0; i < width; i++)
18682           {
18683             dst_i[i] = ctx_over_RGBA8_full_2 (dst_i[i], si_ga_full, si_rb_full, si_a);
18684           }
18685           dst += blit_stride;
18686         }
18687         return;
18688       }
18689     }
18690     else if (comp_op == ctx_RGBA8_source_copy_normal_fragment)
18691     {
18692       for (int y = y0; y < y1; y++)
18693       {
18694         float u0 = 0; float v0 = 0;
18695         float ud = 0; float vd = 0;
18696         ctx_init_uv (rasterizer, x0, width, &u0, &v0, &ud, &vd);
18697         rasterizer->fragment (rasterizer, u0, v0, &dst[0], width, ud, vd);
18698         rasterizer->scanline += CTX_FULL_AA;
18699         dst += blit_stride;
18700       }
18701       return;
18702     }
18703     else if (comp_op == ctx_RGBA8_source_over_normal_fragment)
18704     {
18705       for (int y = y0; y < y1; y++)
18706       {
18707         ctx_RGBA8_source_over_normal_full_cov_fragment (rasterizer,
18708                                 &dst[0], NULL, x0, NULL, width);
18709         rasterizer->scanline += CTX_FULL_AA;
18710         dst += blit_stride;
18711       }
18712       return;
18713     }
18714   }
18715   else
18716   {
18717   if (comp_op == ctx_RGBA8_source_copy_normal_color)
18718     {
18719       uint32_t color = *((uint32_t*)rasterizer->color);
18720       if (width == 1)
18721       {
18722         for (int y = y0; y < y1; y++)
18723         {
18724           uint32_t *dst_i = (uint32_t*)&dst[0];
18725           *dst_i = ctx_lerp_RGBA8 (*dst_i, color, cov);
18726           dst += blit_stride;
18727         }
18728         return;
18729       }
18730       else
18731       {
18732         for (int y = y0; y < y1; y++)
18733         {
18734           uint32_t *dst_i = (uint32_t*)&dst[0];
18735           for (int i = 0; i < width; i++)
18736           {
18737             dst_i[i] = ctx_lerp_RGBA8 (dst_i[i], color, cov);
18738           }
18739           dst += blit_stride;
18740         }
18741         return;
18742       }
18743     }
18744     else if (comp_op == ctx_RGBA8_source_over_normal_color)
18745     {
18746       uint32_t color = *((uint32_t*)rasterizer->color);
18747       if (width == 1)
18748       {
18749         for (int y = y0; y < y1; y++)
18750         {
18751           uint32_t *dst_i = (uint32_t*)&dst[0];
18752           *dst_i = ctx_over_RGBA8 (*dst_i, color, cov);
18753           dst += blit_stride;
18754         }
18755         return;
18756       }
18757       else
18758       {
18759         for (int y = y0; y < y1; y++)
18760         {
18761           uint32_t *dst_i = (uint32_t*)&dst[0];
18762           for (int i = 0; i < width; i++)
18763           {
18764             dst_i[i] = ctx_over_RGBA8 (dst_i[i], color, cov);
18765           }
18766           dst += blit_stride;
18767         }
18768         return;
18769       }
18770     }
18771   }
18772 
18773   {
18774     uint8_t coverage[width];
18775     memset (coverage, cov, sizeof (coverage) );
18776     for (int y = y0; y < y1; y++)
18777     {
18778       ctx_rasterizer_apply_coverage (rasterizer, &dst[0], x0, coverage, width);
18779       rasterizer->scanline += CTX_FULL_AA;
18780       dst += blit_stride;
18781     }
18782   }
18783 }
18784 #endif
18785 
ctx_fmod1f(float val)18786 static inline float ctx_fmod1f (float val)
18787 {
18788   int vali = val;
18789   return val - vali;
18790 }
18791 
18792 static void
ctx_rasterizer_fill(CtxRasterizer * rasterizer)18793 ctx_rasterizer_fill (CtxRasterizer *rasterizer)
18794 {
18795   int preserved_count = rasterizer->preserve?rasterizer->edge_list.count:1;
18796   int blit_x = rasterizer->blit_x;
18797   int blit_y = rasterizer->blit_y;
18798   int blit_width = rasterizer->blit_width;
18799   int blit_height = rasterizer->blit_height;
18800   int blit_stride = rasterizer->blit_stride;
18801 
18802   CtxSegment temp[preserved_count]; /* copy of already built up path's poly line
18803                           XXX - by building a large enough path
18804                           the stack can be smashed!
18805                          */
18806   if (CTX_UNLIKELY(rasterizer->preserve))
18807     { memcpy (temp, rasterizer->edge_list.entries, sizeof (temp) ); }
18808 
18809 #if CTX_ENABLE_SHADOW_BLUR
18810   if (CTX_UNLIKELY(rasterizer->in_shadow))
18811   {
18812   for (int i = 0; i < rasterizer->edge_list.count; i++)
18813     {
18814       CtxSegment *entry = &((CtxSegment*)rasterizer->edge_list.entries)[i];
18815       entry->data.s16[2] += rasterizer->shadow_x * CTX_SUBDIV;
18816       entry->data.s16[3] += rasterizer->shadow_y * CTX_FULL_AA;
18817     }
18818     rasterizer->scan_min += rasterizer->shadow_y * CTX_FULL_AA;
18819     rasterizer->scan_max += rasterizer->shadow_y * CTX_FULL_AA;
18820     rasterizer->col_min  += (rasterizer->shadow_x - rasterizer->state->gstate.shadow_blur * 3 + 1) * CTX_SUBDIV;
18821     rasterizer->col_max  += (rasterizer->shadow_x + rasterizer->state->gstate.shadow_blur * 3 + 1) * CTX_SUBDIV;
18822   }
18823 #endif
18824 
18825   if (CTX_UNLIKELY(ctx_is_transparent (rasterizer, 0) ||
18826       rasterizer->scan_min > CTX_FULL_AA * (blit_y + blit_height) ||
18827       rasterizer->scan_max < CTX_FULL_AA * blit_y ||
18828       rasterizer->col_min > CTX_SUBDIV * (blit_x + blit_width) ||
18829       rasterizer->col_max < CTX_SUBDIV * blit_x))
18830     {
18831       ctx_rasterizer_reset (rasterizer);
18832     }
18833   else
18834   {
18835     _ctx_setup_compositor (rasterizer);
18836 
18837 #if 1
18838     rasterizer->state->min_x = ctx_mini (rasterizer->state->min_x, rasterizer->col_min / CTX_SUBDIV);
18839     rasterizer->state->max_x = ctx_maxi (rasterizer->state->min_x, rasterizer->col_max / CTX_SUBDIV);
18840     rasterizer->state->min_y = ctx_mini (rasterizer->state->min_y, rasterizer->scan_min / CTX_FULL_AA);
18841     rasterizer->state->max_y = ctx_maxi (rasterizer->state->max_y, rasterizer->scan_max / CTX_FULL_AA);
18842 #else
18843     if (CTX_UNLIKELY ( rasterizer->col_min / CTX_SUBDIV < rasterizer->state->min_x))
18844        rasterizer->state->min_x = rasterizer->col_min / CTX_SUBDIV;
18845     if (CTX_UNLIKELY ( rasterizer->col_min / CTX_SUBDIV > rasterizer->state->max_x))
18846        rasterizer->state->min_x = rasterizer->col_min / CTX_SUBDIV;
18847 
18848     if (CTX_UNLIKELY ( rasterizer->scan_min / CTX_FULL_AA < rasterizer->state->min_y))
18849        rasterizer->state->min_y = rasterizer->scan_min / CTX_FULL_AA;
18850     if (CTX_UNLIKELY ( rasterizer->scan_min / CTX_FULL_AA > rasterizer->state->max_y))
18851        rasterizer->state->max_y = rasterizer->scan_max / CTX_FULL_AA;
18852 #endif
18853 
18854 #if CTX_RECT_FILL
18855   if (rasterizer->edge_list.count == 5)
18856     {
18857       CtxSegment *entry0 = &(((CtxSegment*)(rasterizer->edge_list.entries)))[0];
18858       CtxSegment *entry1 = &(((CtxSegment*)(rasterizer->edge_list.entries)))[1];
18859       CtxSegment *entry2 = &(((CtxSegment*)(rasterizer->edge_list.entries)))[2];
18860       CtxSegment *entry3 = &(((CtxSegment*)(rasterizer->edge_list.entries)))[3];
18861 
18862       if ((!(rasterizer->state->gstate.clipped != 0)) &
18863           (entry0->data.s16[2] == entry1->data.s16[2]) &
18864           (entry0->data.s16[3] == entry3->data.s16[3]) &
18865           (entry1->data.s16[3] == entry2->data.s16[3]) &
18866           (entry2->data.s16[2] == entry3->data.s16[2])
18867 #if CTX_ENABLE_SHADOW_BLUR
18868            && !rasterizer->in_shadow
18869 #endif
18870          )
18871        {
18872          if(((entry1->data.s16[2] % (CTX_SUBDIV))  == 0) &
18873             ((entry1->data.s16[3] % (CTX_FULL_AA)) == 0) &
18874             ((entry3->data.s16[2] % (CTX_SUBDIV))  == 0) &
18875             ((entry3->data.s16[3] % (CTX_FULL_AA)) == 0))
18876          {
18877            /* best-case axis aligned rectangle */
18878            int x0 = entry3->data.s16[2] / CTX_SUBDIV;
18879            int y0 = entry3->data.s16[3] / CTX_FULL_AA;
18880            int x1 = entry1->data.s16[2] / CTX_SUBDIV;
18881            int y1 = entry1->data.s16[3] / CTX_FULL_AA;
18882 
18883            ctx_rasterizer_fill_rect (rasterizer, x0, y0, x1, y1, 255);
18884            ctx_rasterizer_reset (rasterizer);
18885            goto done;
18886          }
18887         else
18888          {
18889            float x0 = entry3->data.s16[2] * (1.0f / CTX_SUBDIV);
18890            float y0 = entry3->data.s16[3] * (1.0f / CTX_FULL_AA);
18891            float x1 = entry1->data.s16[2] * (1.0f / CTX_SUBDIV);
18892            float y1 = entry1->data.s16[3] * (1.0f / CTX_FULL_AA);
18893 
18894            x0 = ctx_maxf (x0, blit_x);
18895            y0 = ctx_maxf (y0, blit_y);
18896            x1 = ctx_minf (x1, blit_x + blit_width);
18897            y1 = ctx_minf (y1, blit_y + blit_height);
18898 
18899            uint8_t left = 255-ctx_fmod1f (x0) * 255;
18900            uint8_t top  = 255-ctx_fmod1f (y0) * 255;
18901            uint8_t right  = ctx_fmod1f (x1) * 255;
18902            uint8_t bottom = ctx_fmod1f (y1) * 255;
18903 
18904            x0 = ctx_floorf (x0);
18905            y0 = ctx_floorf (y0);
18906            x1 = ctx_floorf (x1+7/8.0f);
18907            y1 = ctx_floorf (y1+14/15.0f);
18908 
18909            int has_top    = (top < 255);
18910            int has_bottom = (bottom <255);
18911            int has_right  = (right >0);
18912            int has_left   = (left >0);
18913 
18914            int width = x1 - x0;
18915 
18916            if (CTX_LIKELY(width >0))
18917            {
18918               uint8_t *dst = ( (uint8_t *) rasterizer->buf);
18919               uint8_t coverage[width+2];
18920               dst += (((int)y0) - blit_y) * blit_stride;
18921               dst += ((int)x0) * rasterizer->format->bpp/8;
18922 
18923               if (has_top)
18924               {
18925                 int i = 0;
18926                 if (has_left)
18927                 {
18928                   coverage[i++] = top * left / 255;
18929                 }
18930                 for (int x = x0 + has_left; x < x1 - has_right; x++)
18931                   coverage[i++] = top;
18932                 coverage[i++]= top * right / 255;
18933 
18934                   ctx_rasterizer_apply_coverage (rasterizer,dst,
18935                                                  x0,
18936                                                  coverage, width);
18937                  dst += blit_stride;
18938                }
18939 
18940 #if 0
18941            if (!(
18942             (rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_COPY||
18943              rasterizer->state->gstate.compositing_mode == CTX_COMPOSITE_SOURCE_OVER) &&
18944              rasterizer->state->gstate.blend_mode == CTX_BLEND_NORMAL &&
18945              rasterizer->state->gstate.source_fill.type == CTX_SOURCE_COLOR
18946              ))
18947            {
18948              int i = 0;
18949              if (has_left)
18950              {
18951                coverage[i++] = left;
18952              }
18953              for (int x = x0 + has_left; x < x1 - has_right; x++)
18954                coverage[i++] = 255;
18955              coverage[i++] = right;
18956 
18957              for (int ty = y0+has_top; ty < y1-has_bottom; ty++)
18958              {
18959                ctx_rasterizer_apply_coverage (rasterizer, dst, x0, coverage, width);
18960                dst += blit_stride;
18961              }
18962            }
18963            else
18964 #endif
18965            {
18966              if (has_left)
18967                ctx_rasterizer_fill_rect (rasterizer, x0, y0 + has_top, x0+1, y1 - has_bottom, left);
18968              if (has_right)
18969                ctx_rasterizer_fill_rect (rasterizer, x1-1, y0 + has_top, x1, y1 - has_bottom, right);
18970              x0 += has_left;
18971              y0 += has_top;
18972              y1 -= has_bottom;
18973              x1 -= has_right;
18974              ctx_rasterizer_fill_rect (rasterizer, x0,y0,x1,y1,255);
18975 
18976              dst += blit_stride * ((((int)y1)-has_bottom) - (((int)y0)+has_top));
18977            }
18978 
18979            if (has_bottom)
18980            {
18981              int i = 0;
18982              if (has_left)
18983                coverage[i++] = bottom * left / 255;
18984              for (int x = x0 + has_left; x < x1 - has_right; x++)
18985                coverage[i++] = bottom;
18986              coverage[i++]= bottom * right / 255;
18987 
18988              ctx_rasterizer_apply_coverage (rasterizer,dst, x0, coverage, width);
18989            }
18990            }
18991 
18992            ctx_rasterizer_reset (rasterizer);
18993            goto done;
18994          }
18995 
18996        }
18997     }
18998 #endif
18999     ctx_rasterizer_finish_shape (rasterizer);
19000 
19001     uint32_t hash = ctx_rasterizer_poly_to_edges (rasterizer);
19002     if (hash){};
19003 
19004 #if CTX_SHAPE_CACHE
19005     int width = (rasterizer->col_max + (CTX_SUBDIV-1) ) / CTX_SUBDIV - rasterizer->col_min/CTX_SUBDIV + 1;
19006     int height = (rasterizer->scan_max + (CTX_FULL_AA-1) ) / CTX_FULL_AA - rasterizer->scan_min / CTX_FULL_AA + 1;
19007     if (width * height < CTX_SHAPE_CACHE_DIM && width >=1 && height >= 1
19008         && width < CTX_SHAPE_CACHE_MAX_DIM
19009         && height < CTX_SHAPE_CACHE_MAX_DIM
19010 #if CTX_ENABLE_SHADOW_BLUR
19011         && !rasterizer->in_shadow
19012 #endif
19013         )
19014       {
19015         int scan_min = rasterizer->scan_min;
19016         int col_min = rasterizer->col_min;
19017         scan_min -= (scan_min % CTX_FULL_AA);
19018         int y0 = scan_min / CTX_FULL_AA;
19019         int y1 = y0 + height;
19020         int x0 = col_min / CTX_SUBDIV;
19021         int ymin = y0;
19022         int x1 = x0 + width;
19023         int clip_x_min = blit_x;
19024         int clip_x_max = blit_x + blit_width - 1;
19025         int clip_y_min = blit_y;
19026         int clip_y_max = blit_y + blit_height - 1;
19027 
19028         int dont_cache = 0;
19029         if (CTX_UNLIKELY(x1 >= clip_x_max))
19030           { x1 = clip_x_max;
19031             dont_cache = 1;
19032           }
19033         int xo = 0;
19034         if (CTX_UNLIKELY(x0 < clip_x_min))
19035           {
19036             xo = clip_x_min - x0;
19037             x0 = clip_x_min;
19038             dont_cache = 1;
19039           }
19040         if (CTX_UNLIKELY(y0 < clip_y_min || y1 >= clip_y_max))
19041           dont_cache = 1;
19042         if (dont_cache || !_ctx_shape_cache_enabled)
19043         {
19044           ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule
19045 #if CTX_SHAPE_CACHE
19046                                         , NULL
19047 #endif
19048                                        );
19049         }
19050         else
19051         {
19052         rasterizer->scanline = scan_min;
19053         CtxShapeEntry *shape = ctx_shape_entry_find (rasterizer, hash, width, height);
19054 
19055         if (shape->uses == 0)
19056           {
19057             CtxBuffer *buffer_backup = rasterizer->clip_buffer;
19058             rasterizer->clip_buffer = NULL;
19059             ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule, shape);
19060             rasterizer->clip_buffer = buffer_backup;
19061           }
19062 
19063         int ewidth = x1 - x0;
19064         if (ewidth>0)
19065         {
19066           rasterizer->scanline = scan_min;
19067           int bpp = rasterizer->format->bpp;
19068           if (rasterizer->clip_buffer && !rasterizer->clip_rectangle)
19069           {
19070           uint8_t composite[ewidth];
19071           uint8_t *clip_data = (uint8_t*)rasterizer->clip_buffer->data;
19072           int shape_width = shape->width;
19073           for (int y = y0; y < y1; y++)
19074             {
19075               if ( (y >= clip_y_min) && (y <= clip_y_max) )
19076                 {
19077                     for (int x = 0; x < ewidth; x++)
19078                     {
19079                       int val = shape->data[shape_width * (int)(y-ymin) + xo + x];
19080                       // XXX : not valid for 1bit clip buffers
19081                       val = (val*(clip_data) [
19082                               ((y-blit_y) * blit_width) + x0 + x])/255;
19083                       composite[x] = val;
19084                     }
19085                     ctx_rasterizer_apply_coverage (rasterizer,
19086                                                  ( (uint8_t *) rasterizer->buf) + (y-blit_y) * blit_stride + (int) (x0) * bpp/8,
19087                                                  x0, // is 0
19088                                                  composite,
19089                                                  ewidth );
19090                rasterizer->scanline += CTX_FULL_AA;
19091             }
19092           }
19093           }
19094           else
19095           for (int y = y0; y < y1; y++)
19096             {
19097               if (CTX_LIKELY((y >= clip_y_min) && (y <= clip_y_max) ))
19098                 {
19099                     ctx_rasterizer_apply_coverage (rasterizer,
19100                                                  ( (uint8_t *) rasterizer->buf) + (y-blit_y) * blit_stride + (int) (x0) * bpp/8,
19101                                                  x0,
19102                                                  &shape->data[shape->width * (int) (y-ymin) + xo],
19103                                                  ewidth );
19104                 }
19105                rasterizer->scanline += CTX_FULL_AA;
19106             }
19107         }
19108         if (shape->uses != 0)
19109           {
19110             ctx_rasterizer_reset (rasterizer);
19111           }
19112         }
19113       }
19114     else
19115 #endif
19116     {
19117 
19118     ctx_rasterizer_rasterize_edges (rasterizer, rasterizer->state->gstate.fill_rule
19119 #if CTX_SHAPE_CACHE
19120                                     , NULL
19121 #endif
19122                                    );
19123     }
19124   }
19125 done:
19126   if (CTX_UNLIKELY(rasterizer->preserve))
19127     {
19128       memcpy (rasterizer->edge_list.entries, temp, sizeof (temp) );
19129       rasterizer->edge_list.count = preserved_count;
19130     }
19131 #if CTX_ENABLE_SHADOW_BLUR
19132   if (CTX_UNLIKELY(rasterizer->in_shadow))
19133   {
19134     rasterizer->scan_min -= rasterizer->shadow_y * CTX_FULL_AA;
19135     rasterizer->scan_max -= rasterizer->shadow_y * CTX_FULL_AA;
19136     rasterizer->col_min  -= (rasterizer->shadow_x - rasterizer->state->gstate.shadow_blur * 3 + 1) * CTX_SUBDIV;
19137     rasterizer->col_max  -= (rasterizer->shadow_x + rasterizer->state->gstate.shadow_blur * 3 + 1) * CTX_SUBDIV;
19138   }
19139 #endif
19140   rasterizer->preserve = 0;
19141 }
19142 
19143 #if 0
19144 static void
19145 ctx_rasterizer_triangle (CtxRasterizer *rasterizer,
19146                          int x0, int y0,
19147                          int x1, int y1,
19148                          int x2, int y2,
19149                          int r0, int g0, int b0, int a0,
19150                          int r1, int g1, int b1, int a1,
19151                          int r2, int g2, int b2, int a2,
19152                          int u0, int v0,
19153                          int u1, int v1)
19154 {
19155 
19156 }
19157 #endif
19158 
19159 
19160 typedef struct _CtxTermGlyph CtxTermGlyph;
19161 
19162 struct _CtxTermGlyph
19163 {
19164   uint32_t unichar;
19165   int      col;
19166   int      row;
19167   uint8_t  rgba_bg[4];
19168   uint8_t  rgba_fg[4];
19169 };
19170 
19171 static int _ctx_glyph (Ctx *ctx, uint32_t unichar, int stroke);
19172 static void
ctx_rasterizer_glyph(CtxRasterizer * rasterizer,uint32_t unichar,int stroke)19173 ctx_rasterizer_glyph (CtxRasterizer *rasterizer, uint32_t unichar, int stroke)
19174 {
19175   float tx = rasterizer->state->x;
19176   float ty = rasterizer->state->y - rasterizer->state->gstate.font_size;
19177   float tx2 = rasterizer->state->x + rasterizer->state->gstate.font_size;
19178   float ty2 = rasterizer->state->y + rasterizer->state->gstate.font_size;
19179   _ctx_user_to_device (rasterizer->state, &tx, &ty);
19180   _ctx_user_to_device (rasterizer->state, &tx2, &ty2);
19181 
19182   if (tx2 < rasterizer->blit_x || ty2 < rasterizer->blit_y) return;
19183   if (tx  > rasterizer->blit_x + rasterizer->blit_width ||
19184       ty  > rasterizer->blit_y + rasterizer->blit_height)
19185           return;
19186 
19187 #if CTX_BRAILLE_TEXT
19188   float font_size = 0;
19189   int ch = 1;
19190   int cw = 1;
19191 
19192   if (rasterizer->term_glyphs)
19193   {
19194     float tx = 0;
19195     font_size = rasterizer->state->gstate.font_size;
19196 
19197     ch = ctx_term_get_cell_height (rasterizer->ctx);
19198     cw = ctx_term_get_cell_width (rasterizer->ctx);
19199 
19200     _ctx_user_to_device_distance (rasterizer->state, &tx, &font_size);
19201   }
19202   if (rasterizer->term_glyphs && !stroke &&
19203       fabs (font_size - ch) < 0.5)
19204   {
19205     float tx = rasterizer->x;
19206     float ty = rasterizer->y;
19207     _ctx_user_to_device (rasterizer->state, &tx, &ty);
19208     int col = tx / cw + 1;
19209     int row = ty / ch + 1;
19210     CtxTermGlyph *glyph = ctx_calloc (sizeof (CtxTermGlyph), 1);
19211     ctx_list_append (&rasterizer->glyphs, glyph);
19212     glyph->unichar = unichar;
19213     glyph->col = col;
19214     glyph->row = row;
19215     ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color,
19216                          &glyph->rgba_fg[0]);
19217   }
19218   else
19219 #endif
19220   _ctx_glyph (rasterizer->ctx, unichar, stroke);
19221 }
19222 
19223 static void
19224 _ctx_text (Ctx        *ctx,
19225            const char *string,
19226            int         stroke,
19227            int         visible);
19228 static void
ctx_rasterizer_text(CtxRasterizer * rasterizer,const char * string,int stroke)19229 ctx_rasterizer_text (CtxRasterizer *rasterizer, const char *string, int stroke)
19230 {
19231 #if CTX_BRAILLE_TEXT
19232   float font_size = 0;
19233   if (rasterizer->term_glyphs)
19234   {
19235     float tx = 0;
19236     font_size = rasterizer->state->gstate.font_size;
19237     _ctx_user_to_device_distance (rasterizer->state, &tx, &font_size);
19238   }
19239   int   ch = ctx_term_get_cell_height (rasterizer->ctx);
19240   int   cw = ctx_term_get_cell_width (rasterizer->ctx);
19241 
19242   if (rasterizer->term_glyphs && !stroke &&
19243       fabs (font_size - ch) < 0.5)
19244   {
19245     float tx = rasterizer->x;
19246     float ty = rasterizer->y;
19247     _ctx_user_to_device (rasterizer->state, &tx, &ty);
19248     int col = tx / cw + 1;
19249     int row = ty / ch + 1;
19250     for (int i = 0; string[i]; i++, col++)
19251     {
19252       CtxTermGlyph *glyph = ctx_calloc (sizeof (CtxTermGlyph), 1);
19253       ctx_list_prepend (&rasterizer->glyphs, glyph);
19254       glyph->unichar = string[i];
19255       glyph->col = col;
19256       glyph->row = row;
19257       ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color,
19258                       glyph->rgba_fg);
19259     }
19260   }
19261   else
19262 #endif
19263   {
19264     _ctx_text (rasterizer->ctx, string, stroke, 1);
19265   }
19266 }
19267 
19268 void
19269 _ctx_font (Ctx *ctx, const char *name);
19270 static void
ctx_rasterizer_set_font(CtxRasterizer * rasterizer,const char * font_name)19271 ctx_rasterizer_set_font (CtxRasterizer *rasterizer, const char *font_name)
19272 {
19273   _ctx_font (rasterizer->ctx, font_name);
19274 }
19275 
19276 static void
ctx_rasterizer_arc(CtxRasterizer * rasterizer,float x,float y,float radius,float start_angle,float end_angle,int anticlockwise)19277 ctx_rasterizer_arc (CtxRasterizer *rasterizer,
19278                     float          x,
19279                     float          y,
19280                     float          radius,
19281                     float          start_angle,
19282                     float          end_angle,
19283                     int            anticlockwise)
19284 {
19285   int full_segments = CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS;
19286   full_segments = radius * CTX_PI * 2 / 4.0;
19287   if (full_segments > CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS)
19288     { full_segments = CTX_RASTERIZER_MAX_CIRCLE_SEGMENTS; }
19289   if (full_segments < 24) full_segments = 24;
19290   float step = CTX_PI*2.0/full_segments;
19291   int steps;
19292 
19293   if (end_angle < -30.0)
19294     end_angle = -30.0;
19295   if (start_angle < -30.0)
19296     start_angle = -30.0;
19297   if (end_angle > 30.0)
19298     end_angle = 30.0;
19299   if (start_angle > 30.0)
19300     start_angle = 30.0;
19301 
19302   if (radius <= 0.0001)
19303           return;
19304 
19305   if (end_angle == start_angle)
19306           // XXX also detect arcs fully outside render view
19307     {
19308     if (rasterizer->has_prev!=0)
19309       ctx_rasterizer_line_to (rasterizer, x + ctx_cosf (end_angle) * radius,
19310                               y + ctx_sinf (end_angle) * radius);
19311       else
19312       ctx_rasterizer_move_to (rasterizer, x + ctx_cosf (end_angle) * radius,
19313                             y + ctx_sinf (end_angle) * radius);
19314       return;
19315     }
19316 #if 1
19317   if ( (!anticlockwise && fabsf((end_angle - start_angle) - CTX_PI*2) < 0.01f)  ||
19318        ( (anticlockwise && fabsf((start_angle - end_angle) - CTX_PI*2) < 0.01f ) )
19319   ||   (anticlockwise && fabsf((end_angle - start_angle) - CTX_PI*2) < 0.01f)  ||  (!anticlockwise && fabsf((start_angle - end_angle) - CTX_PI*2) < 0.01f )  )
19320     {
19321       steps = full_segments - 1;
19322     }
19323   else
19324 #endif
19325     {
19326       steps = (end_angle - start_angle) / (CTX_PI*2) * full_segments;
19327       if (anticlockwise)
19328         { steps = full_segments - steps; };
19329    // if (steps > full_segments)
19330    //   steps = full_segments;
19331     }
19332   if (anticlockwise) { step = step * -1; }
19333   int first = 1;
19334   if (steps == 0 /* || steps==full_segments -1  || (anticlockwise && steps == full_segments) */)
19335     {
19336       float xv = x + ctx_cosf (start_angle) * radius;
19337       float yv = y + ctx_sinf (start_angle) * radius;
19338       if (!rasterizer->has_prev)
19339         { ctx_rasterizer_move_to (rasterizer, xv, yv); }
19340       first = 0;
19341     }
19342   else
19343     {
19344       for (float angle = start_angle, i = 0; i < steps; angle += step, i++)
19345         {
19346           float xv = x + ctx_cosf (angle) * radius;
19347           float yv = y + ctx_sinf (angle) * radius;
19348           if (first && !rasterizer->has_prev)
19349             { ctx_rasterizer_move_to (rasterizer, xv, yv); }
19350           else
19351             { ctx_rasterizer_line_to (rasterizer, xv, yv); }
19352           first = 0;
19353         }
19354     }
19355   ctx_rasterizer_line_to (rasterizer, x + ctx_cosf (end_angle) * radius,
19356                           y + ctx_sinf (end_angle) * radius);
19357 }
19358 
19359 static void
ctx_rasterizer_quad_to(CtxRasterizer * rasterizer,float cx,float cy,float x,float y)19360 ctx_rasterizer_quad_to (CtxRasterizer *rasterizer,
19361                         float        cx,
19362                         float        cy,
19363                         float        x,
19364                         float        y)
19365 {
19366   /* XXX : it is probably cheaper/faster to do quad interpolation directly -
19367    *       though it will increase the code-size, an
19368    *       alternative is to turn everything into cubic
19369    *       and deal with cubics more directly during
19370    *       rasterization
19371    */
19372   ctx_rasterizer_curve_to (rasterizer,
19373                            (cx * 2 + rasterizer->x) / 3.0f, (cy * 2 + rasterizer->y) / 3.0f,
19374                            (cx * 2 + x) / 3.0f,           (cy * 2 + y) / 3.0f,
19375                            x,                              y);
19376 }
19377 
19378 static void
ctx_rasterizer_rel_quad_to(CtxRasterizer * rasterizer,float cx,float cy,float x,float y)19379 ctx_rasterizer_rel_quad_to (CtxRasterizer *rasterizer,
19380                             float cx, float cy,
19381                             float x,  float y)
19382 {
19383   ctx_rasterizer_quad_to (rasterizer, cx + rasterizer->x, cy + rasterizer->y,
19384                           x  + rasterizer->x, y  + rasterizer->y);
19385 }
19386 
19387 #define LENGTH_OVERSAMPLE 1
19388 #if 0
19389 static void
19390 ctx_rasterizer_pset (CtxRasterizer *rasterizer, int x, int y, uint8_t cov)
19391 {
19392   // XXX - we avoid rendering here x==0 - to keep with
19393   //  an off-by one elsewhere
19394   //
19395   //  XXX onlt works in rgba8 formats
19396   if (x <= 0 || y < 0 || x >= rasterizer->blit_width ||
19397       y >= rasterizer->blit_height)
19398     { return; }
19399   uint8_t fg_color[4];
19400   ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, fg_color);
19401   uint8_t pixel[4];
19402   uint8_t *dst = ( (uint8_t *) rasterizer->buf);
19403   dst += y * rasterizer->blit_stride;
19404   dst += x * rasterizer->format->bpp / 8;
19405   if (!rasterizer->format->to_comp ||
19406       !rasterizer->format->from_comp)
19407     { return; }
19408   if (cov == 255)
19409     {
19410       for (int c = 0; c < 4; c++)
19411         {
19412           pixel[c] = fg_color[c];
19413         }
19414     }
19415   else
19416     {
19417       rasterizer->format->to_comp (rasterizer, x, dst, &pixel[0], 1);
19418       for (int c = 0; c < 4; c++)
19419         {
19420           pixel[c] = ctx_lerp_u8 (pixel[c], fg_color[c], cov);
19421         }
19422     }
19423   rasterizer->format->from_comp (rasterizer, x, &pixel[0], dst, 1);
19424 }
19425 #endif
19426 
19427 #if 0
19428 static void
19429 ctx_rasterizer_stroke_1px (CtxRasterizer *rasterizer)
19430 {
19431   int count = rasterizer->edge_list.count;
19432   CtxSegment *temp = (CtxSegment*)rasterizer->edge_list.entries;
19433   float prev_x = 0.0f;
19434   float prev_y = 0.0f;
19435   int aa = 15;//rasterizer->aa;
19436   int start = 0;
19437   int end = 0;
19438 #if 0
19439   float factor = ctx_matrix_get_scale (&state->gstate.transform);
19440 #endif
19441 
19442   while (start < count)
19443     {
19444       int started = 0;
19445       int i;
19446       for (i = start; i < count; i++)
19447         {
19448           CtxSegment *entry = &temp[i];
19449           float x, y;
19450           if (entry->code == CTX_NEW_EDGE)
19451             {
19452               if (started)
19453                 {
19454                   end = i - 1;
19455                   goto foo;
19456                 }
19457               prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
19458               prev_y = entry->data.s16[1] * 1.0f / aa;
19459               started = 1;
19460               start = i;
19461             }
19462           x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
19463           y = entry->data.s16[3] * 1.0f / aa;
19464           int dx = x - prev_x;
19465           int dy = y - prev_y;
19466           int length = ctx_maxf (abs (dx), abs (dy) );
19467           if (length)
19468             {
19469               length *= LENGTH_OVERSAMPLE;
19470               int len = length;
19471               int tx = prev_x * 256;
19472               int ty = prev_y * 256;
19473               dx *= 256;
19474               dy *= 256;
19475               dx /= length;
19476               dy /= length;
19477               for (int i = 0; i < len; i++)
19478                 {
19479                   ctx_rasterizer_pset (rasterizer, tx/256, ty/256, 255);
19480                   tx += dx;
19481                   ty += dy;
19482                   ctx_rasterizer_pset (rasterizer, tx/256, ty/256, 255);
19483                 }
19484             }
19485           prev_x = x;
19486           prev_y = y;
19487         }
19488       end = i-1;
19489 foo:
19490       start = end+1;
19491     }
19492   ctx_rasterizer_reset (rasterizer);
19493 }
19494 #endif
19495 
19496 static void
ctx_rasterizer_stroke(CtxRasterizer * rasterizer)19497 ctx_rasterizer_stroke (CtxRasterizer *rasterizer)
19498 {
19499   CtxGState *gstate = &rasterizer->state->gstate;
19500   CtxSource source_backup;
19501   int count = rasterizer->edge_list.count;
19502   if (count <= 0)
19503     return;
19504   if (gstate->source_stroke.type != CTX_SOURCE_INHERIT_FILL)
19505   {
19506     source_backup = gstate->source_fill;
19507     gstate->source_fill = rasterizer->state->gstate.source_stroke;
19508   }
19509   int preserved = rasterizer->preserve;
19510   float factor = ctx_matrix_get_scale (&gstate->transform);
19511   float line_width = gstate->line_width * factor;
19512 
19513   CtxSegment temp[count]; /* copy of already built up path's poly line  */
19514   memcpy (temp, rasterizer->edge_list.entries, sizeof (temp) );
19515 
19516 #if CTX_RECT_FILL
19517   if (rasterizer->edge_list.count == 5)
19518     {
19519       CtxSegment *entry0 = &((CtxSegment*)rasterizer->edge_list.entries)[0];
19520       CtxSegment *entry1 = &((CtxSegment*)rasterizer->edge_list.entries)[1];
19521       CtxSegment *entry2 = &((CtxSegment*)rasterizer->edge_list.entries)[2];
19522       CtxSegment *entry3 = &((CtxSegment*)rasterizer->edge_list.entries)[3];
19523       //fprintf (stderr, "{%i %.2f %.2f}", lw, lwmod, line_width);
19524 
19525       if (!rasterizer->state->gstate.clipped &&
19526           (entry0->data.s16[2] == entry1->data.s16[2]) &&
19527           (entry0->data.s16[3] == entry3->data.s16[3]) &&
19528           (entry1->data.s16[3] == entry2->data.s16[3]) &&
19529           (entry2->data.s16[2] == entry3->data.s16[2])
19530 #if CTX_ENABLE_SHADOW_BLUR
19531            && !rasterizer->in_shadow
19532 #endif
19533          )
19534        {
19535       float lwmod = ctx_fmod1f (line_width);
19536       int lw = ctx_floorf (line_width + 0.5f);
19537       int is_compat_even = (lw % 2 == 0) && (lwmod < 0.1); // only even linewidths implemented properly
19538       int is_compat_odd = (lw % 2 == 1) && (lwmod < 0.1); // only even linewidths implemented properly
19539 
19540       int off_x = 0;
19541       int off_y = 0;
19542 
19543 
19544       if (is_compat_odd)
19545       {
19546         off_x = CTX_SUBDIV/2;
19547         off_y = CTX_FULL_AA/2;
19548       }
19549 
19550       if((is_compat_odd || is_compat_even) &&
19551          (((entry1->data.s16[2]-off_x) % (CTX_SUBDIV))  == 0)  &&
19552          (((entry1->data.s16[3]-off_y) % (CTX_FULL_AA)) == 0) &&
19553          (((entry3->data.s16[2]-off_x) % (CTX_SUBDIV))  == 0)  &&
19554          (((entry3->data.s16[3]-off_y) % (CTX_FULL_AA)) == 0))
19555       {
19556         float x0 = entry3->data.s16[2] * 1.0f / CTX_SUBDIV;
19557         float y0 = entry3->data.s16[3] * 1.0f / CTX_FULL_AA;
19558         float x1 = entry1->data.s16[2] * 1.0f / CTX_SUBDIV;
19559         float y1 = entry1->data.s16[3] * 1.0f / CTX_FULL_AA;
19560 
19561         int bw = lw/2+1;
19562         int bwb = lw/2;
19563 
19564         if (is_compat_even)
19565         {
19566           bw = lw/2;
19567         }
19568         ctx_rasterizer_fill_rect (rasterizer, x0-bwb, y0-bwb, x1+bw, y0+bw, 255);
19569         ctx_rasterizer_fill_rect (rasterizer, x0-bwb, y1-bwb, x1-bwb, y1+bw, 255);
19570         ctx_rasterizer_fill_rect (rasterizer, x0-bwb, y0, x0+bw, y1, 255);
19571         ctx_rasterizer_fill_rect (rasterizer, x1-bwb, y0, x1+bw, y1+bw, 255);
19572         ctx_rasterizer_reset (rasterizer);
19573         goto done;
19574       }
19575        }
19576     }
19577 #endif
19578 
19579     {
19580 
19581   int aa = CTX_FULL_AA;
19582 #if 0
19583   if (CTX_UNLIKELY(gstate->line_width * factor <= 0.0f &&
19584       gstate->line_width * factor > -10.0f))
19585     {
19586       ctx_rasterizer_stroke_1px (rasterizer);
19587     }
19588   else
19589 #endif
19590     {
19591       if (line_width < 5.0f)
19592       {
19593       factor *= 0.89; /* this hack adjustment makes sharp 1px and 2px strokewidths
19594       //                 end up sharp without erronious AA; we seem to be off by
19595       //                 one somewhere else, causing the need for this
19596       //                 */
19597       line_width *= 0.89f;
19598       }
19599       ctx_rasterizer_reset (rasterizer); /* then start afresh with our stroked shape  */
19600       CtxMatrix transform_backup = gstate->transform;
19601       _ctx_matrix_identity (&gstate->transform);
19602       float prev_x = 0.0f;
19603       float prev_y = 0.0f;
19604       float half_width_x = line_width/2;
19605       float half_width_y = line_width/2;
19606       if (CTX_UNLIKELY(line_width <= 0.0f))
19607         { // makes 0 width be hairline
19608           half_width_x = .5f;
19609           half_width_y = .5f;
19610         }
19611       int start = 0;
19612       int end   = 0;
19613       while (start < count)
19614         {
19615           int started = 0;
19616           int i;
19617           for (i = start; i < count; i++)
19618             {
19619               CtxSegment *entry = &temp[i];
19620               float x, y;
19621               if (CTX_UNLIKELY(entry->code == CTX_NEW_EDGE))
19622                 {
19623                   if (CTX_LIKELY(started))
19624                     {
19625                       end = i - 1;
19626                       goto foo;
19627                     }
19628                   prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
19629                   prev_y = entry->data.s16[1] * 1.0f / aa;
19630                   started = 1;
19631                   start = i;
19632                 }
19633               x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
19634               y = entry->data.s16[3] * 1.0f / aa;
19635               float dx = x - prev_x;
19636               float dy = y - prev_y;
19637               float length = ctx_fast_hypotf (dx, dy);
19638               if (CTX_LIKELY(length>0.001f))
19639                 {
19640                   float recip_length = 1.0/length;
19641                   dx = dx * recip_length * half_width_x;
19642                   dy = dy * recip_length * half_width_y;
19643                   if (CTX_UNLIKELY(entry->code == CTX_NEW_EDGE))
19644                     {
19645                       ctx_rasterizer_finish_shape (rasterizer);
19646                       ctx_rasterizer_move_to (rasterizer, prev_x+dy, prev_y-dx);
19647                     }
19648                   ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
19649 
19650                   // we need to know the slope of the other side
19651 
19652                   // XXX possible miter line-to
19653                   //ctx_rasterizer_line_to (rasterizer, prev_x-dy+4, prev_y+dx+10);
19654                   //ctx_rasterizer_line_to (rasterizer, prev_x-dy+8, prev_y+dx+0);
19655 
19656 
19657                   ctx_rasterizer_line_to (rasterizer, x-dy, y+dx);
19658                 }
19659               prev_x = x;
19660               prev_y = y;
19661             }
19662           end = i-1;
19663 foo:
19664           for (int i = end; i >= start; i--)
19665             {
19666               CtxSegment *entry = &temp[i];
19667               float x, y, dx, dy;
19668               x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
19669               y = entry->data.s16[3] * 1.0f / aa;
19670               dx = x - prev_x;
19671               dy = y - prev_y;
19672               float length = ctx_fast_hypotf (dx, dy);
19673               float recip_length = 1.0f/length;
19674               dx = dx * recip_length * half_width_x;
19675               dy = dy * recip_length * half_width_y;
19676               if (CTX_LIKELY(length>0.001f))
19677                 {
19678                   ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
19679                   // XXX possible miter line-to
19680              //   ctx_rasterizer_line_to (rasterizer, prev_x-dy+10, prev_y+dx+10);
19681                   ctx_rasterizer_line_to (rasterizer, x-dy,      y+dx);
19682                 }
19683               prev_x = x;
19684               prev_y = y;
19685               if (CTX_UNLIKELY(entry->code == CTX_NEW_EDGE))
19686                 {
19687                   x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
19688                   y = entry->data.s16[1] * 1.0f / aa;
19689                   dx = x - prev_x;
19690                   dy = y - prev_y;
19691                   length = ctx_fast_hypotf (dx, dy);
19692                   recip_length = 1.0f/length;
19693                   if (CTX_LIKELY(length>0.001f))
19694                     {
19695                       dx = dx * recip_length * half_width_x;
19696                       dy = dy * recip_length * half_width_y;
19697                       ctx_rasterizer_line_to (rasterizer, prev_x-dy, prev_y+dx);
19698                       ctx_rasterizer_line_to (rasterizer, x-dy, y+dx);
19699                     }
19700                 }
19701               if ( (prev_x != x) && (prev_y != y) )
19702                 {
19703                   prev_x = x;
19704                   prev_y = y;
19705                 }
19706             }
19707           start = end+1;
19708         }
19709       ctx_rasterizer_finish_shape (rasterizer);
19710       switch (gstate->line_cap)
19711         {
19712           case CTX_CAP_SQUARE: // XXX: incorrect - if rectangles were in
19713                                //                  reverse order - rotation would be off
19714                                //                  better implement correct here
19715             {
19716               float x = 0, y = 0;
19717               int has_prev = 0;
19718               for (int i = 0; i < count; i++)
19719                 {
19720                   CtxSegment *entry = &temp[i];
19721                   if (CTX_UNLIKELY(entry->code == CTX_NEW_EDGE))
19722                     {
19723                       if (has_prev)
19724                         {
19725                           ctx_rasterizer_rectangle (rasterizer, x - half_width_x, y - half_width_y, half_width_x, half_width_y);
19726                           ctx_rasterizer_finish_shape (rasterizer);
19727                         }
19728                       x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
19729                       y = entry->data.s16[1] * 1.0f / aa;
19730                       ctx_rasterizer_rectangle (rasterizer, x - half_width_x, y - half_width_y, half_width_x * 2, half_width_y * 2);
19731                       ctx_rasterizer_finish_shape (rasterizer);
19732                     }
19733                   x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
19734                   y = entry->data.s16[3] * 1.0f / aa;
19735                   has_prev = 1;
19736                 }
19737               ctx_rasterizer_rectangle (rasterizer, x - half_width_x, y - half_width_y, half_width_x * 2, half_width_y * 2);
19738               ctx_rasterizer_finish_shape (rasterizer);
19739             }
19740             break;
19741           case CTX_CAP_NONE: /* nothing to do */
19742             break;
19743           case CTX_CAP_ROUND:
19744             {
19745               float x = 0, y = 0;
19746               int has_prev = 0;
19747               for (int i = 0; i < count; i++)
19748                 {
19749                   CtxSegment *entry = &temp[i];
19750                   if (CTX_UNLIKELY(entry->code == CTX_NEW_EDGE))
19751                     {
19752                       if (has_prev)
19753                         {
19754                           ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
19755                           ctx_rasterizer_finish_shape (rasterizer);
19756                         }
19757                       x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
19758                       y = entry->data.s16[1] * 1.0f / aa;
19759                       ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
19760                       ctx_rasterizer_finish_shape (rasterizer);
19761                     }
19762                   x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
19763                   y = entry->data.s16[3] * 1.0f / aa;
19764                   has_prev = 1;
19765                 }
19766               ctx_rasterizer_move_to (rasterizer, x, y);
19767               ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*3, 0, 1);
19768               ctx_rasterizer_finish_shape (rasterizer);
19769               break;
19770             }
19771         }
19772       switch (gstate->line_join)
19773         {
19774           case CTX_JOIN_BEVEL:
19775           case CTX_JOIN_MITER:
19776             break;
19777           case CTX_JOIN_ROUND:
19778             {
19779               float x = 0, y = 0;
19780               for (int i = 0; i < count-1; i++)
19781                 {
19782                   CtxSegment *entry = &temp[i];
19783                   x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
19784                   y = entry->data.s16[3] * 1.0f / aa;
19785                   if (CTX_UNLIKELY(entry[1].code == CTX_EDGE))
19786                     {
19787                       ctx_rasterizer_arc (rasterizer, x, y, half_width_x, CTX_PI*2, 0, 1);
19788                       ctx_rasterizer_finish_shape (rasterizer);
19789                     }
19790                 }
19791               break;
19792             }
19793         }
19794       CtxFillRule rule_backup = gstate->fill_rule;
19795       gstate->fill_rule = CTX_FILL_RULE_WINDING;
19796       rasterizer->preserve = 0; // so fill isn't tripped
19797       ctx_rasterizer_fill (rasterizer);
19798       gstate->fill_rule = rule_backup;
19799       gstate->transform = transform_backup;
19800     }
19801   }
19802 done:
19803   if (preserved)
19804     {
19805       memcpy (rasterizer->edge_list.entries, temp, sizeof (temp) );
19806       rasterizer->edge_list.count = count;
19807       rasterizer->preserve = 0;
19808     }
19809   if (gstate->source_stroke.type != CTX_SOURCE_INHERIT_FILL)
19810     gstate->source_fill = source_backup;
19811 }
19812 
19813 #if CTX_1BIT_CLIP
19814 #define CTX_CLIP_FORMAT CTX_FORMAT_GRAY1
19815 #else
19816 #define CTX_CLIP_FORMAT CTX_FORMAT_GRAY8
19817 #endif
19818 
19819 
19820 static void
ctx_rasterizer_clip_reset(CtxRasterizer * rasterizer)19821 ctx_rasterizer_clip_reset (CtxRasterizer *rasterizer)
19822 {
19823 #if CTX_ENABLE_CLIP
19824   if (rasterizer->clip_buffer)
19825    ctx_buffer_free (rasterizer->clip_buffer);
19826   rasterizer->clip_buffer = NULL;
19827 #endif
19828   rasterizer->state->gstate.clip_min_x = rasterizer->blit_x;
19829   rasterizer->state->gstate.clip_min_y = rasterizer->blit_y;
19830 
19831   rasterizer->state->gstate.clip_max_x = rasterizer->blit_x + rasterizer->blit_width - 1;
19832   rasterizer->state->gstate.clip_max_y = rasterizer->blit_y + rasterizer->blit_height - 1;
19833 }
19834 
19835 static void
ctx_rasterizer_clip_apply(CtxRasterizer * rasterizer,CtxSegment * edges)19836 ctx_rasterizer_clip_apply (CtxRasterizer *rasterizer,
19837                            CtxSegment    *edges)
19838 {
19839   int count = edges[0].data.u32[0];
19840 
19841   int minx = 5000;
19842   int miny = 5000;
19843   int maxx = -5000;
19844   int maxy = -5000;
19845   int prev_x = 0;
19846   int prev_y = 0;
19847   int blit_width = rasterizer->blit_width;
19848   int blit_height = rasterizer->blit_height;
19849 
19850   int aa = 15;//rasterizer->aa;
19851   float coords[6][2];
19852 
19853   for (int i = 0; i < count; i++)
19854     {
19855       CtxSegment *entry = &edges[i+1];
19856       float x, y;
19857       if (entry->code == CTX_NEW_EDGE)
19858         {
19859           prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
19860           prev_y = entry->data.s16[1] * 1.0f / aa;
19861           if (prev_x < minx) { minx = prev_x; }
19862           if (prev_y < miny) { miny = prev_y; }
19863           if (prev_x > maxx) { maxx = prev_x; }
19864           if (prev_y > maxy) { maxy = prev_y; }
19865         }
19866       x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
19867       y = entry->data.s16[3] * 1.0f / aa;
19868       if (x < minx) { minx = x; }
19869       if (y < miny) { miny = y; }
19870       if (x > maxx) { maxx = x; }
19871       if (y > maxy) { maxy = y; }
19872 
19873       if (i < 6)
19874       {
19875         coords[i][0] = x;
19876         coords[i][1] = y;
19877       }
19878     }
19879 
19880 #if CTX_ENABLE_CLIP
19881 
19882   if ((rasterizer->clip_rectangle==1
19883        || !rasterizer->clip_buffer)
19884       )
19885   {
19886     if (count == 5)
19887     {
19888       if (coords[0][0] == coords[1][0] &&
19889           coords[0][1] == coords[4][1] &&
19890           coords[0][1] == coords[3][1] &&
19891           coords[1][1] == coords[2][1] &&
19892           coords[3][0] == coords[4][0]
19893           )
19894       {
19895 #if 0
19896         printf ("%d,%d %dx%d\n", minx, miny,
19897                                        maxx-minx+1, maxy-miny+1);
19898 #endif
19899 
19900          rasterizer->state->gstate.clip_min_x =
19901             ctx_maxi (minx, rasterizer->state->gstate.clip_min_x);
19902          rasterizer->state->gstate.clip_min_y =
19903             ctx_maxi (miny, rasterizer->state->gstate.clip_min_y);
19904          rasterizer->state->gstate.clip_max_x =
19905             ctx_mini (maxx, rasterizer->state->gstate.clip_max_x);
19906          rasterizer->state->gstate.clip_max_y =
19907             ctx_mini (maxy, rasterizer->state->gstate.clip_max_y);
19908 
19909          rasterizer->clip_rectangle = 1;
19910 
19911 #if 0
19912          if (!rasterizer->clip_buffer)
19913            rasterizer->clip_buffer = ctx_buffer_new (blit_width,
19914                                                      blit_height,
19915                                                      CTX_CLIP_FORMAT);
19916 
19917          memset (rasterizer->clip_buffer->data, 0, blit_width * blit_height);
19918          int i = 0;
19919          for (int y = rasterizer->state->gstate.clip_min_y;
19920                   y <= rasterizer->state->gstate.clip_max_y;
19921                   y++)
19922          for (int x = rasterizer->state->gstate.clip_min_x;
19923                   x <= rasterizer->state->gstate.clip_max_x;
19924                   x++, i++)
19925          {
19926            ((uint8_t*)(rasterizer->clip_buffer->data))[i] = 255;
19927          }
19928 #endif
19929 
19930          return;
19931       }
19932 #if 0
19933       else
19934       {
19935         printf ("%d,%d %dx%d  0,0:%.2f 0,1:%.2f 1,0:%.2f 11:%.2f 20:%.2f 21:%2.f 30:%.2f 31:%.2f 40:%.2f 41:%.2f\n", minx, miny,
19936                                        maxx-minx+1, maxy-miny+1
19937 
19938          ,coords[0][0] ,  coords[0][1]
19939          ,coords[1][0] ,  coords[1][1]
19940          ,coords[2][0] ,  coords[2][1]
19941          ,coords[3][0] ,  coords[3][1]
19942          ,coords[4][0] ,  coords[4][1]
19943          );
19944       }
19945 #endif
19946     }
19947   }
19948   rasterizer->clip_rectangle = 0;
19949 
19950   if ((minx == maxx) || (miny == maxy)) // XXX : reset hack
19951   {
19952     ctx_rasterizer_clip_reset (rasterizer);
19953     return;//goto done;
19954   }
19955 
19956   int we_made_it = 0;
19957   CtxBuffer *clip_buffer;
19958 
19959   if (!rasterizer->clip_buffer)
19960   {
19961     rasterizer->clip_buffer = ctx_buffer_new (blit_width,
19962                                               blit_height,
19963                                               CTX_CLIP_FORMAT);
19964     clip_buffer = rasterizer->clip_buffer;
19965     we_made_it = 1;
19966     if (CTX_CLIP_FORMAT == CTX_FORMAT_GRAY1)
19967       memset (rasterizer->clip_buffer->data, 0, blit_width * blit_height/8);
19968     else
19969       memset (rasterizer->clip_buffer->data, 0, blit_width * blit_height);
19970   }
19971   else
19972   {
19973     clip_buffer = ctx_buffer_new (blit_width, blit_height,
19974                                   CTX_CLIP_FORMAT);
19975   }
19976 
19977   {
19978 
19979   int prev_x = 0;
19980   int prev_y = 0;
19981 
19982     Ctx *ctx = ctx_new_for_framebuffer (clip_buffer->data, blit_width, blit_height,
19983        blit_width,
19984        CTX_CLIP_FORMAT);
19985 
19986   for (int i = 0; i < count; i++)
19987     {
19988       CtxSegment *entry = &edges[i+1];
19989       float x, y;
19990       if (entry->code == CTX_NEW_EDGE)
19991         {
19992           prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
19993           prev_y = entry->data.s16[1] * 1.0f / aa;
19994           ctx_move_to (ctx, prev_x, prev_y);
19995         }
19996       x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
19997       y = entry->data.s16[3] * 1.0f / aa;
19998       ctx_line_to (ctx, x, y);
19999     }
20000     ctx_gray (ctx, 1.0f);
20001     ctx_fill (ctx);
20002     ctx_free (ctx);
20003   }
20004 
20005   int maybe_rect = 1;
20006   rasterizer->clip_rectangle = 0;
20007 
20008   if (CTX_CLIP_FORMAT == CTX_FORMAT_GRAY1)
20009   {
20010     int count = blit_width * blit_height / 8;
20011     for (int i = 0; i < count; i++)
20012     {
20013       ((uint8_t*)rasterizer->clip_buffer->data)[i] =
20014       (((uint8_t*)rasterizer->clip_buffer->data)[i] &
20015       ((uint8_t*)clip_buffer->data)[i]);
20016     }
20017   }
20018   else
20019   {
20020     int count = blit_width * blit_height;
20021 
20022 
20023     int i;
20024     int x0 = 0;
20025     int y0 = 0;
20026     int width = -1;
20027     int next_stage = 0;
20028     uint8_t *p_data = (uint8_t*)rasterizer->clip_buffer->data;
20029     uint8_t *data = (uint8_t*)clip_buffer->data;
20030 
20031     i=0;
20032     /* find upper left */
20033     for (; i < count && maybe_rect && !next_stage; i++)
20034     {
20035       uint8_t val = (p_data[i] * data[i])/255;
20036       data[i] = val;
20037       switch (val)
20038       {
20039         case 255:
20040           x0 = i % blit_width;
20041           y0 = i / blit_width;
20042           next_stage = 1;
20043           break;
20044         case 0: break;
20045         default:
20046           maybe_rect = 0;
20047           break;
20048       }
20049     }
20050 
20051     next_stage = 0;
20052     /* figure out with */
20053     for (; i < count && !next_stage && maybe_rect; i++)
20054     {
20055       int x = i % blit_width;
20056       int y = i / blit_width;
20057       uint8_t val = (p_data[i] * data[i])/255;
20058       data[i] = val;
20059 
20060       if (y == y0)
20061       {
20062         switch (val)
20063         {
20064           case 255:
20065             width = x - x0 + 1;
20066             break;
20067           case 0:
20068             next_stage = 1;
20069             break;
20070           default:
20071             maybe_rect = 0;
20072             break;
20073         }
20074         if (x % blit_width == blit_width - 1) next_stage = 1;
20075       }
20076       else next_stage = 1;
20077     }
20078 
20079     next_stage = 0;
20080     /* body */
20081     for (; i < count && maybe_rect && !next_stage; i++)
20082     {
20083       int x = i % blit_width;
20084       uint8_t val = (p_data[i] * data[i])/255;
20085       data[i] = val;
20086 
20087       if (x < x0)
20088       {
20089         if (val != 0){ maybe_rect = 0; next_stage = 1; }
20090       } else if (x < x0 + width)
20091       {
20092         if (val != 255){ if (val != 0) maybe_rect = 0; next_stage = 1; }
20093       } else {
20094         if (val != 0){ maybe_rect = 0; next_stage = 1; }
20095       }
20096     }
20097 
20098     next_stage = 0;
20099     /* foot */
20100     for (; i < count && maybe_rect && !next_stage; i++)
20101     {
20102       uint8_t val = (p_data[i] * data[i])/255;
20103       data[i] = val;
20104 
20105       if (val != 0){ maybe_rect = 0; next_stage = 1; }
20106     }
20107 
20108 
20109     for (; i < count; i++)
20110     {
20111       uint8_t val = (p_data[i] * data[i])/255;
20112       data[i] = val;
20113     }
20114 
20115     if (maybe_rect)
20116        rasterizer->clip_rectangle = 1;
20117   }
20118   if (!we_made_it)
20119    ctx_buffer_free (clip_buffer);
20120 #else
20121   if (coords[0][0]){};
20122 #endif
20123 
20124   rasterizer->state->gstate.clip_min_x = ctx_maxi (minx,
20125                                          rasterizer->state->gstate.clip_min_x);
20126   rasterizer->state->gstate.clip_min_y = ctx_maxi (miny,
20127                                          rasterizer->state->gstate.clip_min_y);
20128   rasterizer->state->gstate.clip_max_x = ctx_mini (maxx,
20129                                          rasterizer->state->gstate.clip_max_x);
20130   rasterizer->state->gstate.clip_max_y = ctx_mini (maxy,
20131                                          rasterizer->state->gstate.clip_max_y);
20132 }
20133 
20134 static void
ctx_rasterizer_clip(CtxRasterizer * rasterizer)20135 ctx_rasterizer_clip (CtxRasterizer *rasterizer)
20136 {
20137   int count = rasterizer->edge_list.count;
20138   CtxSegment temp[count+1]; /* copy of already built up path's poly line  */
20139   rasterizer->state->has_clipped=1;
20140   rasterizer->state->gstate.clipped=1;
20141   //if (rasterizer->preserve)
20142     { memcpy (temp + 1, rasterizer->edge_list.entries, sizeof (temp) - sizeof (temp[0]));
20143       temp[0].code = CTX_NOP;
20144       temp[0].data.u32[0] = count;
20145       ctx_state_set_blob (rasterizer->state, CTX_clip, (uint8_t*)temp, sizeof(temp));
20146     }
20147   ctx_rasterizer_clip_apply (rasterizer, temp);
20148   ctx_rasterizer_reset (rasterizer);
20149   if (rasterizer->preserve)
20150     {
20151       memcpy (rasterizer->edge_list.entries, temp + 1, sizeof (temp) - sizeof(temp[0]));
20152       rasterizer->edge_list.count = count;
20153       rasterizer->preserve = 0;
20154     }
20155 }
20156 
20157 
20158 #if 0
20159 static void
20160 ctx_rasterizer_load_image (CtxRasterizer *rasterizer,
20161                            const char  *path,
20162                            float x,
20163                            float y)
20164 {
20165   // decode PNG, put it in image is slot 1,
20166   // magic width height stride format data
20167   ctx_buffer_load_png (&rasterizer->ctx->texture[0], path);
20168   ctx_rasterizer_set_texture (rasterizer, 0, x, y);
20169 }
20170 #endif
20171 
20172 
20173 CTX_INLINE void
ctx_rasterizer_rectangle(CtxRasterizer * rasterizer,float x,float y,float width,float height)20174 ctx_rasterizer_rectangle (CtxRasterizer *rasterizer,
20175                           float x,
20176                           float y,
20177                           float width,
20178                           float height)
20179 {
20180   ctx_rasterizer_move_to (rasterizer, x, y);
20181   ctx_rasterizer_rel_line_to (rasterizer, width, 0);
20182   ctx_rasterizer_rel_line_to (rasterizer, 0, height);
20183   ctx_rasterizer_rel_line_to (rasterizer, -width, 0);
20184   ctx_rasterizer_rel_line_to (rasterizer, 0, -height);
20185   //ctx_rasterizer_rel_line_to (rasterizer, width/2, 0);
20186   ctx_rasterizer_finish_shape (rasterizer);
20187 }
20188 
20189 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)20190 ctx_rasterizer_set_pixel (CtxRasterizer *rasterizer,
20191                           uint16_t x,
20192                           uint16_t y,
20193                           uint8_t r,
20194                           uint8_t g,
20195                           uint8_t b,
20196                           uint8_t a)
20197 {
20198   rasterizer->state->gstate.source_fill.type = CTX_SOURCE_COLOR;
20199   ctx_color_set_RGBA8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, r, g, b, a);
20200   rasterizer->comp_op = NULL;
20201 #if 0
20202   // XXX : doesn't take transforms into account - and has
20203   // received less testing than code paths part of protocol,
20204   // using rectangle properly will trigger the fillrect fastpath
20205   ctx_rasterizer_pset (rasterizer, x, y, 255);
20206 #else
20207   ctx_rasterizer_rectangle (rasterizer, x, y, 1.0, 1.0);
20208   ctx_rasterizer_fill (rasterizer);
20209 #endif
20210 }
20211 
20212 #if CTX_ENABLE_SHADOW_BLUR
20213 static float
ctx_gaussian(float x,float mu,float sigma)20214 ctx_gaussian (float x, float mu, float sigma)
20215 {
20216   float a = ( x- mu) / sigma;
20217   return ctx_expf (-0.5 * a * a);
20218 }
20219 
20220 static void
ctx_compute_gaussian_kernel(int dim,float radius,float * kernel)20221 ctx_compute_gaussian_kernel (int dim, float radius, float *kernel)
20222 {
20223   float sigma = radius / 2;
20224   float sum = 0.0;
20225   int i = 0;
20226   //for (int row = 0; row < dim; row ++)
20227     for (int col = 0; col < dim; col ++, i++)
20228     {
20229       float val = //ctx_gaussian (row, radius, sigma) *
20230                             ctx_gaussian (col, radius, sigma);
20231       kernel[i] = val;
20232       sum += val;
20233     }
20234   i = 0;
20235   //for (int row = 0; row < dim; row ++)
20236     for (int col = 0; col < dim; col ++, i++)
20237         kernel[i] /= sum;
20238 }
20239 #endif
20240 
20241 static void
ctx_rasterizer_round_rectangle(CtxRasterizer * rasterizer,float x,float y,float width,float height,float corner_radius)20242 ctx_rasterizer_round_rectangle (CtxRasterizer *rasterizer, float x, float y, float width, float height, float corner_radius)
20243 {
20244   float aspect  = 1.0f;
20245   float radius  = corner_radius / aspect;
20246   float degrees = CTX_PI / 180.0f;
20247 
20248   if (radius > width*0.5f) radius = width/2;
20249   if (radius > height*0.5f) radius = height/2;
20250 
20251   ctx_rasterizer_finish_shape (rasterizer);
20252   ctx_rasterizer_arc (rasterizer, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees, 0);
20253   ctx_rasterizer_arc (rasterizer, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees, 0);
20254   ctx_rasterizer_arc (rasterizer, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees, 0);
20255   ctx_rasterizer_arc (rasterizer, x + radius, y + radius, radius, 180 * degrees, 270 * degrees, 0);
20256 
20257   ctx_rasterizer_finish_shape (rasterizer);
20258 }
20259 
20260 static void
20261 ctx_rasterizer_process (void *user_data, CtxCommand *command);
20262 
20263 int
_ctx_is_rasterizer(Ctx * ctx)20264 _ctx_is_rasterizer (Ctx *ctx)
20265 {
20266   if (ctx->renderer && ctx->renderer->process == ctx_rasterizer_process)
20267     return 1;
20268   return 0;
20269 }
20270 
20271 #if CTX_COMPOSITING_GROUPS
20272 static void
ctx_rasterizer_start_group(CtxRasterizer * rasterizer)20273 ctx_rasterizer_start_group (CtxRasterizer *rasterizer)
20274 {
20275   CtxEntry save_command = ctx_void(CTX_SAVE);
20276   // allocate buffer, and set it as temporary target
20277   int no;
20278   if (rasterizer->group[0] == NULL) // first group
20279   {
20280     rasterizer->saved_buf = rasterizer->buf;
20281   }
20282   for (no = 0; rasterizer->group[no] && no < CTX_GROUP_MAX; no++);
20283 
20284   if (no >= CTX_GROUP_MAX)
20285      return;
20286   rasterizer->group[no] = ctx_buffer_new (rasterizer->blit_width,
20287                                           rasterizer->blit_height,
20288                                           rasterizer->format->composite_format);
20289   rasterizer->buf = rasterizer->group[no]->data;
20290   ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
20291 }
20292 
20293 static void
ctx_rasterizer_end_group(CtxRasterizer * rasterizer)20294 ctx_rasterizer_end_group (CtxRasterizer *rasterizer)
20295 {
20296   CtxEntry restore_command = ctx_void(CTX_RESTORE);
20297   CtxEntry save_command = ctx_void(CTX_SAVE);
20298   int no = 0;
20299   for (no = 0; rasterizer->group[no] && no < CTX_GROUP_MAX; no++);
20300   no--;
20301 
20302   if (no < 0)
20303     return;
20304 
20305   CtxCompositingMode comp = rasterizer->state->gstate.compositing_mode;
20306   CtxBlend blend = rasterizer->state->gstate.blend_mode;
20307   float global_alpha = rasterizer->state->gstate.global_alpha_f;
20308   // fetch compositing, blending, global alpha
20309   ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
20310   ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
20311   CtxEntry set_state[3]=
20312   {
20313     ctx_u32 (CTX_COMPOSITING_MODE, comp,  0),
20314     ctx_u32 (CTX_BLEND_MODE,       blend, 0),
20315     ctx_f  (CTX_GLOBAL_ALPHA,     global_alpha, 0.0)
20316   };
20317   ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[0]);
20318   ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[1]);
20319   ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_state[2]);
20320   if (no == 0)
20321   {
20322     rasterizer->buf = rasterizer->saved_buf;
20323   }
20324   else
20325   {
20326     rasterizer->buf = rasterizer->group[no-1]->data;
20327   }
20328   // XXX use texture_source ?
20329    ctx_texture_init (rasterizer->ctx, ".ctx-group", // XXX ? count groups..
20330                   rasterizer->blit_width,  // or have group based on thread-id?
20331                   rasterizer->blit_height, // .. this would mean threadsafe
20332                                            // allocation
20333                   rasterizer->blit_width * rasterizer->format->bpp/8,
20334                   rasterizer->format->pixel_format,
20335                   NULL, // space
20336                   (uint8_t*)rasterizer->group[no]->data,
20337                   NULL, NULL);
20338   {
20339      const char *eid = ".ctx-group";
20340      int   eid_len = strlen (eid);
20341 
20342      CtxEntry commands[4] =
20343       {
20344        ctx_f  (CTX_TEXTURE, rasterizer->blit_x, rasterizer->blit_y),
20345        ctx_u32 (CTX_DATA, eid_len, eid_len/9+1),
20346        ctx_u32 (CTX_CONT, 0,0),
20347        ctx_u32 (CTX_CONT, 0,0)
20348       };
20349      memcpy( (char *) &commands[2].data.u8[0], eid, eid_len);
20350      ( (char *) (&commands[2].data.u8[0]) ) [eid_len]=0;
20351 
20352      ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
20353   }
20354   {
20355     CtxEntry commands[2]=
20356     {
20357       ctx_f (CTX_RECTANGLE, rasterizer->blit_x, rasterizer->blit_y),
20358       ctx_f (CTX_CONT,      rasterizer->blit_width, rasterizer->blit_height)
20359     };
20360     ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
20361   }
20362   {
20363     CtxEntry commands[1]= { ctx_void (CTX_FILL) };
20364     ctx_rasterizer_process (rasterizer, (CtxCommand*)commands);
20365   }
20366   //ctx_texture_release (rasterizer->ctx, ".ctx-group");
20367   ctx_buffer_free (rasterizer->group[no]);
20368   rasterizer->group[no] = 0;
20369   ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
20370 }
20371 #endif
20372 
20373 #if CTX_ENABLE_SHADOW_BLUR
20374 static void
ctx_rasterizer_shadow_stroke(CtxRasterizer * rasterizer)20375 ctx_rasterizer_shadow_stroke (CtxRasterizer *rasterizer)
20376 {
20377   CtxColor color;
20378   CtxEntry save_command = ctx_void(CTX_SAVE);
20379 
20380   float rgba[4] = {0, 0, 0, 1.0};
20381   if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
20382     ctx_color_get_rgba (rasterizer->state, &color, rgba);
20383 
20384   CtxEntry set_color_command [3]=
20385   {
20386     ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
20387     ctx_f (CTX_CONT, rgba[1], rgba[2]),
20388     ctx_f (CTX_CONT, rgba[3], 0)
20389   };
20390   CtxEntry restore_command = ctx_void(CTX_RESTORE);
20391   float radius = rasterizer->state->gstate.shadow_blur;
20392   int dim = 2 * radius + 1;
20393   if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
20394     dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
20395   ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
20396   ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
20397   {
20398     int i = 0;
20399     for (int v = 0; v < dim; v += 1, i++)
20400       {
20401         float dy = rasterizer->state->gstate.shadow_offset_y + v - dim/2;
20402         set_color_command[2].data.f[0] = rasterizer->kernel[i] * rgba[3];
20403         ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command[0]);
20404 #if CTX_ENABLE_SHADOW_BLUR
20405         rasterizer->in_shadow = 1;
20406 #endif
20407         rasterizer->shadow_x = rasterizer->state->gstate.shadow_offset_x;
20408         rasterizer->shadow_y = dy;
20409         rasterizer->preserve = 1;
20410         ctx_rasterizer_stroke (rasterizer);
20411 #if CTX_ENABLE_SHADOW_BLUR
20412         rasterizer->in_shadow = 0;
20413 #endif
20414       }
20415   }
20416   //free (kernel);
20417   ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
20418 }
20419 
20420 static void
ctx_rasterizer_shadow_text(CtxRasterizer * rasterizer,const char * str)20421 ctx_rasterizer_shadow_text (CtxRasterizer *rasterizer, const char *str)
20422 {
20423   float x = rasterizer->state->x;
20424   float y = rasterizer->state->y;
20425   CtxColor color;
20426   CtxEntry save_command = ctx_void(CTX_SAVE);
20427 
20428   float rgba[4] = {0, 0, 0, 1.0};
20429   if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
20430     ctx_color_get_rgba (rasterizer->state, &color, rgba);
20431 
20432   CtxEntry set_color_command [3]=
20433   {
20434     ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
20435     ctx_f (CTX_CONT, rgba[1], rgba[2]),
20436     ctx_f (CTX_CONT, rgba[3], 0)
20437   };
20438   CtxEntry move_to_command [1]=
20439   {
20440     ctx_f (CTX_MOVE_TO, x, y),
20441   };
20442   CtxEntry restore_command = ctx_void(CTX_RESTORE);
20443   float radius = rasterizer->state->gstate.shadow_blur;
20444   int dim = 2 * radius + 1;
20445   if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
20446     dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
20447   ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
20448   ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
20449 
20450   {
20451       {
20452         move_to_command[0].data.f[0] = x;
20453         move_to_command[0].data.f[1] = y;
20454         set_color_command[2].data.f[0] = rgba[3];
20455         ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command);
20456         ctx_rasterizer_process (rasterizer, (CtxCommand*)&move_to_command);
20457         rasterizer->in_shadow=1;
20458         ctx_rasterizer_text (rasterizer, str, 0);
20459         rasterizer->in_shadow=0;
20460       }
20461   }
20462   ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
20463   move_to_command[0].data.f[0] = x;
20464   move_to_command[0].data.f[1] = y;
20465   ctx_rasterizer_process (rasterizer, (CtxCommand*)&move_to_command);
20466 }
20467 
20468 static void
ctx_rasterizer_shadow_fill(CtxRasterizer * rasterizer)20469 ctx_rasterizer_shadow_fill (CtxRasterizer *rasterizer)
20470 {
20471   CtxColor color;
20472   CtxEntry save_command = ctx_void(CTX_SAVE);
20473 
20474   float rgba[4] = {0, 0, 0, 1.0};
20475   if (ctx_get_color (rasterizer->ctx, CTX_shadowColor, &color) == 0)
20476     ctx_color_get_rgba (rasterizer->state, &color, rgba);
20477 
20478   CtxEntry set_color_command [3]=
20479   {
20480     ctx_f (CTX_COLOR, CTX_RGBA, rgba[0]),
20481     ctx_f (CTX_CONT, rgba[1], rgba[2]),
20482     ctx_f (CTX_CONT, rgba[3], 0)
20483   };
20484   CtxEntry restore_command = ctx_void(CTX_RESTORE);
20485   float radius = rasterizer->state->gstate.shadow_blur;
20486   int dim = 2 * radius + 1;
20487   if (dim > CTX_MAX_GAUSSIAN_KERNEL_DIM)
20488     dim = CTX_MAX_GAUSSIAN_KERNEL_DIM;
20489   ctx_compute_gaussian_kernel (dim, radius, rasterizer->kernel);
20490   ctx_rasterizer_process (rasterizer, (CtxCommand*)&save_command);
20491 
20492   {
20493     for (int v = 0; v < dim; v ++)
20494       {
20495         int i = v;
20496         float dy = rasterizer->state->gstate.shadow_offset_y + v - dim/2;
20497         set_color_command[2].data.f[0] = rasterizer->kernel[i] * rgba[3];
20498         ctx_rasterizer_process (rasterizer, (CtxCommand*)&set_color_command);
20499         rasterizer->in_shadow = 1;
20500         rasterizer->shadow_x = rasterizer->state->gstate.shadow_offset_x;
20501         rasterizer->shadow_y = dy;
20502         rasterizer->preserve = 1;
20503         ctx_rasterizer_fill (rasterizer);
20504         rasterizer->in_shadow = 0;
20505       }
20506   }
20507   ctx_rasterizer_process (rasterizer, (CtxCommand*)&restore_command);
20508 }
20509 #endif
20510 
20511 static void
ctx_rasterizer_line_dash(CtxRasterizer * rasterizer,int count,float * dashes)20512 ctx_rasterizer_line_dash (CtxRasterizer *rasterizer, int count, float *dashes)
20513 {
20514   if (!dashes)
20515   {
20516     rasterizer->state->gstate.n_dashes = 0;
20517     return;
20518   }
20519   count = CTX_MIN(count, CTX_PARSER_MAX_ARGS-1);
20520   rasterizer->state->gstate.n_dashes = count;
20521   memcpy(&rasterizer->state->gstate.dashes[0], dashes, count * sizeof(float));
20522   for (int i = 0; i < count; i ++)
20523   {
20524     if (rasterizer->state->gstate.dashes[i] < 0.0001f)
20525       rasterizer->state->gstate.dashes[i] = 0.0001f; // hang protection
20526   }
20527 }
20528 
20529 
20530 static void
ctx_rasterizer_process(void * user_data,CtxCommand * command)20531 ctx_rasterizer_process (void *user_data, CtxCommand *command)
20532 {
20533   CtxEntry *entry = &command->entry;
20534   CtxRasterizer *rasterizer = (CtxRasterizer *) user_data;
20535   CtxState *state = rasterizer->state;
20536   CtxCommand *c = (CtxCommand *) entry;
20537   int clear_clip = 0;
20538   ctx_interpret_style (state, entry, NULL);
20539   switch (c->code)
20540     {
20541 #if CTX_ENABLE_SHADOW_BLUR
20542       case CTX_SHADOW_COLOR:
20543         {
20544           CtxColor  col;
20545           CtxColor *color = &col;
20546           //state->gstate.source_fill.type = CTX_SOURCE_COLOR;
20547           switch ((int)c->rgba.model)
20548             {
20549               case CTX_RGB:
20550                 ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, 1.0f);
20551                 break;
20552               case CTX_RGBA:
20553                 //ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
20554                 ctx_color_set_rgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
20555                 break;
20556               case CTX_DRGBA:
20557                 ctx_color_set_drgba (state, color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
20558                 break;
20559 #if CTX_ENABLE_CMYK
20560               case CTX_CMYKA:
20561                 ctx_color_set_cmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, c->cmyka.a);
20562                 break;
20563               case CTX_CMYK:
20564                 ctx_color_set_cmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, 1.0f);
20565                 break;
20566               case CTX_DCMYKA:
20567                 ctx_color_set_dcmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, c->cmyka.a);
20568                 break;
20569               case CTX_DCMYK:
20570                 ctx_color_set_dcmyka (state, color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, 1.0f);
20571                 break;
20572 #endif
20573               case CTX_GRAYA:
20574                 ctx_color_set_graya (state, color, c->graya.g, c->graya.a);
20575                 break;
20576               case CTX_GRAY:
20577                 ctx_color_set_graya (state, color, c->graya.g, 1.0f);
20578                 break;
20579             }
20580           ctx_set_color (rasterizer->ctx, CTX_shadowColor, color);
20581         }
20582         break;
20583 #endif
20584       case CTX_LINE_DASH:
20585         if (c->line_dash.count)
20586           {
20587             ctx_rasterizer_line_dash (rasterizer, c->line_dash.count, c->line_dash.data);
20588           }
20589         else
20590         ctx_rasterizer_line_dash (rasterizer, 0, NULL);
20591         break;
20592 
20593       case CTX_LINE_TO:
20594         ctx_rasterizer_line_to (rasterizer, c->c.x0, c->c.y0);
20595         break;
20596       case CTX_REL_LINE_TO:
20597         ctx_rasterizer_rel_line_to (rasterizer, c->c.x0, c->c.y0);
20598         break;
20599       case CTX_MOVE_TO:
20600         ctx_rasterizer_move_to (rasterizer, c->c.x0, c->c.y0);
20601         break;
20602       case CTX_REL_MOVE_TO:
20603         ctx_rasterizer_rel_move_to (rasterizer, c->c.x0, c->c.y0);
20604         break;
20605       case CTX_CURVE_TO:
20606         ctx_rasterizer_curve_to (rasterizer, c->c.x0, c->c.y0,
20607                                  c->c.x1, c->c.y1,
20608                                  c->c.x2, c->c.y2);
20609         break;
20610       case CTX_REL_CURVE_TO:
20611         ctx_rasterizer_rel_curve_to (rasterizer, c->c.x0, c->c.y0,
20612                                      c->c.x1, c->c.y1,
20613                                      c->c.x2, c->c.y2);
20614         break;
20615       case CTX_QUAD_TO:
20616         ctx_rasterizer_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
20617         break;
20618       case CTX_REL_QUAD_TO:
20619         ctx_rasterizer_rel_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
20620         break;
20621       case CTX_ARC:
20622         ctx_rasterizer_arc (rasterizer, c->arc.x, c->arc.y, c->arc.radius, c->arc.angle1, c->arc.angle2, c->arc.direction);
20623         break;
20624       case CTX_RECTANGLE:
20625         ctx_rasterizer_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
20626                                   c->rectangle.width, c->rectangle.height);
20627         break;
20628       case CTX_ROUND_RECTANGLE:
20629         ctx_rasterizer_round_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
20630                                         c->rectangle.width, c->rectangle.height,
20631                                         c->rectangle.radius);
20632         break;
20633       case CTX_SET_PIXEL:
20634         ctx_rasterizer_set_pixel (rasterizer, c->set_pixel.x, c->set_pixel.y,
20635                                   c->set_pixel.rgba[0],
20636                                   c->set_pixel.rgba[1],
20637                                   c->set_pixel.rgba[2],
20638                                   c->set_pixel.rgba[3]);
20639         break;
20640       case CTX_DEFINE_TEXTURE:
20641         {
20642           uint8_t *pixel_data = ctx_define_texture_pixel_data (entry);
20643           ctx_rasterizer_define_texture (rasterizer, c->define_texture.eid,
20644                                          c->define_texture.width, c->define_texture.height,
20645                                          c->define_texture.format,
20646                                          pixel_data);
20647           rasterizer->comp_op = NULL;
20648           rasterizer->fragment = NULL;
20649         }
20650         break;
20651       case CTX_TEXTURE:
20652         ctx_rasterizer_set_texture (rasterizer, c->texture.eid,
20653                                     c->texture.x, c->texture.y);
20654         rasterizer->comp_op = NULL;
20655         rasterizer->fragment = NULL;
20656         break;
20657       case CTX_SOURCE_TRANSFORM:
20658         ctx_matrix_set (&state->gstate.source_fill.set_transform,
20659                         ctx_arg_float (0), ctx_arg_float (1),
20660                         ctx_arg_float (2), ctx_arg_float (3),
20661                         ctx_arg_float (4), ctx_arg_float (5));
20662         rasterizer->comp_op = NULL;
20663         break;
20664 #if 0
20665       case CTX_LOAD_IMAGE:
20666         ctx_rasterizer_load_image (rasterizer, ctx_arg_string(),
20667                                    ctx_arg_float (0), ctx_arg_float (1) );
20668         break;
20669 #endif
20670 #if CTX_GRADIENTS
20671       case CTX_GRADIENT_STOP:
20672         {
20673           float rgba[4]= {ctx_u8_to_float (ctx_arg_u8 (4) ),
20674                           ctx_u8_to_float (ctx_arg_u8 (4+1) ),
20675                           ctx_u8_to_float (ctx_arg_u8 (4+2) ),
20676                           ctx_u8_to_float (ctx_arg_u8 (4+3) )
20677                          };
20678           ctx_rasterizer_gradient_add_stop (rasterizer,
20679                                             ctx_arg_float (0), rgba);
20680           rasterizer->comp_op = NULL;
20681         }
20682         break;
20683       case CTX_LINEAR_GRADIENT:
20684         ctx_state_gradient_clear_stops (state);
20685         rasterizer->comp_op = NULL;
20686         break;
20687       case CTX_RADIAL_GRADIENT:
20688         ctx_state_gradient_clear_stops (state);
20689         rasterizer->comp_op = NULL;
20690         break;
20691 #endif
20692       case CTX_PRESERVE:
20693         rasterizer->preserve = 1;
20694         break;
20695       case CTX_COLOR:
20696       case CTX_COMPOSITING_MODE:
20697       case CTX_BLEND_MODE:
20698         rasterizer->comp_op = NULL;
20699         //_ctx_setup_compositor (rasterizer);
20700         break;
20701 #if CTX_COMPOSITING_GROUPS
20702       case CTX_START_GROUP:
20703         ctx_rasterizer_start_group (rasterizer);
20704         break;
20705       case CTX_END_GROUP:
20706         ctx_rasterizer_end_group (rasterizer);
20707         break;
20708 #endif
20709 
20710       case CTX_RESTORE:
20711         for (int i = state->gstate_no?state->gstate_stack[state->gstate_no-1].keydb_pos:0;
20712              i < state->gstate.keydb_pos; i++)
20713         {
20714           if (state->keydb[i].key == CTX_clip)
20715           {
20716             clear_clip = 1;
20717           }
20718         }
20719         /* FALLTHROUGH */
20720       case CTX_ROTATE:
20721       case CTX_SCALE:
20722       case CTX_TRANSLATE:
20723       case CTX_IDENTITY:
20724       case CTX_SAVE:
20725         rasterizer->comp_op = NULL;
20726         rasterizer->uses_transforms = 1;
20727         ctx_interpret_transforms (state, entry, NULL);
20728         if (clear_clip)
20729         {
20730           ctx_rasterizer_clip_reset (rasterizer);
20731         for (int i = state->gstate_no?state->gstate_stack[state->gstate_no-1].keydb_pos:0;
20732              i < state->gstate.keydb_pos; i++)
20733         {
20734           if (state->keydb[i].key == CTX_clip)
20735           {
20736             int idx = ctx_float_to_string_index (state->keydb[i].value);
20737             if (idx >=0)
20738             {
20739               CtxSegment *edges = (CtxSegment*)&state->stringpool[idx];
20740               ctx_rasterizer_clip_apply (rasterizer, edges);
20741             }
20742           }
20743         }
20744         }
20745         break;
20746       case CTX_STROKE:
20747 #if CTX_ENABLE_SHADOW_BLUR
20748         if (state->gstate.shadow_blur > 0.0 &&
20749             !rasterizer->in_text)
20750           ctx_rasterizer_shadow_stroke (rasterizer);
20751 #endif
20752         {
20753         int count = rasterizer->edge_list.count;
20754         if (state->gstate.n_dashes)
20755         {
20756           int n_dashes = state->gstate.n_dashes;
20757           float *dashes = state->gstate.dashes;
20758           float factor = ctx_matrix_get_scale (&state->gstate.transform);
20759 
20760           int aa = 15;//rasterizer->aa;
20761           CtxSegment temp[count]; /* copy of already built up path's poly line  */
20762           memcpy (temp, rasterizer->edge_list.entries, sizeof (temp));
20763           int start = 0;
20764           int end   = 0;
20765       CtxMatrix transform_backup = state->gstate.transform;
20766       _ctx_matrix_identity (&state->gstate.transform);
20767       ctx_rasterizer_reset (rasterizer); /* for dashing we create
20768                                             a dashed path to stroke */
20769       float prev_x = 0.0f;
20770       float prev_y = 0.0f;
20771       float pos = 0.0;
20772 
20773       int   dash_no  = 0.0;
20774       float dash_lpos = state->gstate.line_dash_offset * factor;
20775       int   is_down = 0;
20776 
20777           while (start < count)
20778           {
20779             int started = 0;
20780             int i;
20781             is_down = 0;
20782 
20783             if (!is_down)
20784             {
20785               CtxSegment *entry = &temp[0];
20786               prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
20787               prev_y = entry->data.s16[1] * 1.0f / aa;
20788               ctx_rasterizer_move_to (rasterizer, prev_x, prev_y);
20789               is_down = 1;
20790             }
20791 
20792 
20793             for (i = start; i < count; i++)
20794             {
20795               CtxSegment *entry = &temp[i];
20796               float x, y;
20797               if (entry->code == CTX_NEW_EDGE)
20798                 {
20799                   if (started)
20800                     {
20801                       end = i - 1;
20802                       dash_no = 0;
20803                       dash_lpos = 0.0;
20804                       goto foo;
20805                     }
20806                   prev_x = entry->data.s16[0] * 1.0f / CTX_SUBDIV;
20807                   prev_y = entry->data.s16[1] * 1.0f / aa;
20808                   started = 1;
20809                   start = i;
20810                   is_down = 1;
20811                   ctx_rasterizer_move_to (rasterizer, prev_x, prev_y);
20812                 }
20813 
20814 again:
20815 
20816               x = entry->data.s16[2] * 1.0f / CTX_SUBDIV;
20817               y = entry->data.s16[3] * 1.0f / aa;
20818               float dx = x - prev_x;
20819               float dy = y - prev_y;
20820               float length = ctx_fast_hypotf (dx, dy);
20821 
20822               if (dash_lpos + length >= dashes[dash_no] * factor)
20823               {
20824                 float p = (dashes[dash_no] * factor - dash_lpos) / length;
20825                 float splitx = x * p + (1.0f - p) * prev_x;
20826                 float splity = y * p + (1.0f - p) * prev_y;
20827                 if (is_down)
20828                 {
20829                   ctx_rasterizer_line_to (rasterizer, splitx, splity);
20830                   is_down = 0;
20831                 }
20832                 else
20833                 {
20834                   ctx_rasterizer_move_to (rasterizer, splitx, splity);
20835                   is_down = 1;
20836                 }
20837                 prev_x = splitx;
20838                 prev_y = splity;
20839                 dash_no++;
20840                 dash_lpos=0;
20841                 if (dash_no >= n_dashes) dash_no = 0;
20842                 goto again;
20843               }
20844               else
20845               {
20846                 pos += length;
20847                 dash_lpos += length;
20848                 {
20849                   if (is_down)
20850                     ctx_rasterizer_line_to (rasterizer, x, y);
20851                 }
20852               }
20853               prev_x = x;
20854               prev_y = y;
20855             }
20856           end = i-1;
20857 foo:
20858           start = end+1;
20859         }
20860         state->gstate.transform = transform_backup;
20861         }
20862         ctx_rasterizer_stroke (rasterizer);
20863         }
20864 
20865         break;
20866       case CTX_FONT:
20867         ctx_rasterizer_set_font (rasterizer, ctx_arg_string() );
20868         break;
20869       case CTX_TEXT:
20870         rasterizer->in_text++;
20871 #if CTX_ENABLE_SHADOW_BLUR
20872         if (state->gstate.shadow_blur > 0.0)
20873           ctx_rasterizer_shadow_text (rasterizer, ctx_arg_string ());
20874 #endif
20875         ctx_rasterizer_text (rasterizer, ctx_arg_string(), 0);
20876         rasterizer->in_text--;
20877         ctx_rasterizer_reset (rasterizer);
20878         break;
20879       case CTX_STROKE_TEXT:
20880         ctx_rasterizer_text (rasterizer, ctx_arg_string(), 1);
20881         ctx_rasterizer_reset (rasterizer);
20882         break;
20883       case CTX_GLYPH:
20884         ctx_rasterizer_glyph (rasterizer, entry[0].data.u32[0], entry[0].data.u8[4]);
20885         break;
20886       case CTX_FILL:
20887 #if CTX_ENABLE_SHADOW_BLUR
20888         if (state->gstate.shadow_blur > 0.0 &&
20889             !rasterizer->in_text)
20890           ctx_rasterizer_shadow_fill (rasterizer);
20891 #endif
20892         ctx_rasterizer_fill (rasterizer);
20893         break;
20894       case CTX_RESET:
20895       case CTX_BEGIN_PATH:
20896         ctx_rasterizer_reset (rasterizer);
20897         break;
20898       case CTX_CLIP:
20899         ctx_rasterizer_clip (rasterizer);
20900         break;
20901       case CTX_CLOSE_PATH:
20902         ctx_rasterizer_finish_shape (rasterizer);
20903         break;
20904       case CTX_IMAGE_SMOOTHING:
20905         rasterizer->comp_op = NULL;
20906         break;
20907     }
20908   ctx_interpret_pos_bare (state, entry, NULL);
20909 }
20910 
20911 void
ctx_rasterizer_deinit(CtxRasterizer * rasterizer)20912 ctx_rasterizer_deinit (CtxRasterizer *rasterizer)
20913 {
20914   ctx_drawlist_deinit (&rasterizer->edge_list);
20915 #if CTX_ENABLE_CLIP
20916   if (rasterizer->clip_buffer)
20917   {
20918     ctx_buffer_free (rasterizer->clip_buffer);
20919     rasterizer->clip_buffer = NULL;
20920   }
20921 #endif
20922 #if CTX_SHAPE_CACHE
20923   for (int i = 0; i < CTX_SHAPE_CACHE_ENTRIES; i ++)
20924     if (rasterizer->shape_cache.entries[i])
20925     {
20926       free (rasterizer->shape_cache.entries[i]);
20927       rasterizer->shape_cache.entries[i] = NULL;
20928     }
20929 
20930 #endif
20931   free (rasterizer);
20932 }
20933 
20934 
ctx_get_antialias(Ctx * ctx)20935 CtxAntialias ctx_get_antialias (Ctx *ctx)
20936 {
20937 #if CTX_EVENTS
20938   if (ctx_renderer_is_tiled (ctx))
20939   {
20940      CtxTiled *fb = (CtxTiled*)(ctx->renderer);
20941      return fb->antialias;
20942   }
20943 #endif
20944   if (!_ctx_is_rasterizer (ctx)) return CTX_ANTIALIAS_DEFAULT;
20945 
20946   switch (((CtxRasterizer*)(ctx->renderer))->aa)
20947   {
20948     case 1: return CTX_ANTIALIAS_NONE;
20949     case 3: return CTX_ANTIALIAS_FAST;
20950     //case 5: return CTX_ANTIALIAS_GOOD;
20951     default:
20952     case 15: return CTX_ANTIALIAS_DEFAULT;
20953   }
20954 }
20955 
_ctx_antialias_to_aa(CtxAntialias antialias)20956 static int _ctx_antialias_to_aa (CtxAntialias antialias)
20957 {
20958   switch (antialias)
20959   {
20960     case CTX_ANTIALIAS_NONE: return 1;
20961     case CTX_ANTIALIAS_FAST: return 3;
20962     case CTX_ANTIALIAS_GOOD: return 5;
20963     default:
20964     case CTX_ANTIALIAS_DEFAULT: return CTX_RASTERIZER_AA;
20965   }
20966 }
20967 
20968 void
ctx_set_antialias(Ctx * ctx,CtxAntialias antialias)20969 ctx_set_antialias (Ctx *ctx, CtxAntialias antialias)
20970 {
20971 #if CTX_EVENTS
20972   if (ctx_renderer_is_tiled (ctx))
20973   {
20974      CtxTiled *fb = (CtxTiled*)(ctx->renderer);
20975      fb->antialias = antialias;
20976      for (int i = 0; i < _ctx_max_threads; i++)
20977      {
20978        ctx_set_antialias (fb->host[i], antialias);
20979      }
20980      return;
20981   }
20982 #endif
20983   if (!_ctx_is_rasterizer (ctx)) return;
20984 
20985   ((CtxRasterizer*)(ctx->renderer))->aa =
20986      _ctx_antialias_to_aa (antialias);
20987   ((CtxRasterizer*)(ctx->renderer))->fast_aa = 0;
20988   if (antialias == CTX_ANTIALIAS_DEFAULT||
20989       antialias == CTX_ANTIALIAS_FAST)
20990     ((CtxRasterizer*)(ctx->renderer))->fast_aa = 1;
20991 }
20992 
20993 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)20994 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)
20995 {
20996 #if CTX_ENABLE_CLIP
20997   if (rasterizer->clip_buffer)
20998     ctx_buffer_free (rasterizer->clip_buffer);
20999 #endif
21000   if (rasterizer->edge_list.size)
21001     ctx_drawlist_deinit (&rasterizer->edge_list);
21002 
21003   memset (rasterizer, 0, sizeof (CtxRasterizer) );
21004   rasterizer->vfuncs.process = ctx_rasterizer_process;
21005   rasterizer->vfuncs.free    = (CtxDestroyNotify)ctx_rasterizer_deinit;
21006   rasterizer->edge_list.flags |= CTX_DRAWLIST_EDGE_LIST;
21007   rasterizer->state       = state;
21008   rasterizer->ctx         = ctx;
21009   rasterizer->texture_source = texture_source?texture_source:ctx;
21010 
21011   rasterizer->aa          = _ctx_antialias_to_aa (antialias);
21012   rasterizer->fast_aa = (antialias == CTX_ANTIALIAS_DEFAULT||antialias == CTX_ANTIALIAS_FAST);
21013   ctx_state_init (rasterizer->state);
21014   rasterizer->buf         = data;
21015   rasterizer->blit_x      = x;
21016   rasterizer->blit_y      = y;
21017   rasterizer->blit_width  = width;
21018   rasterizer->blit_height = height;
21019   rasterizer->state->gstate.clip_min_x  = x;
21020   rasterizer->state->gstate.clip_min_y  = y;
21021   rasterizer->state->gstate.clip_max_x  = x + width - 1;
21022   rasterizer->state->gstate.clip_max_y  = y + height - 1;
21023   rasterizer->blit_stride = stride;
21024   rasterizer->scan_min    = 5000;
21025   rasterizer->scan_max    = -5000;
21026 
21027   if (pixel_format == CTX_FORMAT_BGRA8)
21028   {
21029     pixel_format = CTX_FORMAT_RGBA8;
21030     rasterizer->swap_red_green = 1;
21031   }
21032 
21033   rasterizer->format = ctx_pixel_format_info (pixel_format);
21034 
21035   return rasterizer;
21036 }
21037 
21038 Ctx *
ctx_new_for_buffer(CtxBuffer * buffer)21039 ctx_new_for_buffer (CtxBuffer *buffer)
21040 {
21041   Ctx *ctx = ctx_new ();
21042   ctx_set_renderer (ctx,
21043                     ctx_rasterizer_init ( (CtxRasterizer *) malloc (sizeof (CtxRasterizer) ),
21044                                           ctx, NULL, &ctx->state,
21045                                           buffer->data, 0, 0, buffer->width, buffer->height,
21046                                           buffer->stride, buffer->format->pixel_format,
21047                                           CTX_ANTIALIAS_DEFAULT));
21048   return ctx;
21049 }
21050 
21051 Ctx *
ctx_new_for_framebuffer(void * data,int width,int height,int stride,CtxPixelFormat pixel_format)21052 ctx_new_for_framebuffer (void *data, int width, int height,
21053                          int stride,
21054                          CtxPixelFormat pixel_format)
21055 {
21056   Ctx *ctx = ctx_new ();
21057   CtxRasterizer *r = ctx_rasterizer_init ( (CtxRasterizer *) ctx_calloc (sizeof (CtxRasterizer), 1),
21058                                           ctx, NULL, &ctx->state, data, 0, 0, width, height,
21059                                           stride, pixel_format, CTX_ANTIALIAS_DEFAULT);
21060   ctx_set_renderer (ctx, r);
21061   return ctx;
21062 }
21063 
21064 // ctx_new_for_stream (FILE *stream);
21065 
21066 #if 0
21067 CtxRasterizer *ctx_rasterizer_new (void *data, int x, int y, int width, int height,
21068                                    int stride, CtxPixelFormat pixel_format)
21069 {
21070   CtxState    *state    = (CtxState *) malloc (sizeof (CtxState) );
21071   CtxRasterizer *rasterizer = (CtxRasterizer *) malloc (sizeof (CtxRenderer) );
21072   ctx_rasterizer_init (rasterizer, state, data, x, y, width, height,
21073                        stride, pixel_format, CTX_ANTIALIAS_DEFAULT);
21074 }
21075 #endif
21076 
21077 CtxPixelFormatInfo *
21078 ctx_pixel_format_info (CtxPixelFormat format);
21079 
21080 #else
21081 
21082 CtxPixelFormatInfo *
ctx_pixel_format_info(CtxPixelFormat format)21083 ctx_pixel_format_info (CtxPixelFormat format)
21084 {
21085   return NULL;
21086 }
21087 #endif
21088 
21089 void
ctx_current_point(Ctx * ctx,float * x,float * y)21090 ctx_current_point (Ctx *ctx, float *x, float *y)
21091 {
21092   if (!ctx)
21093     {
21094       if (x) { *x = 0.0f; }
21095       if (y) { *y = 0.0f; }
21096     }
21097 #if CTX_RASTERIZER
21098   if (ctx->renderer)
21099     {
21100       if (x) { *x = ( (CtxRasterizer *) (ctx->renderer) )->x; }
21101       if (y) { *y = ( (CtxRasterizer *) (ctx->renderer) )->y; }
21102       return;
21103     }
21104 #endif
21105   if (x) { *x = ctx->state.x; }
21106   if (y) { *y = ctx->state.y; }
21107 }
21108 
ctx_x(Ctx * ctx)21109 float ctx_x (Ctx *ctx)
21110 {
21111   float x = 0, y = 0;
21112   ctx_current_point (ctx, &x, &y);
21113   return x;
21114 }
21115 
ctx_y(Ctx * ctx)21116 float ctx_y (Ctx *ctx)
21117 {
21118   float x = 0, y = 0;
21119   ctx_current_point (ctx, &x, &y);
21120   return y;
21121 }
21122 
21123 static void
ctx_process(Ctx * ctx,CtxEntry * entry)21124 ctx_process (Ctx *ctx, CtxEntry *entry)
21125 {
21126 #if CTX_CURRENT_PATH
21127   switch (entry->code)
21128     {
21129       case CTX_TEXT:
21130       case CTX_STROKE_TEXT:
21131       case CTX_BEGIN_PATH:
21132         ctx->current_path.count = 0;
21133         break;
21134       case CTX_CLIP:
21135       case CTX_FILL:
21136       case CTX_STROKE:
21137               // XXX unless preserve
21138         ctx->current_path.count = 0;
21139         break;
21140       case CTX_CLOSE_PATH:
21141       case CTX_LINE_TO:
21142       case CTX_MOVE_TO:
21143       case CTX_QUAD_TO:
21144       case CTX_SMOOTH_TO:
21145       case CTX_SMOOTHQ_TO:
21146       case CTX_REL_QUAD_TO:
21147       case CTX_REL_SMOOTH_TO:
21148       case CTX_REL_SMOOTHQ_TO:
21149       case CTX_CURVE_TO:
21150       case CTX_REL_CURVE_TO:
21151       case CTX_ARC:
21152       case CTX_ARC_TO:
21153       case CTX_REL_ARC_TO:
21154       case CTX_RECTANGLE:
21155       case CTX_ROUND_RECTANGLE:
21156         ctx_drawlist_add_entry (&ctx->current_path, entry);
21157         break;
21158       default:
21159         break;
21160     }
21161 #endif
21162 #if CTX_RASTERIZER
21163   if (CTX_LIKELY(ctx->renderer && ctx->renderer->process == ctx_rasterizer_process))
21164     {
21165       ctx_rasterizer_process (ctx->renderer, (CtxCommand *) entry);
21166     }
21167   else
21168 #endif
21169   if (CTX_LIKELY(ctx->renderer && ctx->renderer->process))
21170     {
21171       ctx->renderer->process (ctx->renderer, (CtxCommand *) entry);
21172     }
21173   else
21174     {
21175       /* these functions might alter the code and coordinates of
21176          command that in the end gets added to the drawlist
21177        */
21178       ctx_interpret_style (&ctx->state, entry, ctx);
21179       ctx_interpret_transforms (&ctx->state, entry, ctx);
21180       ctx_interpret_pos (&ctx->state, entry, ctx);
21181       ctx_drawlist_add_entry (&ctx->drawlist, entry);
21182     }
21183 }
21184 
21185 
21186 int ctx_gradient_cache_valid = 0;
21187 
21188 void
ctx_state_gradient_clear_stops(CtxState * state)21189 ctx_state_gradient_clear_stops (CtxState *state)
21190 {
21191 //#if CTX_GRADIENT_CACHE
21192 //  ctx_gradient_cache_reset ();
21193 //#endif
21194   ctx_gradient_cache_valid = 0;
21195   state->gradient.n_stops = 0;
21196 }
21197 
21198 
21199 /****  end of engine ****/
21200 
ctx_buffer_new_bare(void)21201 CtxBuffer *ctx_buffer_new_bare (void)
21202 {
21203   CtxBuffer *buffer = (CtxBuffer *) ctx_calloc (sizeof (CtxBuffer), 1);
21204   return buffer;
21205 }
21206 
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)21207 void ctx_buffer_set_data (CtxBuffer *buffer,
21208                           void *data, int width, int height,
21209                           int stride,
21210                           CtxPixelFormat pixel_format,
21211                           void (*freefunc) (void *pixels, void *user_data),
21212                           void *user_data)
21213 {
21214   if (buffer->free_func)
21215     { buffer->free_func (buffer->data, buffer->user_data); }
21216   if (stride <= 0)
21217     stride = ctx_pixel_format_get_stride (pixel_format, width);
21218   buffer->data      = data;
21219   buffer->width     = width;
21220   buffer->height    = height;
21221   buffer->stride    = stride;
21222   buffer->format    = ctx_pixel_format_info (pixel_format);
21223   buffer->free_func = freefunc;
21224   buffer->user_data = user_data;
21225 }
21226 
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)21227 CtxBuffer *ctx_buffer_new_for_data (void *data, int width, int height,
21228                                     int stride,
21229                                     CtxPixelFormat pixel_format,
21230                                     void (*freefunc) (void *pixels, void *user_data),
21231                                     void *user_data)
21232 {
21233   CtxBuffer *buffer = ctx_buffer_new_bare ();
21234   ctx_buffer_set_data (buffer, data, width, height, stride, pixel_format,
21235                        freefunc, user_data);
21236   return buffer;
21237 }
21238 
ctx_buffer_pixels_free(void * pixels,void * userdata)21239 void ctx_buffer_pixels_free (void *pixels, void *userdata)
21240 {
21241   free (pixels);
21242 }
21243 
ctx_buffer_new(int width,int height,CtxPixelFormat pixel_format)21244 CtxBuffer *ctx_buffer_new (int width, int height,
21245                            CtxPixelFormat pixel_format)
21246 {
21247   //CtxPixelFormatInfo *info = ctx_pixel_format_info (pixel_format);
21248   CtxBuffer *buffer = ctx_buffer_new_bare ();
21249   int stride = ctx_pixel_format_get_stride (pixel_format, width);
21250   int data_len = stride * height;
21251   if (pixel_format == CTX_FORMAT_YUV420)
21252     data_len = width * height + ((width/2) * (height/2)) * 2;
21253 
21254   uint8_t *pixels = (uint8_t*)ctx_calloc (data_len, 1);
21255 
21256   ctx_buffer_set_data (buffer, pixels, width, height, stride, pixel_format,
21257                        ctx_buffer_pixels_free, NULL);
21258   return buffer;
21259 }
21260 
ctx_buffer_deinit(CtxBuffer * buffer)21261 static void ctx_buffer_deinit (CtxBuffer *buffer)
21262 {
21263   if (buffer->free_func)
21264     buffer->free_func (buffer->data, buffer->user_data);
21265   if (buffer->eid)
21266   {
21267     free (buffer->eid);
21268   }
21269   buffer->eid = NULL;
21270   buffer->data = NULL;
21271   buffer->free_func = NULL;
21272   buffer->user_data  = NULL;
21273   if (buffer->color_managed)
21274   {
21275     if (buffer->color_managed != buffer)
21276     {
21277       ctx_buffer_free (buffer->color_managed);
21278     }
21279     buffer->color_managed = NULL;
21280   }
21281 }
21282 
ctx_buffer_free(CtxBuffer * buffer)21283 void ctx_buffer_free (CtxBuffer *buffer)
21284 {
21285   ctx_buffer_deinit (buffer);
21286   free (buffer);
21287 }
21288 
21289 #if 0
21290 static int
21291 ctx_texture_check_eid (Ctx *ctx, const char *eid, int *tw, int *th)
21292 {
21293   for (int i = 0; i <  CTX_MAX_TEXTURES; i++)
21294   {
21295     if (ctx->texture[i].data &&
21296         ctx->texture[i].eid  &&
21297         !strcmp (ctx->texture[i].eid, eid))
21298     {
21299       if (tw) *tw = ctx->texture[i].width;
21300       if (th) *th = ctx->texture[i].height;
21301       ctx->texture[i].frame = ctx->texture_cache->frame;
21302       return i;
21303     }
21304   }
21305   return -1;
21306 }
21307 #endif
21308 
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)21309 const char* ctx_texture_init (Ctx           *ctx,
21310                               const char    *eid,
21311                               int            width,
21312                               int            height,
21313                               int            stride,
21314                               CtxPixelFormat format,
21315                               void          *space,
21316                               uint8_t       *pixels,
21317                               void (*freefunc) (void *pixels, void *user_data),
21318                               void *user_data)
21319 {
21320   int id = 0;
21321   if (eid)
21322   {
21323     for (int i = 0; i <  CTX_MAX_TEXTURES; i++)
21324     {
21325       if (ctx->texture[i].data &&
21326           ctx->texture[i].eid &&
21327           !strcmp (ctx->texture[i].eid, eid))
21328       {
21329         ctx->texture[i].frame = ctx->texture_cache->frame;
21330         if (freefunc && user_data != (void*)23)
21331           freefunc (pixels, user_data);
21332         return ctx->texture[i].eid;
21333       }
21334       if (ctx->texture[i].data == NULL
21335           ||   (ctx->texture_cache->frame - ctx->texture[i].frame >= 2))
21336         id = i;
21337     }
21338   } else
21339   {
21340     for (int i = 0; i <  CTX_MAX_TEXTURES; i++)
21341     {
21342       if (ctx->texture[i].data == NULL
21343           || (ctx->texture_cache->frame - ctx->texture[i].frame > 2))
21344         id = i;
21345     }
21346   }
21347   //int bpp = ctx_pixel_format_bits_per_pixel (format);
21348   ctx_buffer_deinit (&ctx->texture[id]);
21349 
21350   if (stride<=0)
21351   {
21352     stride = ctx_pixel_format_get_stride ((CtxPixelFormat)format, width);
21353   }
21354 
21355   int data_len = stride * height;
21356   if (format == CTX_FORMAT_YUV420)
21357           data_len = width * height +
21358                   2 * ((width/2)*(height/2));
21359 
21360   if (freefunc == ctx_buffer_pixels_free && user_data == (void*)23)
21361   {
21362      uint8_t *tmp = (uint8_t*)malloc (data_len);
21363      memcpy (tmp, pixels, data_len);
21364      pixels = tmp;
21365   }
21366 
21367   ctx_buffer_set_data (&ctx->texture[id],
21368                        pixels, width, height,
21369                        stride, format,
21370                        freefunc, user_data);
21371 #if CTX_ENABLE_CM
21372   ctx->texture[id].space = space;
21373 #endif
21374   ctx->texture[id].frame = ctx->texture_cache->frame;
21375   if (eid)
21376   {
21377     /* we got an eid, this is the fast path */
21378     ctx->texture[id].eid = strdup (eid);
21379   }
21380   else
21381   {
21382     uint8_t hash[20];
21383     char ascii[41];
21384 
21385     CtxSHA1 *sha1 = ctx_sha1_new ();
21386     ctx_sha1_process (sha1, pixels, stride * height);
21387     ctx_sha1_done (sha1, hash);
21388     ctx_sha1_free (sha1);
21389     const char *hex="0123456789abcdef";
21390     for (int i = 0; i < 20; i ++)
21391     {
21392        ascii[i*2]=hex[hash[i]/16];
21393        ascii[i*2+1]=hex[hash[i]%16];
21394     }
21395     ascii[40]=0;
21396     ctx->texture[id].eid = strdup (ascii);
21397   }
21398   return ctx->texture[id].eid;
21399 }
21400 
21401 static void
_ctx_texture_prepare_color_management(CtxRasterizer * rasterizer,CtxBuffer * buffer)21402 _ctx_texture_prepare_color_management (CtxRasterizer *rasterizer,
21403                                       CtxBuffer     *buffer)
21404 {
21405    switch (buffer->format->pixel_format)
21406    {
21407 #ifndef NO_BABL
21408 #if CTX_BABL
21409      case CTX_FORMAT_RGBA8:
21410        if (buffer->space == rasterizer->state->gstate.device_space)
21411        {
21412          buffer->color_managed = buffer;
21413        }
21414        else
21415        {
21416           buffer->color_managed = ctx_buffer_new (buffer->width, buffer->height,
21417                                                   CTX_FORMAT_RGBA8);
21418           babl_process (
21419              babl_fish (babl_format_with_space ("R'G'B'A u8", buffer->space),
21420                         babl_format_with_space ("R'G'B'A u8", rasterizer->state->gstate.device_space)),
21421              buffer->data, buffer->color_managed->data,
21422              buffer->width * buffer->height
21423              );
21424        }
21425        break;
21426      case CTX_FORMAT_RGB8:
21427        if (buffer->space == rasterizer->state->gstate.device_space)
21428        {
21429          buffer->color_managed = buffer;
21430        }
21431        else
21432        {
21433          buffer->color_managed = ctx_buffer_new (buffer->width, buffer->height,
21434                                                CTX_FORMAT_RGB8);
21435          babl_process (
21436             babl_fish (babl_format_with_space ("R'G'B' u8", buffer->space),
21437                        babl_format_with_space ("R'G'B' u8", rasterizer->state->gstate.device_space)),
21438             buffer->data, buffer->color_managed->data,
21439             buffer->width * buffer->height
21440           );
21441        }
21442        break;
21443 #endif
21444 #endif
21445      default:
21446        buffer->color_managed = buffer;
21447    }
21448 }
21449 
21450 
21451 
ctx_utf8_len(const unsigned char first_byte)21452 int ctx_utf8_len (const unsigned char first_byte)
21453 {
21454   if      ( (first_byte & 0x80) == 0)
21455     { return 1; } /* ASCII */
21456   else if ( (first_byte & 0xE0) == 0xC0)
21457     { return 2; }
21458   else if ( (first_byte & 0xF0) == 0xE0)
21459     { return 3; }
21460   else if ( (first_byte & 0xF8) == 0xF0)
21461     { return 4; }
21462   return 1;
21463 }
21464 
21465 
ctx_utf8_skip(const char * s,int utf8_length)21466 const char *ctx_utf8_skip (const char *s, int utf8_length)
21467 {
21468   int count;
21469   if (!s)
21470     { return NULL; }
21471   for (count = 0; *s; s++)
21472     {
21473       if ( (*s & 0xC0) != 0x80)
21474         { count++; }
21475       if (count == utf8_length + 1)
21476         { return s; }
21477     }
21478   return s;
21479 }
21480 
21481 //  XXX  :  unused
ctx_utf8_strlen(const char * s)21482 int ctx_utf8_strlen (const char *s)
21483 {
21484   int count;
21485   if (!s)
21486     { return 0; }
21487   for (count = 0; *s; s++)
21488     if ( (*s & 0xC0) != 0x80)
21489       { count++; }
21490   return count;
21491 }
21492 
21493 int
ctx_unichar_to_utf8(uint32_t ch,uint8_t * dest)21494 ctx_unichar_to_utf8 (uint32_t  ch,
21495                      uint8_t  *dest)
21496 {
21497   /* http://www.cprogramming.com/tutorial/utf8.c  */
21498   /*  Basic UTF-8 manipulation routines
21499     by Jeff Bezanson
21500     placed in the public domain Fall 2005 ... */
21501   if (ch < 0x80)
21502     {
21503       dest[0] = (char) ch;
21504       return 1;
21505     }
21506   if (ch < 0x800)
21507     {
21508       dest[0] = (ch>>6) | 0xC0;
21509       dest[1] = (ch & 0x3F) | 0x80;
21510       return 2;
21511     }
21512   if (ch < 0x10000)
21513     {
21514       dest[0] = (ch>>12) | 0xE0;
21515       dest[1] = ( (ch>>6) & 0x3F) | 0x80;
21516       dest[2] = (ch & 0x3F) | 0x80;
21517       return 3;
21518     }
21519   if (ch < 0x110000)
21520     {
21521       dest[0] = (ch>>18) | 0xF0;
21522       dest[1] = ( (ch>>12) & 0x3F) | 0x80;
21523       dest[2] = ( (ch>>6) & 0x3F) | 0x80;
21524       dest[3] = (ch & 0x3F) | 0x80;
21525       return 4;
21526     }
21527   return 0;
21528 }
21529 
21530 uint32_t
ctx_utf8_to_unichar(const char * input)21531 ctx_utf8_to_unichar (const char *input)
21532 {
21533   const uint8_t *utf8 = (const uint8_t *) input;
21534   uint8_t c = utf8[0];
21535   if ( (c & 0x80) == 0)
21536     { return c; }
21537   else if ( (c & 0xE0) == 0xC0)
21538     return ( (utf8[0] & 0x1F) << 6) |
21539            (utf8[1] & 0x3F);
21540   else if ( (c & 0xF0) == 0xE0)
21541     return ( (utf8[0] & 0xF)  << 12) |
21542            ( (utf8[1] & 0x3F) << 6) |
21543            (utf8[2] & 0x3F);
21544   else if ( (c & 0xF8) == 0xF0)
21545     return ( (utf8[0] & 0x7)  << 18) |
21546            ( (utf8[1] & 0x3F) << 12) |
21547            ( (utf8[2] & 0x3F) << 6) |
21548            (utf8[3] & 0x3F);
21549   else if ( (c & 0xFC) == 0xF8)
21550     return ( (utf8[0] & 0x3)  << 24) |
21551            ( (utf8[1] & 0x3F) << 18) |
21552            ( (utf8[2] & 0x3F) << 12) |
21553            ( (utf8[3] & 0x3F) << 6) |
21554            (utf8[4] & 0x3F);
21555   else if ( (c & 0xFE) == 0xFC)
21556     return ( (utf8[0] & 0x1)  << 30) |
21557            ( (utf8[1] & 0x3F) << 24) |
21558            ( (utf8[2] & 0x3F) << 18) |
21559            ( (utf8[3] & 0x3F) << 12) |
21560            ( (utf8[4] & 0x3F) << 6) |
21561            (utf8[5] & 0x3F);
21562   return 0;
21563 }
21564 
21565 #if CTX_RASTERIZER
21566 
21567 
21568 static int
ctx_rect_intersect(const CtxIntRectangle * a,const CtxIntRectangle * b)21569 ctx_rect_intersect (const CtxIntRectangle *a, const CtxIntRectangle *b)
21570 {
21571   if (a->x >= b->x + b->width ||
21572       b->x >= a->x + a->width ||
21573       a->y >= b->y + b->height ||
21574       b->y >= a->y + a->height) return 0;
21575 
21576   return 1;
21577 }
21578 
21579 static void
_ctx_add_hash(CtxHasher * hasher,CtxIntRectangle * shape_rect,char * hash)21580 _ctx_add_hash (CtxHasher *hasher, CtxIntRectangle *shape_rect, char *hash)
21581 {
21582   CtxIntRectangle rect = {0,0, hasher->rasterizer.blit_width/hasher->cols,
21583                             hasher->rasterizer.blit_height/hasher->rows};
21584   int hno = 0;
21585   for (int row = 0; row < hasher->rows; row++)
21586     for (int col = 0; col < hasher->cols; col++, hno++)
21587      {
21588       rect.x = col * rect.width;
21589       rect.y = row * rect.height;
21590       if (ctx_rect_intersect (shape_rect, &rect))
21591       {
21592         int temp = hasher->hashes[(row * hasher->cols + col)  *20 + 0];
21593         for (int i = 0; i <19;i++)
21594            hasher->hashes[(row * hasher->cols + col)  *20 + i] =
21595              hasher->hashes[(row * hasher->cols + col)  *20 + i+1]^
21596              hash[i];
21597         hasher->hashes[(row * hasher->cols + col)  *20 + 19] =
21598                 temp ^ hash[19];
21599       }
21600     }
21601 }
21602 
21603 static int
ctx_str_count_lines(const char * str)21604 ctx_str_count_lines (const char *str)
21605 {
21606   int count = 0;
21607   for (const char *p = str; *p; p++)
21608     if (*p == '\n') count ++;
21609   return count;
21610 }
21611 
21612 static void
ctx_hasher_process(void * user_data,CtxCommand * command)21613 ctx_hasher_process (void *user_data, CtxCommand *command)
21614 {
21615   CtxEntry *entry = &command->entry;
21616   CtxRasterizer *rasterizer = (CtxRasterizer *) user_data;
21617   CtxHasher *hasher = (CtxHasher*) user_data;
21618   CtxState *state = rasterizer->state;
21619   CtxCommand *c = (CtxCommand *) entry;
21620   int aa = 15;//rasterizer->aa;
21621 
21622   ctx_interpret_pos_bare (rasterizer->state, entry, NULL);
21623   ctx_interpret_style (rasterizer->state, entry, NULL);
21624 
21625   switch (c->code)
21626     {
21627       case CTX_TEXT:
21628         {
21629           CtxSHA1 sha1;
21630           memcpy (&sha1, &hasher->sha1_fill, sizeof (CtxSHA1));
21631           char ctx_sha1_hash[20];
21632           float width = ctx_text_width (rasterizer->ctx, ctx_arg_string());
21633 
21634 
21635           float height = ctx_get_font_size (rasterizer->ctx);
21636            CtxIntRectangle shape_rect;
21637 
21638            shape_rect.x=rasterizer->x;
21639            shape_rect.y=rasterizer->y - height,
21640            shape_rect.width = width;
21641            shape_rect.height = height * (ctx_str_count_lines (ctx_arg_string()) + 1.5);
21642           switch ((int)ctx_state_get (rasterizer->state, CTX_text_align))
21643           {
21644           case CTX_TEXT_ALIGN_LEFT:
21645           case CTX_TEXT_ALIGN_START:
21646                   break;
21647           case CTX_TEXT_ALIGN_END:
21648           case CTX_TEXT_ALIGN_RIGHT:
21649            shape_rect.x -= shape_rect.width;
21650            break;
21651           case CTX_TEXT_ALIGN_CENTER:
21652            shape_rect.x -= shape_rect.width/2;
21653            break;
21654                    // XXX : doesn't take all text-alignments into account
21655           }
21656 
21657 #if 0
21658           uint32_t color;
21659           ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, (uint8_t*)(&color));
21660 #endif
21661           ctx_sha1_process(&sha1, (const unsigned char*)ctx_arg_string(), strlen  (ctx_arg_string()));
21662 #if 1
21663         ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
21664     //      ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
21665 #endif
21666           ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxIntRectangle));
21667           ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
21668           _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
21669 
21670           ctx_rasterizer_rel_move_to (rasterizer, width, 0);
21671         }
21672         ctx_rasterizer_reset (rasterizer);
21673         break;
21674       case CTX_STROKE_TEXT:
21675         {
21676           CtxSHA1 sha1;
21677           memcpy (&sha1, &hasher->sha1_stroke, sizeof (CtxSHA1));
21678           char ctx_sha1_hash[20];
21679           float width = ctx_text_width (rasterizer->ctx, ctx_arg_string());
21680           float height = ctx_get_font_size (rasterizer->ctx);
21681 
21682            CtxIntRectangle shape_rect = {
21683               (int)rasterizer->x, (int)(rasterizer->y - height),
21684               (int)width, (int)(height * 2)
21685            };
21686 
21687 #if 0
21688           uint32_t color;
21689           ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_stroke.color, (uint8_t*)(&color));
21690 #endif
21691           ctx_sha1_process(&sha1, (unsigned char*)ctx_arg_string(), strlen  (ctx_arg_string()));
21692 #if 1
21693           ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
21694     //    ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
21695 #endif
21696           ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxIntRectangle));
21697           ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
21698           _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
21699 
21700           ctx_rasterizer_rel_move_to (rasterizer, width, 0);
21701         }
21702         ctx_rasterizer_reset (rasterizer);
21703         break;
21704       case CTX_GLYPH:
21705          {
21706           CtxSHA1 sha1;
21707           memcpy (&sha1, &hasher->sha1_fill, sizeof (CtxSHA1));
21708 
21709           char ctx_sha1_hash[20];
21710           uint8_t string[8];
21711           string[ctx_unichar_to_utf8 (c->u32.a0, string)]=0;
21712           float width = ctx_text_width (rasterizer->ctx, (char*)string);
21713           float height = ctx_get_font_size (rasterizer->ctx);
21714 
21715           float tx = rasterizer->x;
21716           float ty = rasterizer->y;
21717           float tw = width;
21718           float th = height * 2;
21719 
21720           _ctx_user_to_device (rasterizer->state, &tx, &ty);
21721           _ctx_user_to_device_distance (rasterizer->state, &tw, &th);
21722           CtxIntRectangle shape_rect = {(int)tx,(int)(ty-th/2),(int)tw,(int)th};
21723 
21724 
21725 #if 0
21726           uint32_t color;
21727           ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, (uint8_t*)(&color));
21728 #endif
21729           ctx_sha1_process(&sha1, string, strlen ((const char*)string));
21730           ctx_sha1_process(&sha1, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
21731 #if 0
21732           ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
21733 #endif
21734           ctx_sha1_process(&sha1, (unsigned char*)&shape_rect, sizeof (CtxIntRectangle));
21735           ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
21736           _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
21737 
21738           ctx_rasterizer_rel_move_to (rasterizer, width, 0);
21739           ctx_rasterizer_reset (rasterizer);
21740          }
21741         break;
21742 
21743       case CTX_FILL:
21744         {
21745           CtxSHA1 sha1;
21746           memcpy (&sha1, &hasher->sha1_fill, sizeof (CtxSHA1));
21747           char ctx_sha1_hash[20];
21748 
21749           /* we eant this hasher to be as good as possible internally,
21750            * since it is also used in the small shapes rasterization
21751            * cache
21752            */
21753         uint64_t hash = ctx_rasterizer_poly_to_hash (rasterizer); // + hasher->salt;
21754         CtxIntRectangle shape_rect = {
21755           (int)(rasterizer->col_min / CTX_SUBDIV - 2),
21756           (int)(rasterizer->scan_min / aa - 2),
21757           (int)(3+(rasterizer->col_max - rasterizer->col_min + 1) / CTX_SUBDIV),
21758           (int)(3+(rasterizer->scan_max - rasterizer->scan_min + 1) / aa)
21759         };
21760 
21761         hash ^= (rasterizer->state->gstate.fill_rule * 23);
21762 
21763         ctx_sha1_process(&sha1, (unsigned char*)&hash, 8);
21764 
21765         {
21766           int is = rasterizer->state->gstate.image_smoothing;
21767           ctx_sha1_process(&sha1, (uint8_t*)&is, sizeof(int));
21768         }
21769 
21770           ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
21771           _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
21772 
21773         if (!rasterizer->preserve)
21774           ctx_rasterizer_reset (rasterizer);
21775         rasterizer->preserve = 0;
21776         }
21777         break;
21778       case CTX_STROKE:
21779         {
21780           CtxSHA1 sha1;
21781           memcpy (&sha1, &hasher->sha1_stroke, sizeof (CtxSHA1));
21782           char ctx_sha1_hash[20];
21783         uint64_t hash = ctx_rasterizer_poly_to_hash (rasterizer);
21784         CtxIntRectangle shape_rect = {
21785           (int)(rasterizer->col_min / CTX_SUBDIV - rasterizer->state->gstate.line_width),
21786           (int)(rasterizer->scan_min / aa - rasterizer->state->gstate.line_width),
21787           (int)((rasterizer->col_max - rasterizer->col_min + 1) / CTX_SUBDIV + rasterizer->state->gstate.line_width),
21788           (int)((rasterizer->scan_max - rasterizer->scan_min + 1) / aa + rasterizer->state->gstate.line_width)
21789         };
21790 
21791         shape_rect.width += rasterizer->state->gstate.line_width * 2;
21792         shape_rect.height += rasterizer->state->gstate.line_width * 2;
21793         shape_rect.x -= rasterizer->state->gstate.line_width;
21794         shape_rect.y -= rasterizer->state->gstate.line_width;
21795 
21796         hash ^= (int)(rasterizer->state->gstate.line_width * 110);
21797         hash ^= (rasterizer->state->gstate.line_cap * 23);
21798         hash ^= (rasterizer->state->gstate.source_stroke.type * 117);
21799 
21800         ctx_sha1_process(&sha1, (unsigned char*)&hash, 8);
21801 
21802         uint32_t color;
21803         ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_stroke.color, (uint8_t*)(&color));
21804 
21805           ctx_sha1_process(&sha1, (unsigned char*)&color, 4);
21806 
21807           ctx_sha1_done(&sha1, (unsigned char*)ctx_sha1_hash);
21808           _ctx_add_hash (hasher, &shape_rect, ctx_sha1_hash);
21809         }
21810         if (!rasterizer->preserve)
21811           ctx_rasterizer_reset (rasterizer);
21812         rasterizer->preserve = 0;
21813         break;
21814         /* the above cases are the painting cases and
21815          * the only ones differing from the rasterizer's process switch
21816          */
21817 
21818       case CTX_LINE_TO:
21819         ctx_rasterizer_line_to (rasterizer, c->c.x0, c->c.y0);
21820         break;
21821       case CTX_REL_LINE_TO:
21822         ctx_rasterizer_rel_line_to (rasterizer, c->c.x0, c->c.y0);
21823         break;
21824       case CTX_MOVE_TO:
21825         ctx_rasterizer_move_to (rasterizer, c->c.x0, c->c.y0);
21826         break;
21827       case CTX_REL_MOVE_TO:
21828         ctx_rasterizer_rel_move_to (rasterizer, c->c.x0, c->c.y0);
21829         break;
21830       case CTX_CURVE_TO:
21831         ctx_rasterizer_curve_to (rasterizer, c->c.x0, c->c.y0,
21832                                  c->c.x1, c->c.y1,
21833                                  c->c.x2, c->c.y2);
21834         break;
21835       case CTX_REL_CURVE_TO:
21836         ctx_rasterizer_rel_curve_to (rasterizer, c->c.x0, c->c.y0,
21837                                      c->c.x1, c->c.y1,
21838                                      c->c.x2, c->c.y2);
21839         break;
21840       case CTX_QUAD_TO:
21841         ctx_rasterizer_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
21842         break;
21843       case CTX_REL_QUAD_TO:
21844         ctx_rasterizer_rel_quad_to (rasterizer, c->c.x0, c->c.y0, c->c.x1, c->c.y1);
21845         break;
21846       case CTX_ARC:
21847         ctx_rasterizer_arc (rasterizer, c->arc.x, c->arc.y, c->arc.radius, c->arc.angle1, c->arc.angle2, c->arc.direction);
21848         break;
21849       case CTX_RECTANGLE:
21850         ctx_rasterizer_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
21851                                   c->rectangle.width, c->rectangle.height);
21852         break;
21853       case CTX_ROUND_RECTANGLE:
21854         ctx_rasterizer_round_rectangle (rasterizer, c->rectangle.x, c->rectangle.y,
21855                                         c->rectangle.width, c->rectangle.height,
21856                                         c->rectangle.radius);
21857         break;
21858       case CTX_SET_PIXEL:
21859         ctx_rasterizer_set_pixel (rasterizer, c->set_pixel.x, c->set_pixel.y,
21860                                   c->set_pixel.rgba[0],
21861                                   c->set_pixel.rgba[1],
21862                                   c->set_pixel.rgba[2],
21863                                   c->set_pixel.rgba[3]);
21864         break;
21865       case CTX_PRESERVE:
21866         rasterizer->preserve = 1;
21867         break;
21868       case CTX_ROTATE:
21869       case CTX_SCALE:
21870       case CTX_TRANSLATE:
21871       case CTX_SAVE:
21872       case CTX_RESTORE:
21873         rasterizer->uses_transforms = 1;
21874         ctx_interpret_transforms (rasterizer->state, entry, NULL);
21875 
21876 
21877         break;
21878       case CTX_FONT:
21879         ctx_rasterizer_set_font (rasterizer, ctx_arg_string() );
21880         break;
21881       case CTX_BEGIN_PATH:
21882         ctx_rasterizer_reset (rasterizer);
21883         break;
21884       case CTX_CLIP:
21885         // should perhaps modify a global state to include
21886         // in hash?
21887         ctx_rasterizer_clip (rasterizer);
21888         break;
21889       case CTX_CLOSE_PATH:
21890         ctx_rasterizer_finish_shape (rasterizer);
21891         break;
21892       case CTX_DEFINE_TEXTURE:
21893         {
21894         ctx_sha1_init (&hasher->sha1_fill);
21895         ctx_sha1_process (&hasher->sha1_fill, (uint8_t*)c->define_texture.eid, strlen (c->define_texture.eid));
21896         ctx_sha1_process(&hasher->sha1_fill, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
21897 
21898         rasterizer->comp_op = NULL; // why?
21899         }
21900         break;
21901       case CTX_TEXTURE:
21902         ctx_sha1_init (&hasher->sha1_fill);
21903         ctx_sha1_process (&hasher->sha1_fill, (uint8_t*)c->texture.eid, strlen (c->texture.eid));
21904         ctx_sha1_process (&hasher->sha1_fill, (uint8_t*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
21905         rasterizer->comp_op = NULL; // why?
21906         break;
21907       case CTX_COLOR:
21908         {
21909           uint32_t color;
21910           if (((int)(ctx_arg_float(0))&512))
21911           {
21912             ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_stroke.color, (uint8_t*)(&color));
21913             ctx_sha1_init (&hasher->sha1_stroke);
21914             ctx_sha1_process(&hasher->sha1_stroke, (unsigned char*)&color, 4);
21915           }
21916           else
21917           {
21918             ctx_color_get_rgba8 (rasterizer->state, &rasterizer->state->gstate.source_fill.color, (uint8_t*)(&color));
21919             ctx_sha1_init (&hasher->sha1_fill);
21920             ctx_sha1_process(&hasher->sha1_fill, (unsigned char*)&color, 4);
21921           }
21922         }
21923         break;
21924       case CTX_LINEAR_GRADIENT:
21925           ctx_sha1_init (&hasher->sha1_fill);
21926           ctx_sha1_process(&hasher->sha1_fill,
21927                            (uint8_t*)c, sizeof (c->linear_gradient));
21928           ctx_sha1_process (&hasher->sha1_fill, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
21929         break;
21930       case CTX_RADIAL_GRADIENT:
21931           ctx_sha1_init (&hasher->sha1_fill);
21932           ctx_sha1_process(&hasher->sha1_fill,
21933                            (uint8_t*)c, sizeof (c->radial_gradient));
21934           ctx_sha1_process (&hasher->sha1_fill, (unsigned char*)(&rasterizer->state->gstate.transform), sizeof (rasterizer->state->gstate.transform));
21935         //ctx_state_gradient_clear_stops (rasterizer->state);
21936         break;
21937 #if CTX_GRADIENTS
21938       case CTX_GRADIENT_STOP:
21939         {
21940           float rgba[4]= {ctx_u8_to_float (ctx_arg_u8 (4) ),
21941                           ctx_u8_to_float (ctx_arg_u8 (4+1) ),
21942                           ctx_u8_to_float (ctx_arg_u8 (4+2) ),
21943                           ctx_u8_to_float (ctx_arg_u8 (4+3) )
21944                          };
21945           ctx_sha1_process(&hasher->sha1_fill,
21946                            (uint8_t*) &rgba[0], sizeof(rgba));
21947         }
21948         break;
21949 #endif
21950     }
21951   if (command->code == CTX_LINE_WIDTH)
21952     {
21953       float x = state->gstate.line_width;
21954       /* normalize line width according to scaling factor
21955        */
21956       x = x * ctx_maxf (ctx_maxf (ctx_fabsf (state->gstate.transform.m[0][0]),
21957                                   ctx_fabsf (state->gstate.transform.m[0][1]) ),
21958                         ctx_maxf (ctx_fabsf (state->gstate.transform.m[1][0]),
21959                                   ctx_fabsf (state->gstate.transform.m[1][1]) ) );
21960       state->gstate.line_width = x;
21961     }
21962 }
21963 
21964 static CtxRasterizer *
ctx_hasher_init(CtxRasterizer * rasterizer,Ctx * ctx,CtxState * state,int width,int height,int cols,int rows)21965 ctx_hasher_init (CtxRasterizer *rasterizer, Ctx *ctx, CtxState *state, int width, int height, int cols, int rows)
21966 {
21967   CtxHasher *hasher = (CtxHasher*)rasterizer;
21968   ctx_memset (rasterizer, 0, sizeof (CtxHasher) );
21969   rasterizer->vfuncs.process = ctx_hasher_process;
21970   rasterizer->vfuncs.free    = (CtxDestroyNotify)ctx_rasterizer_deinit;
21971   // XXX need own destructor to not leak ->hashes
21972   rasterizer->edge_list.flags |= CTX_DRAWLIST_EDGE_LIST;
21973   rasterizer->state       = state;
21974   rasterizer->ctx         = ctx;
21975   ctx_state_init (rasterizer->state);
21976   rasterizer->blit_x      = 0;
21977   rasterizer->blit_y      = 0;
21978   rasterizer->blit_width  = width;
21979   rasterizer->blit_height = height;
21980   rasterizer->state->gstate.clip_min_x  = 0;
21981   rasterizer->state->gstate.clip_min_y  = 0;
21982   rasterizer->state->gstate.clip_max_x  = width - 1;
21983   rasterizer->state->gstate.clip_max_y  = height - 1;
21984   rasterizer->scan_min    = 5000;
21985   rasterizer->scan_max    = -5000;
21986   //rasterizer->aa          = 15;
21987 
21988   hasher->rows = rows;
21989   hasher->cols = cols;
21990 
21991   hasher->hashes = (uint8_t*)ctx_calloc (20, rows * cols);
21992   ctx_sha1_init (&hasher->sha1_fill);
21993   ctx_sha1_init (&hasher->sha1_stroke);
21994 
21995   return rasterizer;
21996 }
21997 
ctx_hasher_new(int width,int height,int cols,int rows)21998 Ctx *ctx_hasher_new (int width, int height, int cols, int rows)
21999 {
22000   Ctx *ctx           = ctx_new ();
22001   CtxState    *state = &ctx->state;
22002   CtxRasterizer *rasterizer = (CtxRasterizer *) ctx_calloc (sizeof (CtxHasher), 1);
22003   ctx_hasher_init (rasterizer, ctx, state, width, height, cols, rows);
22004   ctx_set_renderer (ctx, (void*)rasterizer);
22005   return ctx;
22006 }
22007 
ctx_hasher_get_hash(Ctx * ctx,int col,int row)22008 uint8_t *ctx_hasher_get_hash (Ctx *ctx, int col, int row)
22009 {
22010   CtxHasher *hasher = (CtxHasher*)ctx->renderer;
22011   if (row < 0) row =0;
22012   if (col < 0) col =0;
22013   if (row >= hasher->rows) row = hasher->rows-1;
22014   if (col >= hasher->cols) col = hasher->cols-1;
22015 
22016   return &hasher->hashes[(row*hasher->cols+col)*20];
22017 }
22018 
22019 #endif
22020 #if CTX_EVENTS
22021 
22022 #if !__COSMOPOLITAN__
22023 #include <termios.h>
22024 
22025 #include <fcntl.h>
22026 #include <sys/ioctl.h>
22027 #endif
22028 
22029 #if 0
22030 int ctx_terminal_width (void)
22031 {
22032   char buf[1024];
22033   struct termios orig_attr;
22034   struct termios raw;
22035   tcgetattr (STDIN_FILENO, &orig_attr);
22036   raw = orig_attr;
22037   raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
22038   raw.c_oflag &= ~(OPOST);
22039   raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
22040   raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
22041   if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
22042     return 0;
22043   fprintf (stderr, "\e[14t");
22044   //tcflush(STDIN_FILENO, 1);
22045 #if __COSMOPOLITAN__
22046   /// XXX ?
22047 #else
22048   tcdrain(STDIN_FILENO);
22049 #endif
22050   int length = 0;
22051   usleep (1000 * 60); // to account for possibly lowish latency ssh,
22052                       // should be made configurable ; perhaps in
22053                       // an env var
22054   struct timeval tv = {0,0};
22055   fd_set rfds;
22056 
22057   FD_ZERO(&rfds);
22058   FD_SET(0, &rfds);
22059   tv.tv_usec = 1000 * 5;
22060 
22061   for (int n = 0; select(1, &rfds, NULL, NULL, &tv) && n < 20; n++)
22062   {
22063     length += read (STDIN_FILENO, &buf[length], 1);
22064   }
22065   tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
22066   if (length == -1)
22067   {
22068     return 0;
22069   }
22070   char *semi = strchr (buf, ';');
22071   buf[length]=0;
22072   if (semi) {semi++; semi = strchr (semi, ';');}
22073   if (semi)
22074   {
22075     return atoi(semi + 1);
22076   }
22077   return 0;
22078 }
22079 
22080 int ctx_terminal_height (void)
22081 {
22082   char buf[1024];
22083   struct termios orig_attr;
22084   struct termios raw;
22085   tcgetattr (STDIN_FILENO, &orig_attr);
22086   raw = orig_attr;
22087   raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
22088   raw.c_oflag &= ~(OPOST);
22089   raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
22090   raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
22091   if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
22092     return 0;
22093   fprintf (stderr, "\e[14t");
22094   //tcflush(STDIN_FILENO, 1);
22095 #if !__COSMOPOLITAN__
22096   tcdrain(STDIN_FILENO);
22097 #endif
22098   int length = 0;
22099   usleep (1000 * 60); // to account for possibly lowish latency ssh,
22100                       // should be made configurable ; perhaps in
22101                       // an env var
22102   struct timeval tv = {0,0};
22103   fd_set rfds;
22104 
22105   FD_ZERO(&rfds);
22106   FD_SET(0, &rfds);
22107   tv.tv_usec = 1000 * 5;
22108 
22109   for (int n = 0; select(1, &rfds, NULL, NULL, &tv) && n < 20; n++)
22110   {
22111     length += read (STDIN_FILENO, &buf[length], 1);
22112   }
22113   tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
22114   if (length == -1)
22115   {
22116     return 0;
22117   }
22118   char *semi = strchr (buf, ';');
22119   buf[length]=0;
22120   if (semi)
22121   {
22122     return atoi(semi + 1);
22123   }
22124   return 0;
22125 }
22126 #else
22127 
22128 
ctx_terminal_width(void)22129 int ctx_terminal_width (void)
22130 {
22131   struct winsize ws;
22132   if (ioctl(0,TIOCGWINSZ,&ws)!=0)
22133     return 640;
22134   return ws.ws_xpixel;
22135 }
22136 
ctx_terminal_height(void)22137 int ctx_terminal_height (void)
22138 {
22139   struct winsize ws;
22140   if (ioctl(0,TIOCGWINSZ,&ws)!=0)
22141     return 450;
22142   return ws.ws_ypixel;
22143 }
22144 
22145 #endif
22146 
ctx_terminal_cols(void)22147 int ctx_terminal_cols (void)
22148 {
22149   struct winsize ws;
22150   if (ioctl(0,TIOCGWINSZ,&ws)!=0)
22151     return 80;
22152   return ws.ws_col;
22153 }
22154 
ctx_terminal_rows(void)22155 int ctx_terminal_rows (void)
22156 {
22157   struct winsize ws;
22158   if (ioctl(0,TIOCGWINSZ,&ws)!=0)
22159     return 25;
22160   return ws.ws_row;
22161 }
22162 
22163 
22164 
22165 
22166 
22167 #define DECTCEM_CURSOR_SHOW      "\033[?25h"
22168 #define DECTCEM_CURSOR_HIDE      "\033[?25l"
22169 #define TERMINAL_MOUSE_OFF       "\033[?1000l\033[?1003l"
22170 #define TERMINAL_MOUSE_ON_BASIC  "\033[?1000h"
22171 #define TERMINAL_MOUSE_ON_DRAG   "\033[?1000h\033[?1003h" /* +ON_BASIC for wider */
22172 #define TERMINAL_MOUSE_ON_FULL   "\033[?1000h\033[?1004h" /* compatibility */
22173 #define XTERM_ALTSCREEN_ON       "\033[?47h"
22174 #define XTERM_ALTSCREEN_OFF      "\033[?47l"
22175 
22176 /*************************** input handling *************************/
22177 
22178 #if !__COSMOPOLITAN__
22179 #include <termios.h>
22180 #include <errno.h>
22181 #include <signal.h>
22182 #endif
22183 
22184 #define DELAY_MS  100
22185 
22186 #ifndef MIN
22187 #define MIN(a,b) (((a)<(b))?(a):(b))
22188 #endif
22189 
22190 static int  size_changed = 0;       /* XXX: global state */
22191 static int  ctx_term_signal_installed = 0;   /* XXX: global state */
22192 
22193 static const char *mouse_modes[]=
22194 {TERMINAL_MOUSE_OFF,
22195  TERMINAL_MOUSE_ON_BASIC,
22196  TERMINAL_MOUSE_ON_DRAG,
22197  TERMINAL_MOUSE_ON_FULL,
22198  NULL};
22199 
22200 /* note that a nick can have multiple occurences, the labels
22201  * should be kept the same for all occurences of a combination. */
22202 typedef struct NcKeyCode {
22203   const char *nick;          /* programmers name for key (combo) */
22204   const char *label;         /* utf8 label for key */
22205   const char  sequence[10];  /* terminal sequence */
22206 } NcKeyCode;
22207 static const NcKeyCode keycodes[]={
22208 
22209   {"up",                  "↑",     "\033[A"},
22210   {"down",                "↓",     "\033[B"},
22211   {"right",               "→",     "\033[C"},
22212   {"left",                "←",     "\033[D"},
22213 
22214   {"shift-up",            "⇧↑",    "\033[1;2A"},
22215   {"shift-down",          "⇧↓",    "\033[1;2B"},
22216   {"shift-right",         "⇧→",    "\033[1;2C"},
22217   {"shift-left",          "⇧←",    "\033[1;2D"},
22218 
22219   {"alt-up",              "^↑",    "\033[1;3A"},
22220   {"alt-down",            "^↓",    "\033[1;3B"},
22221   {"alt-right",           "^→",    "\033[1;3C"},
22222   {"alt-left",            "^←",    "\033[1;3D"},
22223 
22224   {"alt-shift-up",        "alt-s↑", "\033[1;4A"},
22225   {"alt-shift-down",      "alt-s↓", "\033[1;4B"},
22226   {"alt-shift-right",     "alt-s→", "\033[1;4C"},
22227   {"alt-shift-left",      "alt-s←", "\033[1;4D"},
22228 
22229   {"control-up",          "^↑",    "\033[1;5A"},
22230   {"control-down",        "^↓",    "\033[1;5B"},
22231   {"control-right",       "^→",    "\033[1;5C"},
22232   {"control-left",        "^←",    "\033[1;5D"},
22233 
22234   /* putty */
22235   {"control-up",          "^↑",    "\033OA"},
22236   {"control-down",        "^↓",    "\033OB"},
22237   {"control-right",       "^→",    "\033OC"},
22238   {"control-left",        "^←",    "\033OD"},
22239 
22240   {"control-shift-up",    "^⇧↑",   "\033[1;6A"},
22241   {"control-shift-down",  "^⇧↓",   "\033[1;6B"},
22242   {"control-shift-right", "^⇧→",   "\033[1;6C"},
22243   {"control-shift-left",  "^⇧←",   "\033[1;6D"},
22244 
22245   {"control-up",          "^↑",    "\033Oa"},
22246   {"control-down",        "^↓",    "\033Ob"},
22247   {"control-right",       "^→",    "\033Oc"},
22248   {"control-left",        "^←",    "\033Od"},
22249 
22250   {"shift-up",            "⇧↑",    "\033[a"},
22251   {"shift-down",          "⇧↓",    "\033[b"},
22252   {"shift-right",         "⇧→",    "\033[c"},
22253   {"shift-left",          "⇧←",    "\033[d"},
22254 
22255   {"insert",              "ins",   "\033[2~"},
22256   {"delete",              "del",   "\033[3~"},
22257   {"page-up",             "PgUp",  "\033[5~"},
22258   {"page-down",           "PdDn",  "\033[6~"},
22259   {"home",                "Home",  "\033OH"},
22260   {"end",                 "End",   "\033OF"},
22261   {"home",                "Home",  "\033[H"},
22262   {"end",                 "End",   "\033[F"},
22263   {"control-delete",      "^del",  "\033[3;5~"},
22264   {"shift-delete",        "⇧del",  "\033[3;2~"},
22265   {"control-shift-delete","^⇧del", "\033[3;6~"},
22266 
22267   {"F1",        "F1",  "\033[10~"},
22268   {"F2",        "F2",  "\033[11~"},
22269   {"F3",        "F3",  "\033[12~"},
22270   {"F4",        "F4",  "\033[13~"},
22271   {"F1",        "F1",  "\033OP"},
22272   {"F2",        "F2",  "\033OQ"},
22273   {"F3",        "F3",  "\033OR"},
22274   {"F4",        "F4",  "\033OS"},
22275   {"F5",        "F5",  "\033[15~"},
22276   {"F6",        "F6",  "\033[16~"},
22277   {"F7",        "F7",  "\033[17~"},
22278   {"F8",        "F8",  "\033[18~"},
22279   {"F9",        "F9",  "\033[19~"},
22280   {"F9",        "F9",  "\033[20~"},
22281   {"F10",       "F10", "\033[21~"},
22282   {"F11",       "F11", "\033[22~"},
22283   {"F12",       "F12", "\033[23~"},
22284   {"tab",       "↹",     {9, '\0'}},
22285   {"shift-tab", "shift+↹",  "\033[Z"},
22286   {"backspace", "⌫",  {127, '\0'}},
22287   {"space",     "␣",   " "},
22288   {"esc",        "␛",  "\033"},
22289   {"return",    "⏎",  {10,0}},
22290   {"return",    "⏎",  {13,0}},
22291   /* this section could be autogenerated by code */
22292   {"control-a", "^A",  {1,0}},
22293   {"control-b", "^B",  {2,0}},
22294   {"control-c", "^C",  {3,0}},
22295   {"control-d", "^D",  {4,0}},
22296   {"control-e", "^E",  {5,0}},
22297   {"control-f", "^F",  {6,0}},
22298   {"control-g", "^G",  {7,0}},
22299   {"control-h", "^H",  {8,0}}, /* backspace? */
22300   {"control-i", "^I",  {9,0}}, /* tab */
22301   {"control-j", "^J",  {10,0}},
22302   {"control-k", "^K",  {11,0}},
22303   {"control-l", "^L",  {12,0}},
22304   {"control-n", "^N",  {14,0}},
22305   {"control-o", "^O",  {15,0}},
22306   {"control-p", "^P",  {16,0}},
22307   {"control-q", "^Q",  {17,0}},
22308   {"control-r", "^R",  {18,0}},
22309   {"control-s", "^S",  {19,0}},
22310   {"control-t", "^T",  {20,0}},
22311   {"control-u", "^U",  {21,0}},
22312   {"control-v", "^V",  {22,0}},
22313   {"control-w", "^W",  {23,0}},
22314   {"control-x", "^X",  {24,0}},
22315   {"control-y", "^Y",  {25,0}},
22316   {"control-z", "^Z",  {26,0}},
22317   {"alt-0",     "%0",  "\0330"},
22318   {"alt-1",     "%1",  "\0331"},
22319   {"alt-2",     "%2",  "\0332"},
22320   {"alt-3",     "%3",  "\0333"},
22321   {"alt-4",     "%4",  "\0334"},
22322   {"alt-5",     "%5",  "\0335"},
22323   {"alt-6",     "%6",  "\0336"},
22324   {"alt-7",     "%7",  "\0337"}, /* backspace? */
22325   {"alt-8",     "%8",  "\0338"},
22326   {"alt-9",     "%9",  "\0339"},
22327   {"alt-+",     "%+",  "\033+"},
22328   {"alt--",     "%-",  "\033-"},
22329   {"alt-/",     "%/",  "\033/"},
22330   {"alt-a",     "%A",  "\033a"},
22331   {"alt-b",     "%B",  "\033b"},
22332   {"alt-c",     "%C",  "\033c"},
22333   {"alt-d",     "%D",  "\033d"},
22334   {"alt-e",     "%E",  "\033e"},
22335   {"alt-f",     "%F",  "\033f"},
22336   {"alt-g",     "%G",  "\033g"},
22337   {"alt-h",     "%H",  "\033h"}, /* backspace? */
22338   {"alt-i",     "%I",  "\033i"},
22339   {"alt-j",     "%J",  "\033j"},
22340   {"alt-k",     "%K",  "\033k"},
22341   {"alt-l",     "%L",  "\033l"},
22342   {"alt-n",     "%N",  "\033m"},
22343   {"alt-n",     "%N",  "\033n"},
22344   {"alt-o",     "%O",  "\033o"},
22345   {"alt-p",     "%P",  "\033p"},
22346   {"alt-q",     "%Q",  "\033q"},
22347   {"alt-r",     "%R",  "\033r"},
22348   {"alt-s",     "%S",  "\033s"},
22349   {"alt-t",     "%T",  "\033t"},
22350   {"alt-u",     "%U",  "\033u"},
22351   {"alt-v",     "%V",  "\033v"},
22352   {"alt-w",     "%W",  "\033w"},
22353   {"alt-x",     "%X",  "\033x"},
22354   {"alt-y",     "%Y",  "\033y"},
22355   {"alt-z",     "%Z",  "\033z"},
22356   {"shift-tab", "shift-↹", {27, 9, 0}},
22357   /* Linux Console  */
22358   {"home",      "Home", "\033[1~"},
22359   {"end",       "End",  "\033[4~"},
22360   {"F1",        "F1",   "\033[[A"},
22361   {"F2",        "F2",   "\033[[B"},
22362   {"F3",        "F3",   "\033[[C"},
22363   {"F4",        "F4",   "\033[[D"},
22364   {"F5",        "F5",   "\033[[E"},
22365   {"F6",        "F6",   "\033[[F"},
22366   {"F7",        "F7",   "\033[[G"},
22367   {"F8",        "F8",   "\033[[H"},
22368   {"F9",        "F9",   "\033[[I"},
22369   {"F10",       "F10",  "\033[[J"},
22370   {"F11",       "F11",  "\033[[K"},
22371   {"F12",       "F12",  "\033[[L"},
22372   {"ok",        "",     "\033[0n"},
22373   {NULL, }
22374 };
22375 
22376 static struct termios orig_attr;    /* in order to restore at exit */
22377 static int    nc_is_raw = 0;
22378 static int    atexit_registered = 0;
22379 static int    mouse_mode = NC_MOUSE_NONE;
22380 
_nc_noraw(void)22381 static void _nc_noraw (void)
22382 {
22383   if (nc_is_raw && tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr) != -1)
22384     nc_is_raw = 0;
22385 }
22386 
22387 void
nc_at_exit(void)22388 nc_at_exit (void)
22389 {
22390   printf (TERMINAL_MOUSE_OFF);
22391   printf (XTERM_ALTSCREEN_OFF);
22392   _nc_noraw();
22393   fprintf (stdout, "\e[?25h");
22394   //if (ctx_native_events)
22395   fprintf (stdout, "\e[?201l");
22396   fprintf (stdout, "\e[?1049l");
22397 }
22398 
mouse_get_event_int(Ctx * n,int * x,int * y)22399 static const char *mouse_get_event_int (Ctx *n, int *x, int *y)
22400 {
22401   static int prev_state = 0;
22402   const char *ret = "mouse-motion";
22403   float relx, rely;
22404   signed char buf[3];
22405   read (n->mouse_fd, buf, 3);
22406   relx = buf[1];
22407   rely = -buf[2];
22408 
22409   n->mouse_x += relx * 0.1;
22410   n->mouse_y += rely * 0.1;
22411 
22412   if (n->mouse_x < 1) n->mouse_x = 1;
22413   if (n->mouse_y < 1) n->mouse_y = 1;
22414   if (n->mouse_x >= n->events.width)  n->mouse_x = n->events.width;
22415   if (n->mouse_y >= n->events.height) n->mouse_y = n->events.height;
22416 
22417   if (x) *x = n->mouse_x;
22418   if (y) *y = n->mouse_y;
22419 
22420   if ((prev_state & 1) != (buf[0] & 1))
22421     {
22422       if (buf[0] & 1) ret = "mouse-press";
22423     }
22424   else if (buf[0] & 1)
22425     ret = "mouse-drag";
22426 
22427   if ((prev_state & 2) != (buf[0] & 2))
22428     {
22429       if (buf[0] & 2) ret = "mouse2-press";
22430     }
22431   else if (buf[0] & 2)
22432     ret = "mouse2-drag";
22433 
22434   if ((prev_state & 4) != (buf[0] & 4))
22435     {
22436       if (buf[0] & 4) ret = "mouse1-press";
22437     }
22438   else if (buf[0] & 4)
22439     ret = "mouse1-drag";
22440 
22441   prev_state = buf[0];
22442   return ret;
22443 }
22444 
22445 static const char *mev_type = NULL;
22446 static int         mev_x = 0;
22447 static int         mev_y = 0;
22448 static int         mev_q = 0;
22449 
mouse_get_event(Ctx * n,int * x,int * y)22450 static const char *mouse_get_event (Ctx  *n, int *x, int *y)
22451 {
22452   if (!mev_q)
22453     return NULL;
22454   *x = mev_x;
22455   *y = mev_y;
22456   mev_q = 0;
22457   return mev_type;
22458 }
22459 
mouse_has_event(Ctx * n)22460 static int mouse_has_event (Ctx *n)
22461 {
22462   struct timeval tv;
22463   int retval;
22464 
22465   if (mouse_mode == NC_MOUSE_NONE)
22466     return 0;
22467 
22468   if (mev_q)
22469     return 1;
22470 
22471   if (n->mouse_fd == 0)
22472     return 0;
22473   return 0;
22474 
22475   {
22476     fd_set rfds;
22477     FD_ZERO (&rfds);
22478     FD_SET(n->mouse_fd, &rfds);
22479     tv.tv_sec = 0; tv.tv_usec = 0;
22480     retval = select (n->mouse_fd+1, &rfds, NULL, NULL, &tv);
22481   }
22482 
22483   if (retval != 0)
22484     {
22485       int nx = 0, ny = 0;
22486       const char *type = mouse_get_event_int (n, &nx, &ny);
22487 
22488       if ((mouse_mode < NC_MOUSE_DRAG && mev_type && !strcmp (mev_type, "drag")) ||
22489           (mouse_mode < NC_MOUSE_ALL && mev_type && !strcmp (mev_type, "motion")))
22490         {
22491           mev_q = 0;
22492           return mouse_has_event (n);
22493         }
22494 
22495       if ((mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse-motion")) ||
22496          (mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse1-drag")) ||
22497          (mev_type && !strcmp (type, mev_type) && !strcmp (type, "mouse2-drag")))
22498         {
22499           if (nx == mev_x && ny == mev_y)
22500           {
22501             mev_q = 0;
22502             return mouse_has_event (n);
22503           }
22504         }
22505       mev_x = nx;
22506       mev_y = ny;
22507       mev_type = type;
22508       mev_q = 1;
22509     }
22510   return retval != 0;
22511 }
22512 
22513 
_nc_raw(void)22514 static int _nc_raw (void)
22515 {
22516   struct termios raw;
22517   if (!isatty (STDIN_FILENO))
22518     return -1;
22519   if (!atexit_registered)
22520     {
22521       atexit (nc_at_exit);
22522       atexit_registered = 1;
22523     }
22524   if (tcgetattr (STDIN_FILENO, &orig_attr) == -1)
22525     return -1;
22526   raw = orig_attr;  /* modify the original mode */
22527   raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
22528   raw.c_oflag &= ~(OPOST);
22529   raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
22530   raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
22531   if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
22532     return -1;
22533   nc_is_raw = 1;
22534 #if !__COSMOPOLITAN__
22535   tcdrain(STDIN_FILENO);
22536   tcflush(STDIN_FILENO, 1);
22537 #endif
22538   return 0;
22539 }
22540 
match_keycode(const char * buf,int length,const NcKeyCode ** ret)22541 static int match_keycode (const char *buf, int length, const NcKeyCode **ret)
22542 {
22543   int i;
22544   int matches = 0;
22545 
22546   if (!strncmp (buf, "\033[M", MIN(length,3)))
22547     {
22548       if (length >= 6)
22549         return 9001;
22550       return 2342;
22551     }
22552   for (i = 0; keycodes[i].nick; i++)
22553     if (!strncmp (buf, keycodes[i].sequence, length))
22554       {
22555         matches ++;
22556         if ((int)strlen (keycodes[i].sequence) == length && ret)
22557           {
22558             *ret = &keycodes[i];
22559             return 1;
22560           }
22561       }
22562   if (matches != 1 && ret)
22563     *ret = NULL;
22564   return matches==1?2:matches;
22565 }
22566 
nc_resize_term(int dummy)22567 static void nc_resize_term (int  dummy)
22568 {
22569   size_changed = 1;
22570 }
22571 
ctx_nct_has_event(Ctx * n,int delay_ms)22572 int ctx_nct_has_event (Ctx  *n, int delay_ms)
22573 {
22574   struct timeval tv;
22575   int retval;
22576   fd_set rfds;
22577 
22578   if (size_changed)
22579     return 1;
22580   FD_ZERO (&rfds);
22581   FD_SET (STDIN_FILENO, &rfds);
22582   tv.tv_sec = 0; tv.tv_usec = delay_ms * 1000;
22583   retval = select (1, &rfds, NULL, NULL, &tv);
22584   if (size_changed)
22585     return 1;
22586   return retval == 1 && retval != -1;
22587 }
22588 
ctx_nct_get_event(Ctx * n,int timeoutms,int * x,int * y)22589 const char *ctx_nct_get_event (Ctx *n, int timeoutms, int *x, int *y)
22590 {
22591   unsigned char buf[20];
22592   int length;
22593 
22594 
22595   if (x) *x = -1;
22596   if (y) *y = -1;
22597 
22598   if (!ctx_term_signal_installed)
22599     {
22600       _nc_raw ();
22601       ctx_term_signal_installed = 1;
22602       signal (SIGWINCH, nc_resize_term);
22603     }
22604   if (mouse_mode) // XXX too often to do it all the time!
22605     printf("%s", mouse_modes[mouse_mode]);
22606 
22607   {
22608     int elapsed = 0;
22609     int got_event = 0;
22610 
22611     do {
22612       if (size_changed)
22613         {
22614           size_changed = 0;
22615           return "size-changed";
22616         }
22617       got_event = mouse_has_event (n);
22618       if (!got_event)
22619         got_event = ctx_nct_has_event (n, MIN(DELAY_MS, timeoutms-elapsed));
22620       if (size_changed)
22621         {
22622           size_changed = 0;
22623           return "size-changed";
22624         }
22625       /* only do this if the client has asked for idle events,
22626        * and perhaps programmed the ms timer?
22627        */
22628       elapsed += MIN(DELAY_MS, timeoutms-elapsed);
22629       if (!got_event && timeoutms && elapsed >= timeoutms)
22630         return "idle";
22631     } while (!got_event);
22632   }
22633 
22634   if (mouse_has_event (n))
22635     return mouse_get_event (n, x, y);
22636 
22637   for (length = 0; length < 10; length ++)
22638     if (read (STDIN_FILENO, &buf[length], 1) != -1)
22639       {
22640         const NcKeyCode *match = NULL;
22641 
22642         /* special case ESC, so that we can use it alone in keybindings */
22643         if (length == 0 && buf[0] == 27)
22644           {
22645             struct timeval tv;
22646             fd_set rfds;
22647             FD_ZERO (&rfds);
22648             FD_SET (STDIN_FILENO, &rfds);
22649             tv.tv_sec = 0;
22650             tv.tv_usec = 1000 * DELAY_MS;
22651             if (select (1, &rfds, NULL, NULL, &tv) == 0)
22652               return "esc";
22653           }
22654 
22655         switch (match_keycode ((const char*)buf, length + 1, &match))
22656           {
22657             case 1: /* unique match */
22658               if (!match)
22659                 return NULL;
22660               if (!strcmp(match->nick, "ok"))
22661               {
22662                 ctx_frame_ack = 1;
22663                 return NULL;
22664               }
22665               return match->nick;
22666               break;
22667             case 9001: /* mouse event */
22668               if (x) *x = ((unsigned char)buf[4]-32)*1.0;
22669               if (y) *y = ((unsigned char)buf[5]-32)*1.0;
22670               switch (buf[3])
22671                 {
22672                         /* XXX : todo reduce this to less string constants */
22673                   case 32:  return "mouse-press";
22674                   case 33:  return "mouse1-press";
22675                   case 34:  return "mouse2-press";
22676                   case 40:  return "alt-mouse-press";
22677                   case 41:  return "alt-mouse1-press";
22678                   case 42:  return "alt-mouse2-press";
22679                   case 48:  return "control-mouse-press";
22680                   case 49:  return "control-mouse1-press";
22681                   case 50:  return "control-mouse2-press";
22682                   case 56:  return "alt-control-mouse-press";
22683                   case 57:  return "alt-control-mouse1-press";
22684                   case 58:  return "alt-control-mouse2-press";
22685                   case 64:  return "mouse-drag";
22686                   case 65:  return "mouse1-drag";
22687                   case 66:  return "mouse2-drag";
22688                   case 71:  return "mouse-motion"; /* shift+motion */
22689                   case 72:  return "alt-mouse-drag";
22690                   case 73:  return "alt-mouse1-drag";
22691                   case 74:  return "alt-mouse2-drag";
22692                   case 75:  return "mouse-motion"; /* alt+motion */
22693                   case 80:  return "control-mouse-drag";
22694                   case 81:  return "control-mouse1-drag";
22695                   case 82:  return "control-mouse2-drag";
22696                   case 83:  return "mouse-motion"; /* ctrl+motion */
22697                   case 91:  return "mouse-motion"; /* ctrl+alt+motion */
22698                   case 95:  return "mouse-motion"; /* ctrl+alt+shift+motion */
22699                   case 96:  return "scroll-up";
22700                   case 97:  return "scroll-down";
22701                   case 100: return "shift-scroll-up";
22702                   case 101: return "shift-scroll-down";
22703                   case 104: return "alt-scroll-up";
22704                   case 105: return "alt-scroll-down";
22705                   case 112: return "control-scroll-up";
22706                   case 113: return "control-scroll-down";
22707                   case 116: return "control-shift-scroll-up";
22708                   case 117: return "control-shift-scroll-down";
22709                   case 35: /* (or release) */
22710                   case 51: /* (or ctrl-release) */
22711                   case 43: /* (or alt-release) */
22712                   case 67: return "mouse-motion";
22713                            /* have a separate mouse-drag ? */
22714                   default: {
22715                              static char rbuf[100];
22716                              sprintf (rbuf, "mouse (unhandled state: %i)", buf[3]);
22717                              return rbuf;
22718                            }
22719                 }
22720             case 0: /* no matches, bail*/
22721               {
22722                 static char ret[256];
22723                 if (length == 0 && ctx_utf8_len (buf[0])>1) /* single unicode
22724                                                                char */
22725                   {
22726                     int n_read =
22727                     read (STDIN_FILENO, &buf[length+1], ctx_utf8_len(buf[0])-1);
22728                     if (n_read)
22729                     {
22730                       buf[ctx_utf8_len(buf[0])]=0;
22731                       strcpy (ret, (const char*)buf);
22732                     }
22733                     return ret;
22734                   }
22735                 if (length == 0) /* ascii */
22736                   {
22737                     buf[1]=0;
22738                     strcpy (ret, (const char*)buf);
22739                     return ret;
22740                   }
22741                 sprintf (ret, "unhandled %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c'",
22742                   length>=0? buf[0]: 0, length>=0? buf[0]>31?buf[0]:'?': ' ',
22743                   length>=1? buf[1]: 0, length>=1? buf[1]>31?buf[1]:'?': ' ',
22744                   length>=2? buf[2]: 0, length>=2? buf[2]>31?buf[2]:'?': ' ',
22745                   length>=3? buf[3]: 0, length>=3? buf[3]>31?buf[3]:'?': ' ',
22746                   length>=4? buf[4]: 0, length>=4? buf[4]>31?buf[4]:'?': ' ',
22747                   length>=5? buf[5]: 0, length>=5? buf[5]>31?buf[5]:'?': ' ',
22748                   length>=6? buf[6]: 0, length>=6? buf[6]>31?buf[6]:'?': ' ');
22749                 return ret;
22750               }
22751               return NULL;
22752             default: /* continue */
22753               break;
22754           }
22755       }
22756     else
22757       return "key read eek";
22758   return "fail";
22759 }
22760 
ctx_nct_consume_events(Ctx * ctx)22761 int ctx_nct_consume_events (Ctx *ctx)
22762 {
22763   int ix, iy;
22764   CtxCtx *ctxctx = (CtxCtx*)ctx->renderer;
22765   const char *event = NULL;
22766 
22767   {
22768     float x, y;
22769     event = ctx_nct_get_event (ctx, 50, &ix, &iy);
22770 
22771     x = (ix - 1.0 + 0.5) / ctxctx->cols * ctx->events.width;
22772     y = (iy - 1.0)       / ctxctx->rows * ctx->events.height;
22773 
22774     if (!strcmp (event, "mouse-press"))
22775     {
22776       ctx_pointer_press (ctx, x, y, 0, 0);
22777       ctxctx->was_down = 1;
22778     } else if (!strcmp (event, "mouse-release"))
22779     {
22780       ctx_pointer_release (ctx, x, y, 0, 0);
22781       ctxctx->was_down = 0;
22782     } else if (!strcmp (event, "mouse-motion"))
22783     {
22784       //nct_set_cursor_pos (backend->term, ix, iy);
22785       //nct_flush (backend->term);
22786       if (ctxctx->was_down)
22787       {
22788         ctx_pointer_release (ctx, x, y, 0, 0);
22789         ctxctx->was_down = 0;
22790       }
22791       ctx_pointer_motion (ctx, x, y, 0, 0);
22792     } else if (!strcmp (event, "mouse-drag"))
22793     {
22794       ctx_pointer_motion (ctx, x, y, 0, 0);
22795     } else if (!strcmp (event, "size-changed"))
22796     {
22797 #if 0
22798       int width = nct_sys_terminal_width ();
22799       int height = nct_sys_terminal_height ();
22800       nct_set_size (backend->term, width, height);
22801       width *= CPX;
22802       height *= CPX;
22803       free (mrg->glyphs);
22804       free (mrg->styles);
22805       free (backend->nct_pixels);
22806       backend->nct_pixels = calloc (width * height * 4, 1);
22807       mrg->glyphs = calloc ((width/CPX) * (height/CPX) * 4, 1);
22808       mrg->styles = calloc ((width/CPX) * (height/CPX) * 1, 1);
22809       mrg_set_size (mrg, width, height);
22810       mrg_queue_draw (mrg, NULL);
22811 #endif
22812       //if (ctx_renderer_is_ctx (ctx))
22813 #if 0
22814       {
22815         int width = ctx_terminal_width ();
22816         int height = ctx_terminal_height ();
22817         ctx_set_size (ctx, width, height);
22818       }
22819 #endif
22820 
22821     }
22822     else
22823     {
22824       if (!strcmp (event, "esc"))
22825         ctx_key_press (ctx, 0, "escape", 0);
22826       else if (!strcmp (event, "space"))
22827         ctx_key_press (ctx, 0, "space", 0);
22828       else if (!strcmp (event, "enter"))
22829         ctx_key_press (ctx, 0, "\n", 0);
22830       else if (!strcmp (event, "return"))
22831         ctx_key_press (ctx, 0, "return", 0);
22832       else if (!strcmp (event, "idle"))
22833       {
22834       }
22835       else
22836       ctx_key_press (ctx, 0, event, 0);
22837     }
22838   }
22839 
22840   return 1;
22841 }
22842 
ctx_native_get_event(Ctx * n,int timeoutms)22843 const char *ctx_native_get_event (Ctx *n, int timeoutms)
22844 {
22845   static unsigned char buf[256];
22846   int length;
22847 
22848   if (!ctx_term_signal_installed)
22849     {
22850       _nc_raw ();
22851       ctx_term_signal_installed = 1;
22852       signal (SIGWINCH, nc_resize_term);
22853     }
22854 //if (mouse_mode) // XXX too often to do it all the time!
22855 //  printf("%s", mouse_modes[mouse_mode]);
22856 
22857     int got_event = 0;
22858   {
22859     int elapsed = 0;
22860 
22861     do {
22862       if (size_changed)
22863         {
22864           size_changed = 0;
22865           return "size-changed";
22866         }
22867       got_event = ctx_nct_has_event (n, MIN(DELAY_MS, timeoutms-elapsed));
22868       if (size_changed)
22869         {
22870           size_changed = 0;
22871           return "size-changed";
22872         }
22873       /* only do this if the client has asked for idle events,
22874        * and perhaps programmed the ms timer?
22875        */
22876       elapsed += MIN(DELAY_MS, timeoutms-elapsed);
22877       if (!got_event && timeoutms && elapsed >= timeoutms)
22878       {
22879         return "idle";
22880       }
22881     } while (!got_event);
22882   }
22883 
22884   for (length = 0; got_event && length < 200; length ++)
22885   {
22886     if (read (STDIN_FILENO, &buf[length], 1) != -1)
22887       {
22888          buf[length+1] = 0;
22889          if (!strcmp ((char*)buf, "\e[0n"))
22890          {
22891            ctx_frame_ack = 1;
22892            return NULL;
22893          }
22894          else if (buf[length]=='\n')
22895          {
22896            buf[length]=0;
22897            return (const char*)buf;
22898          }
22899       }
22900       got_event = ctx_nct_has_event (n, 5);
22901     }
22902   return NULL;
22903 }
22904 
ctx_key_get_label(Ctx * n,const char * nick)22905 const char *ctx_key_get_label (Ctx  *n, const char *nick)
22906 {
22907   int j;
22908   int found = -1;
22909   for (j = 0; keycodes[j].nick; j++)
22910     if (found == -1 && !strcmp (keycodes[j].nick, nick))
22911       return keycodes[j].label;
22912   return NULL;
22913 }
22914 
_ctx_mouse(Ctx * term,int mode)22915 void _ctx_mouse (Ctx *term, int mode)
22916 {
22917   //if (term->is_st && mode > 1)
22918   //  mode = 1;
22919   if (mode != mouse_mode)
22920   {
22921     printf ("%s", mouse_modes[mode]);
22922     fflush (stdout);
22923   }
22924   mouse_mode = mode;
22925 }
22926 
22927 
22928 #endif
22929 
22930 #if !__COSMOPOLITAN__
22931 #include <sys/time.h>
22932 #endif
22933 
22934 
22935 #define usecs(time)    ((uint64_t)(time.tv_sec - start_time.tv_sec) * 1000000 + time.     tv_usec)
22936 
22937 #if !__COSMOPOLITAN__
22938 static struct timeval start_time;
22939 
22940 static void
_ctx_init_ticks(void)22941 _ctx_init_ticks (void)
22942 {
22943   static int done = 0;
22944   if (done)
22945     return;
22946   done = 1;
22947   gettimeofday (&start_time, NULL);
22948 }
22949 
22950 static inline unsigned long
_ctx_ticks(void)22951 _ctx_ticks (void)
22952 {
22953   struct timeval measure_time;
22954   gettimeofday (&measure_time, NULL);
22955   return usecs (measure_time) - usecs (start_time);
22956 }
22957 
22958 unsigned long
ctx_ticks(void)22959 ctx_ticks (void)
22960 {
22961   _ctx_init_ticks ();
22962   return _ctx_ticks ();
22963 }
22964 
22965 
22966 
22967 enum _CtxFlags {
22968    CTX_FLAG_DIRECT = (1<<0),
22969 };
22970 typedef enum _CtxFlags CtxFlags;
22971 
22972 
22973 int _ctx_max_threads = 1;
22974 int _ctx_enable_hash_cache = 1;
22975 #if CTX_SHAPE_CACHE
22976 extern int _ctx_shape_cache_enabled;
22977 #endif
22978 
22979 #if CTX_THREADS
22980 static mtx_t _ctx_texture_mtx;
22981 #endif
22982 
_ctx_texture_lock(void)22983 void _ctx_texture_lock (void)
22984 {
22985 #if CTX_THREADS
22986   mtx_lock (&_ctx_texture_mtx);
22987 #endif
22988 }
22989 
_ctx_texture_unlock(void)22990 void _ctx_texture_unlock (void)
22991 {
22992 #if CTX_THREADS
22993   mtx_unlock (&_ctx_texture_mtx);
22994 #endif
22995 }
22996 
22997 
22998 void
ctx_init(int * argc,char *** argv)22999 ctx_init (int *argc, char ***argv)
23000 {
23001 #if 0
23002   if (!getenv ("CTX_VERSION"))
23003   {
23004     int i;
23005     char *new_argv[*argc+3];
23006     new_argv[0] = "ctx";
23007     for (i = 0; i < *argc; i++)
23008     {
23009       new_argv[i+1] = *argv[i];
23010     }
23011     new_argv[i+1] = NULL;
23012     execvp (new_argv[0], new_argv);
23013     // if this fails .. we continue normal startup
23014     // and end up in self-hosted braille
23015   }
23016 #endif
23017 }
23018 
23019 
23020 #if 0
23021 int ctx_count (Ctx *ctx)
23022 {
23023   return ctx->drawlist.count;
23024 }
23025 #endif
23026 
23027 extern int _ctx_damage_control;
23028 
23029 
23030 #if CTX_EVENTS
23031 
ctx_list_backends(void)23032 void ctx_list_backends(void)
23033 {
23034     fprintf (stderr, "possible values for CTX_BACKEND:\n");
23035     fprintf (stderr, " ctx");
23036 #if CTX_SDL
23037     fprintf (stderr, " SDL");
23038 #endif
23039 #if CTX_KMS
23040     fprintf (stderr, " kms");
23041 #endif
23042 #if CTX_FB
23043     fprintf (stderr, " fb");
23044 #endif
23045     fprintf (stderr, " term");
23046     fprintf (stderr, " termimg");
23047     fprintf (stderr, "\n");
23048 }
23049 
ctx_ms(Ctx * ctx)23050 static uint32_t ctx_ms (Ctx *ctx)
23051 {
23052   return _ctx_ticks () / 1000;
23053 }
23054 
23055 
23056 static int is_in_ctx (void);
ctx_new_ui(int width,int height)23057 Ctx *ctx_new_ui (int width, int height)
23058 {
23059 #if CTX_TILED
23060   if (getenv ("CTX_DAMAGE_CONTROL"))
23061   {
23062     const char * val = getenv ("CTX_DAMAGE_CONTROL");
23063     if (!strcmp (val, "0") ||
23064         !strcmp (val, "off"))
23065       _ctx_damage_control = 0;
23066     else
23067       _ctx_damage_control = 1;
23068   }
23069 #endif
23070 
23071   if (getenv ("CTX_HASH_CACHE"))
23072   {
23073     const char * val = getenv ("CTX_HASH_CACHE");
23074     if (!strcmp (val, "0"))
23075       _ctx_enable_hash_cache = 0;
23076     if (!strcmp (val, "off"))
23077       _ctx_enable_hash_cache = 0;
23078   }
23079 #if CTX_SHAPE_CACHE
23080   if (getenv ("CTX_SHAPE_CACHE"))
23081   {
23082     const char * val = getenv ("CTX_SHAPE_CACHE");
23083     if (!strcmp (val, "0"))
23084       _ctx_shape_cache_enabled = 0;
23085     if (!strcmp (val, "off"))
23086       _ctx_shape_cache_enabled = 0;
23087   }
23088 #endif
23089 
23090   if (getenv ("CTX_THREADS"))
23091   {
23092     int val = atoi (getenv ("CTX_THREADS"));
23093     _ctx_max_threads = val;
23094   }
23095   else
23096   {
23097     _ctx_max_threads = 2;
23098 #ifdef _SC_NPROCESSORS_ONLN
23099     _ctx_max_threads = sysconf (_SC_NPROCESSORS_ONLN) / 2;
23100 #endif
23101   }
23102 
23103 #if CTX_THREADS
23104   mtx_init (&_ctx_texture_mtx, mtx_plain);
23105 #endif
23106 
23107   if (_ctx_max_threads < 1) _ctx_max_threads = 1;
23108   if (_ctx_max_threads > CTX_MAX_THREADS) _ctx_max_threads = CTX_MAX_THREADS;
23109 
23110   //fprintf (stderr, "ctx using %i threads\n", _ctx_max_threads);
23111   const char *backend = getenv ("CTX_BACKEND");
23112 
23113   if (backend && !strcmp (backend, ""))
23114     backend = NULL;
23115   if (backend && !strcmp (backend, "auto"))
23116     backend = NULL;
23117   if (backend && !strcmp (backend, "list"))
23118   {
23119     ctx_list_backends ();
23120     exit (-1);
23121   }
23122 
23123   Ctx *ret = NULL;
23124 
23125   /* we do the query on auto but not on directly set ctx
23126    *
23127    */
23128   if ((backend && !strcmp(backend, "ctx")) ||
23129       (backend == NULL && is_in_ctx ()))
23130   {
23131     if (!backend || !strcmp (backend, "ctx"))
23132     {
23133       // full blown ctx protocol - in terminal or standalone
23134       ret = ctx_new_ctx (width, height);
23135     }
23136   }
23137 
23138 #if CTX_SDL
23139   if (!ret && getenv ("DISPLAY"))
23140   {
23141     if ((backend==NULL) || (!strcmp (backend, "SDL")))
23142       ret = ctx_new_sdl (width, height);
23143   }
23144 #endif
23145 
23146 #if CTX_KMS
23147   if (!ret && !getenv ("DISPLAY"))
23148   {
23149     if ((backend==NULL) || (!strcmp (backend, "kms")))
23150       ret = ctx_new_kms (width, height);
23151   }
23152 #endif
23153 
23154 #if CTX_FB
23155   if (!ret && !getenv ("DISPLAY"))
23156     {
23157       if ((backend==NULL) || (!strcmp (backend, "fb")))
23158         ret = ctx_new_fb (width, height);
23159     }
23160 #endif
23161 
23162 #if CTX_RASTERIZER
23163   // braille in terminal
23164   if (!ret)
23165   {
23166     if ((backend==NULL) || (!strcmp (backend, "term")))
23167     ret = ctx_new_term (width, height);
23168   }
23169   if (!ret)
23170   {
23171     if ((backend==NULL) || (!strcmp (backend, "termimg")))
23172     ret = ctx_new_termimg (width, height);
23173   }
23174 #endif
23175   if (!ret)
23176   {
23177     fprintf (stderr, "no interactive ctx backend\n");
23178     ctx_list_backends ();
23179     exit (2);
23180   }
23181   ctx_get_event (ret); // enables events
23182   return ret;
23183 }
23184 #endif
23185 #else
_ctx_texture_unlock(void)23186 void _ctx_texture_unlock (void)
23187 {
23188 }
_ctx_texture_lock(void)23189 void _ctx_texture_lock (void)
23190 {
23191 }
23192 
23193 #endif
23194 void _ctx_resized (Ctx *ctx, int width, int height, long time);
23195 
ctx_set_size(Ctx * ctx,int width,int height)23196 void ctx_set_size (Ctx *ctx, int width, int height)
23197 {
23198 #if CTX_EVENTS
23199   if (ctx->events.width != width || ctx->events.height != height)
23200   {
23201     ctx->events.width = width;
23202     ctx->events.height = height;
23203     _ctx_resized (ctx, width, height, 0);
23204 #if 1
23205     if (ctx_renderer_is_ctx (ctx))
23206     {
23207       CtxCtx *ctxctx = (CtxCtx*)ctx->renderer;
23208       ctxctx->width = width;
23209       ctxctx->height= height;
23210     }
23211 #endif
23212   }
23213 #endif
23214 }
23215 
23216 #if CTX_EVENTS
23217 
23218 
is_in_ctx(void)23219 static int is_in_ctx (void)
23220 {
23221   char buf[1024];
23222   struct termios orig_attr;
23223   struct termios raw;
23224   tcgetattr (STDIN_FILENO, &orig_attr);
23225   raw = orig_attr;
23226   raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
23227   raw.c_oflag &= ~(OPOST);
23228   raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
23229   raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
23230   if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
23231     return 0;
23232   fprintf (stderr, "\e[?200$p");
23233   //tcflush(STDIN_FILENO, 1);
23234 #if !__COSMOPOLITAN__
23235   tcdrain(STDIN_FILENO);
23236 #endif
23237   int length = 0;
23238   usleep (1000 * 60); // to account for possibly lowish latency ssh,
23239                       // should be made configurable ; perhaps in
23240                       // an env var
23241   struct timeval tv = {0,0};
23242   fd_set rfds;
23243 
23244   FD_ZERO(&rfds);
23245   FD_SET(0, &rfds);
23246   tv.tv_usec = 1000 * 5;
23247 
23248   for (int n = 0; select(1, &rfds, NULL, NULL, &tv) && n < 20; n++)
23249   {
23250     length += read (STDIN_FILENO, &buf[length], 1);
23251   }
23252   tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
23253   if (length == -1)
23254   {
23255     return 0;
23256   }
23257   char *semi = strchr (buf, ';');
23258   buf[length]=0;
23259   if (semi &&  semi[1] == '2')
23260   {
23261     return 1;
23262   }
23263   return 0;
23264 }
23265 
23266 typedef struct CtxIdleCb {
23267   int (*cb) (Ctx *ctx, void *idle_data);
23268   void *idle_data;
23269 
23270   void (*destroy_notify)(void *destroy_data);
23271   void *destroy_data;
23272 
23273   int   ticks_full;
23274   int   ticks_remaining;
23275   int   is_idle;
23276   int   id;
23277 } CtxIdleCb;
23278 
_ctx_events_init(Ctx * ctx)23279 void _ctx_events_init (Ctx *ctx)
23280 {
23281   CtxEvents *events = &ctx->events;
23282   _ctx_init_ticks ();
23283   events->tap_delay_min  = 40;
23284   events->tap_delay_max  = 800;
23285   events->tap_delay_max  = 8000000; /* quick reflexes needed making it hard for some is an argument against very short values  */
23286 
23287   events->tap_delay_hold = 1000;
23288   events->tap_hysteresis = 32;  /* XXX: should be ppi dependent */
23289 }
23290 
23291 
_ctx_idle_iteration(Ctx * ctx)23292 void _ctx_idle_iteration (Ctx *ctx)
23293 {
23294   static unsigned long prev_ticks = 0;
23295   CtxList *l;
23296   unsigned long ticks = ctx_ticks ();
23297   long tick_delta = (prev_ticks == 0) ? 0 : ticks - prev_ticks;
23298   prev_ticks = ticks;
23299 
23300 
23301   if (!ctx->events.idles)
23302   {
23303     return;
23304   }
23305 
23306   ctx->events.in_idle_dispatch=1;
23307 
23308   for (l = ctx->events.idles; l; l = l->next)
23309   {
23310     CtxIdleCb *item = l->data;
23311 
23312     long rem = item->ticks_remaining;
23313     if (item->ticks_remaining >= 0)
23314     {
23315       rem -= tick_delta;
23316 
23317       item->ticks_remaining -= tick_delta / 100;
23318 
23319     if (rem < 0)
23320     {
23321       int to_be_removed = 0;
23322       for (CtxList *l2 = ctx->events.idles_to_remove; l2; l2=l2->next)
23323       {
23324         CtxIdleCb *item2 = l2->data;
23325         if (item2 == item) to_be_removed = 1;
23326       }
23327 
23328       if (!to_be_removed)
23329       {
23330       if (item->cb (ctx, item->idle_data) == 0)
23331       {
23332         ctx_list_prepend (&ctx->events.idles_to_remove, item);
23333       }
23334       else
23335         item->ticks_remaining = item->ticks_full;
23336       }
23337     }
23338     else
23339         item->ticks_remaining = rem;
23340     }
23341     else
23342     {
23343       int to_be_removed = 0;
23344       for (CtxList *l2 = ctx->events.idles_to_remove; l2; l2=l2->next)
23345       {
23346         CtxIdleCb *item2 = l2->data;
23347         if (item2 == item) to_be_removed = 1;
23348       }
23349 
23350       if (!to_be_removed)
23351       {
23352         if (item->cb (ctx, item->idle_data) == 0)
23353         {
23354           ctx_list_prepend (&ctx->events.idles_to_remove, item);
23355         }
23356         else
23357           item->ticks_remaining = item->ticks_full;
23358       }
23359     }
23360   }
23361 
23362   while (ctx->events.idles_to_add)
23363   {
23364     CtxIdleCb *item = ctx->events.idles_to_add->data;
23365     ctx_list_prepend (&ctx->events.idles, item);
23366     ctx_list_remove (&ctx->events.idles_to_add, item);
23367   }
23368 
23369   while (ctx->events.idles_to_remove)
23370   {
23371     CtxIdleCb *item = ctx->events.idles_to_remove->data;
23372     if (item->destroy_notify)
23373       item->destroy_notify (item->destroy_data);
23374     ctx_list_remove (&ctx->events.idles, item);
23375     ctx_list_remove (&ctx->events.idles_to_remove, item);
23376   }
23377   ctx->events.in_idle_dispatch=0;
23378 }
23379 
23380 
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)23381 void ctx_add_key_binding_full (Ctx *ctx,
23382                            const char *key,
23383                            const char *action,
23384                            const char *label,
23385                            CtxCb       cb,
23386                            void       *cb_data,
23387                            CtxDestroyNotify destroy_notify,
23388                            void       *destroy_data)
23389 {
23390   CtxEvents *events = &ctx->events;
23391   if (events->n_bindings +1 >= CTX_MAX_KEYBINDINGS)
23392   {
23393     fprintf (stderr, "warning: binding overflow\n");
23394     return;
23395   }
23396   events->bindings[events->n_bindings].nick = strdup (key);
23397   strcpy (events->bindings[events->n_bindings].nick, key);
23398 
23399   if (action)
23400     events->bindings[events->n_bindings].command = action ? strdup (action) : NULL;
23401   if (label)
23402     events->bindings[events->n_bindings].label = label ? strdup (label) : NULL;
23403   events->bindings[events->n_bindings].cb = cb;
23404   events->bindings[events->n_bindings].cb_data = cb_data;
23405   events->bindings[events->n_bindings].destroy_notify = destroy_notify;
23406   events->bindings[events->n_bindings].destroy_data = destroy_data;
23407   events->n_bindings++;
23408 }
23409 
ctx_add_key_binding(Ctx * ctx,const char * key,const char * action,const char * label,CtxCb cb,void * cb_data)23410 void ctx_add_key_binding (Ctx *ctx,
23411                           const char *key,
23412                           const char *action,
23413                           const char *label,
23414                           CtxCb       cb,
23415                           void       *cb_data)
23416 {
23417   ctx_add_key_binding_full (ctx, key, action, label, cb, cb_data, NULL, NULL);
23418 }
23419 
ctx_clear_bindings(Ctx * ctx)23420 void ctx_clear_bindings (Ctx *ctx)
23421 {
23422   CtxEvents *events = &ctx->events;
23423   int i;
23424   for (i = 0; events->bindings[i].nick; i ++)
23425   {
23426     if (events->bindings[i].destroy_notify)
23427       events->bindings[i].destroy_notify (events->bindings[i].destroy_data);
23428     free (events->bindings[i].nick);
23429     if (events->bindings[i].command)
23430       free (events->bindings[i].command);
23431     if (events->bindings[i].label)
23432       free (events->bindings[i].label);
23433   }
23434   memset (&events->bindings, 0, sizeof (events->bindings));
23435   events->n_bindings = 0;
23436 }
23437 
23438 static void
23439 ctx_collect_events (CtxEvent *event, void *data, void *data2);
_ctx_bindings_key_press(CtxEvent * event,void * data1,void * data2)23440 static void _ctx_bindings_key_press (CtxEvent *event, void *data1, void *data2)
23441 {
23442   Ctx *ctx = event->ctx;
23443   CtxEvents *events = &ctx->events;
23444   int i;
23445   int handled = 0;
23446 
23447   for (i = events->n_bindings-1; i>=0; i--)
23448     if (!strcmp (events->bindings[i].nick, event->string))
23449     {
23450       if (events->bindings[i].cb)
23451       {
23452         events->bindings[i].cb (event, events->bindings[i].cb_data, NULL);
23453         if (event->stop_propagate)
23454           return;
23455         handled = 1;
23456       }
23457     }
23458   if (!handled)
23459   for (i = events->n_bindings-1; i>=0; i--)
23460     if (!strcmp (events->bindings[i].nick, "any"))
23461     {
23462       if (events->bindings[i].cb)
23463       {
23464         events->bindings[i].cb (event, events->bindings[i].cb_data, NULL);
23465         if (event->stop_propagate)
23466           return;
23467       }
23468     }
23469   ctx_collect_events (event, data1, data2);
23470 }
23471 
ctx_get_bindings(Ctx * ctx)23472 CtxBinding *ctx_get_bindings (Ctx *ctx)
23473 {
23474   return &ctx->events.bindings[0];
23475 }
23476 
ctx_remove_idle(Ctx * ctx,int handle)23477 void ctx_remove_idle (Ctx *ctx, int handle)
23478 {
23479   CtxList *l;
23480   //CtxList *to_remove = NULL;
23481 
23482   if (!ctx->events.idles)
23483   {
23484     return;
23485   }
23486 
23487   for (l = ctx->events.idles; l; l = l->next)
23488   {
23489     CtxIdleCb *item = l->data;
23490     if (item->id == handle)
23491     {
23492       ctx_list_prepend (&ctx->events.idles_to_remove, item);
23493     }
23494   }
23495 
23496   if (ctx->events.in_idle_dispatch)
23497     return;
23498 
23499   while (ctx->events.idles_to_remove)
23500   {
23501     CtxIdleCb *item = ctx->events.idles_to_remove->data;
23502     if (item->destroy_notify)
23503       item->destroy_notify (item->destroy_data);
23504     ctx_list_remove (&ctx->events.idles, item);
23505     ctx_list_remove (&ctx->events.idles_to_remove, item);
23506   }
23507 }
23508 
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)23509 int ctx_add_timeout_full (Ctx *ctx, int ms, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data,
23510                           void (*destroy_notify)(void *destroy_data), void *destroy_data)
23511 {
23512   CtxIdleCb *item = calloc (sizeof (CtxIdleCb), 1);
23513   item->cb              = idle_cb;
23514   item->idle_data       = idle_data;
23515   item->id              = ++ctx->events.idle_id;
23516   item->ticks_full      =
23517   item->ticks_remaining = ms * 1000;
23518   item->destroy_notify  = destroy_notify;
23519   item->destroy_data    = destroy_data;
23520   if (ctx->events.in_idle_dispatch)
23521   ctx_list_append (&ctx->events.idles_to_add, item);
23522   else
23523   ctx_list_append (&ctx->events.idles, item);
23524   return item->id;
23525 }
23526 
ctx_add_timeout(Ctx * ctx,int ms,int (* idle_cb)(Ctx * ctx,void * idle_data),void * idle_data)23527 int ctx_add_timeout (Ctx *ctx, int ms, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data)
23528 {
23529   return ctx_add_timeout_full (ctx, ms, idle_cb, idle_data, NULL, NULL);
23530 }
23531 
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)23532 int ctx_add_idle_full (Ctx *ctx, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data,
23533                                  void (*destroy_notify)(void *destroy_data), void *destroy_data)
23534 {
23535   CtxIdleCb *item = calloc (sizeof (CtxIdleCb), 1);
23536   item->cb = idle_cb;
23537   item->idle_data = idle_data;
23538   item->id = ++ctx->events.idle_id;
23539   item->ticks_full =
23540   item->ticks_remaining = -1;
23541   item->is_idle = 1;
23542   item->destroy_notify = destroy_notify;
23543   item->destroy_data = destroy_data;
23544   ctx_list_append (&ctx->events.idles, item);
23545   return item->id;
23546 }
23547 
ctx_add_idle(Ctx * ctx,int (* idle_cb)(Ctx * ctx,void * idle_data),void * idle_data)23548 int ctx_add_idle (Ctx *ctx, int (*idle_cb)(Ctx *ctx, void *idle_data), void *idle_data)
23549 {
23550   return ctx_add_idle_full (ctx, idle_cb, idle_data, NULL, NULL);
23551 }
23552 
23553 #endif
23554 /* using bigger primes would be a good idea, this falls apart due to rounding
23555  * when zoomed in close
23556  */
ctx_path_hash(void * path)23557 static inline double ctx_path_hash (void *path)
23558 {
23559   double ret = 0;
23560 #if 0
23561   int i;
23562   cairo_path_data_t *data;
23563   if (!path)
23564     return 0.99999;
23565   for (i = 0; i <path->num_data; i += path->data[i].header.length)
23566   {
23567     data = &path->data[i];
23568     switch (data->header.type) {
23569       case CAIRO_PATH_MOVE_TO:
23570         ret *= 17;
23571         ret += data[1].point.x;
23572         ret *= 113;
23573         ret += data[1].point.y;
23574         break;
23575       case CAIRO_PATH_LINE_TO:
23576         ret *= 121;
23577         ret += data[1].point.x;
23578         ret *= 1021;
23579         ret += data[1].point.y;
23580         break;
23581       case CAIRO_PATH_CURVE_TO:
23582         ret *= 3111;
23583         ret += data[1].point.x;
23584         ret *= 23;
23585         ret += data[1].point.y;
23586         ret *= 107;
23587         ret += data[2].point.x;
23588         ret *= 739;
23589         ret += data[2].point.y;
23590         ret *= 3;
23591         ret += data[3].point.x;
23592         ret *= 51;
23593         ret += data[3].point.y;
23594         break;
23595       case CAIRO_PATH_CLOSE_PATH:
23596         ret *= 51;
23597         break;
23598     }
23599   }
23600 #endif
23601   return ret;
23602 }
23603 
23604 #if CTX_EVENTS
_ctx_item_ref(CtxItem * item)23605 void _ctx_item_ref (CtxItem *item)
23606 {
23607   if (item->ref_count < 0)
23608   {
23609     fprintf (stderr, "EEEEK!\n");
23610   }
23611   item->ref_count++;
23612 }
23613 
23614 
_ctx_item_unref(CtxItem * item)23615 void _ctx_item_unref (CtxItem *item)
23616 {
23617   if (item->ref_count <= 0)
23618   {
23619     fprintf (stderr, "EEEEK!\n");
23620     return;
23621   }
23622   item->ref_count--;
23623   if (item->ref_count <=0)
23624   {
23625     {
23626       int i;
23627       for (i = 0; i < item->cb_count; i++)
23628       {
23629         if (item->cb[i].finalize)
23630           item->cb[i].finalize (item->cb[i].data1, item->cb[i].data2,
23631                                    item->cb[i].finalize_data);
23632       }
23633     }
23634     if (item->path)
23635     {
23636       //cairo_path_destroy (item->path);
23637     }
23638     free (item);
23639   }
23640 }
23641 
23642 
23643 static int
path_equal(void * path,void * path2)23644 path_equal (void *path,
23645             void *path2)
23646 {
23647   //  XXX
23648   return 0;
23649 }
23650 
ctx_listen_set_cursor(Ctx * ctx,CtxCursor cursor)23651 void ctx_listen_set_cursor (Ctx      *ctx,
23652                             CtxCursor cursor)
23653 {
23654   if (ctx->events.last_item)
23655   {
23656     ctx->events.last_item->cursor = cursor;
23657   }
23658 }
23659 
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)23660 void ctx_listen_full (Ctx     *ctx,
23661                       float    x,
23662                       float    y,
23663                       float    width,
23664                       float    height,
23665                       CtxEventType  types,
23666                       CtxCb    cb,
23667                       void    *data1,
23668                       void    *data2,
23669                       void   (*finalize)(void *listen_data,
23670                                          void *listen_data2,
23671                                          void *finalize_data),
23672                       void    *finalize_data)
23673 {
23674   if (!ctx->events.frozen)
23675   {
23676     CtxItem *item;
23677 
23678     /* early bail for listeners outside screen  */
23679     /* XXX: fixme respect clipping */
23680     {
23681       float tx = x;
23682       float ty = y;
23683       float tw = width;
23684       float th = height;
23685       _ctx_user_to_device (&ctx->state, &tx, &ty);
23686       _ctx_user_to_device_distance (&ctx->state, &tw, &th);
23687       if (ty > ctx->events.height * 2 ||
23688           tx > ctx->events.width * 2 ||
23689           tx + tw < 0 ||
23690           ty + th < 0)
23691       {
23692         if (finalize)
23693           finalize (data1, data2, finalize_data);
23694         return;
23695       }
23696     }
23697 
23698     item = calloc (sizeof (CtxItem), 1);
23699     item->x0 = x;
23700     item->y0 = y;
23701     item->x1 = x + width;
23702     item->y1 = y + height;
23703     item->cb[0].types = types;
23704     item->cb[0].cb = cb;
23705     item->cb[0].data1 = data1;
23706     item->cb[0].data2 = data2;
23707     item->cb[0].finalize = finalize;
23708     item->cb[0].finalize_data = finalize_data;
23709     item->cb_count = 1;
23710     item->types = types;
23711     //item->path = cairo_copy_path (cr); // XXX
23712     item->path_hash = ctx_path_hash (item->path);
23713     ctx_get_matrix (ctx, &item->inv_matrix);
23714     ctx_matrix_invert (&item->inv_matrix);
23715 
23716     if (ctx->events.items)
23717     {
23718       CtxList *l;
23719       for (l = ctx->events.items; l; l = l->next)
23720       {
23721         CtxItem *item2 = l->data;
23722 
23723         /* store multiple callbacks for one entry when the paths
23724          * are exact matches, reducing per event traversal checks at the
23725          * cost of a little paint-hit (XXX: is this the right tradeoff,
23726          * perhaps it is better to spend more time during event processing
23727          * than during paint?)
23728          */
23729         if (item->path_hash == item2->path_hash &&
23730             path_equal (item->path, item2->path))
23731         {
23732           /* found an item, copy over cb data  */
23733           item2->cb[item2->cb_count] = item->cb[0];
23734           free (item);
23735           item2->cb_count++;
23736           item2->types |= types;
23737           return;
23738         }
23739       }
23740     }
23741     item->ref_count       = 1;
23742     ctx->events.last_item = item;
23743     ctx_list_prepend_full (&ctx->events.items, item, (void*)_ctx_item_unref, NULL);
23744   }
23745 }
23746 
ctx_event_stop_propagate(CtxEvent * event)23747 void ctx_event_stop_propagate (CtxEvent *event)
23748 {
23749   if (event)
23750     event->stop_propagate = 1;
23751 }
23752 
ctx_listen(Ctx * ctx,CtxEventType types,CtxCb cb,void * data1,void * data2)23753 void ctx_listen (Ctx          *ctx,
23754                  CtxEventType  types,
23755                  CtxCb         cb,
23756                  void*         data1,
23757                  void*         data2)
23758 {
23759   float x, y, width, height;
23760   /* generate bounding box of what to listen for - from current cairo path */
23761   if (types & CTX_KEY)
23762   {
23763     x = 0;
23764     y = 0;
23765     width = 0;
23766     height = 0;
23767   }
23768   else
23769   {
23770      float ex1,ey1,ex2,ey2;
23771      ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
23772      x = ex1;
23773      y = ey1;
23774      width = ex2 - ex1;
23775      height = ey2 - ey1;
23776   }
23777 
23778   if (types == CTX_DRAG_MOTION)
23779     types = CTX_DRAG_MOTION | CTX_DRAG_PRESS;
23780   return ctx_listen_full (ctx, x, y, width, height, types, cb, data1, data2, NULL, NULL);
23781 }
23782 
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)23783 void  ctx_listen_with_finalize (Ctx          *ctx,
23784                                 CtxEventType  types,
23785                                 CtxCb         cb,
23786                                 void*         data1,
23787                                 void*         data2,
23788                       void   (*finalize)(void *listen_data, void *listen_data2,
23789                                          void *finalize_data),
23790                       void    *finalize_data)
23791 {
23792   float x, y, width, height;
23793   /* generate bounding box of what to listen for - from current cairo path */
23794   if (types & CTX_KEY)
23795   {
23796     x = 0;
23797     y = 0;
23798     width = 0;
23799     height = 0;
23800   }
23801   else
23802   {
23803      float ex1,ey1,ex2,ey2;
23804      ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
23805      x = ex1;
23806      y = ey1;
23807      width = ex2 - ex1;
23808      height = ey2 - ey1;
23809   }
23810 
23811   if (types == CTX_DRAG_MOTION)
23812     types = CTX_DRAG_MOTION | CTX_DRAG_PRESS;
23813   return ctx_listen_full (ctx, x, y, width, height, types, cb, data1, data2, finalize, finalize_data);
23814 }
23815 
23816 
ctx_report_hit_region(CtxEvent * event,void * data,void * data2)23817 static void ctx_report_hit_region (CtxEvent *event,
23818                        void     *data,
23819                        void     *data2)
23820 {
23821   const char *id = data;
23822 
23823   fprintf (stderr, "hit region %s\n", id);
23824   // XXX: NYI
23825 }
23826 
ctx_add_hit_region(Ctx * ctx,const char * id)23827 void ctx_add_hit_region (Ctx *ctx, const char *id)
23828 {
23829   char *id_copy = strdup (id);
23830   float x, y, width, height;
23831   /* generate bounding box of what to listen for - from current cairo path */
23832   {
23833      float ex1,ey1,ex2,ey2;
23834      ctx_path_extents (ctx, &ex1, &ey1, &ex2, &ey2);
23835      x = ex1;
23836      y = ey1;
23837      width = ex2 - ex1;
23838      height = ey2 - ey1;
23839   }
23840 
23841   return ctx_listen_full (ctx, x, y, width, height,
23842                           CTX_POINTER, ctx_report_hit_region,
23843                           id_copy, NULL, (void*)free, NULL);
23844 }
23845 
23846 typedef struct _CtxGrab CtxGrab;
23847 
23848 struct _CtxGrab
23849 {
23850   CtxItem *item;
23851   int      device_no;
23852   int      timeout_id;
23853   int      start_time;
23854   float    x; // for tap and hold
23855   float    y;
23856   CtxEventType  type;
23857 };
23858 
grab_free(Ctx * ctx,CtxGrab * grab)23859 static void grab_free (Ctx *ctx, CtxGrab *grab)
23860 {
23861   if (grab->timeout_id)
23862   {
23863     ctx_remove_idle (ctx, grab->timeout_id);
23864     grab->timeout_id = 0;
23865   }
23866   _ctx_item_unref (grab->item);
23867   free (grab);
23868 }
23869 
device_remove_grab(Ctx * ctx,CtxGrab * grab)23870 static void device_remove_grab (Ctx *ctx, CtxGrab *grab)
23871 {
23872   ctx_list_remove (&ctx->events.grabs, grab);
23873   grab_free (ctx, grab);
23874 }
23875 
device_add_grab(Ctx * ctx,int device_no,CtxItem * item,CtxEventType type)23876 static CtxGrab *device_add_grab (Ctx *ctx, int device_no, CtxItem *item, CtxEventType type)
23877 {
23878   CtxGrab *grab = calloc (1, sizeof (CtxGrab));
23879   grab->item = item;
23880   grab->type = type;
23881   _ctx_item_ref (item);
23882   grab->device_no = device_no;
23883   ctx_list_append (&ctx->events.grabs, grab);
23884   return grab;
23885 }
23886 
_ctx_device_get_grabs(Ctx * ctx,int device_no)23887 static CtxList *_ctx_device_get_grabs (Ctx *ctx, int device_no)
23888 {
23889   CtxList *ret = NULL;
23890   CtxList *l;
23891   for (l = ctx->events.grabs; l; l = l->next)
23892   {
23893     CtxGrab *grab = l->data;
23894     if (grab->device_no == device_no)
23895       ctx_list_append (&ret, grab);
23896   }
23897   return ret;
23898 }
23899 
_mrg_restore_path(Ctx * ctx,void * path)23900 static void _mrg_restore_path (Ctx *ctx, void *path)  //XXX
23901 {
23902   //int i;
23903   //cairo_path_data_t *data;
23904   //cairo_new_path (cr);
23905   //cairo_append_path (cr, path);
23906 }
23907 
_ctx_detect_list(Ctx * ctx,float x,float y,CtxEventType type)23908 CtxList *_ctx_detect_list (Ctx *ctx, float x, float y, CtxEventType type)
23909 {
23910   CtxList *a;
23911   CtxList *ret = NULL;
23912 
23913   if (type == CTX_KEY_DOWN ||
23914       type == CTX_KEY_UP ||
23915       type == CTX_KEY_PRESS ||
23916       type == CTX_MESSAGE ||
23917       type == (CTX_KEY_DOWN|CTX_MESSAGE) ||
23918       type == (CTX_KEY_DOWN|CTX_KEY_UP) ||
23919       type == (CTX_KEY_DOWN|CTX_KEY_UP|CTX_MESSAGE))
23920   {
23921     for (a = ctx->events.items; a; a = a->next)
23922     {
23923       CtxItem *item = a->data;
23924       if (item->types & type)
23925       {
23926         ctx_list_prepend (&ret, item);
23927         return ret;
23928       }
23929     }
23930     return NULL;
23931   }
23932 
23933   for (a = ctx->events.items; a; a = a->next)
23934   {
23935     CtxItem *item= a->data;
23936 
23937     float u, v;
23938     u = x;
23939     v = y;
23940     _ctx_matrix_apply_transform (&item->inv_matrix, &u, &v);
23941 
23942     if (u >= item->x0 && v >= item->y0 &&
23943         u <  item->x1 && v <  item->y1 &&
23944         ((item->types & type) || ((type == CTX_SET_CURSOR) &&
23945         item->cursor)))
23946     {
23947       if (item->path)
23948       {
23949         _mrg_restore_path (ctx, item->path);
23950         if (ctx_in_fill (ctx, u, v))
23951         {
23952           ctx_begin_path (ctx);
23953           ctx_list_prepend (&ret, item);
23954         }
23955         ctx_begin_path (ctx);
23956       }
23957       else
23958       {
23959         ctx_list_prepend (&ret, item);
23960       }
23961     }
23962   }
23963   return ret;
23964 }
23965 
_ctx_detect(Ctx * ctx,float x,float y,CtxEventType type)23966 CtxItem *_ctx_detect (Ctx *ctx, float x, float y, CtxEventType type)
23967 {
23968   CtxList *l = _ctx_detect_list (ctx, x, y, type);
23969   if (l)
23970   {
23971     ctx_list_reverse (&l);
23972     CtxItem *ret = l->data;
23973     ctx_list_free (&l);
23974     return ret;
23975   }
23976   return NULL;
23977 }
23978 
23979 static int
_ctx_emit_cb_item(Ctx * ctx,CtxItem * item,CtxEvent * event,CtxEventType type,float x,float y)23980 _ctx_emit_cb_item (Ctx *ctx, CtxItem *item, CtxEvent *event, CtxEventType type, float x, float y)
23981 {
23982   static CtxEvent s_event;
23983   CtxEvent transformed_event;
23984   int i;
23985 
23986 
23987   if (!event)
23988   {
23989     event = &s_event;
23990     event->type = type;
23991     event->x = x;
23992     event->y = y;
23993   }
23994   event->ctx = ctx;
23995   transformed_event = *event;
23996   transformed_event.device_x = event->x;
23997   transformed_event.device_y = event->y;
23998 
23999   {
24000     float tx, ty;
24001     tx = transformed_event.x;
24002     ty = transformed_event.y;
24003     _ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
24004     transformed_event.x = tx;
24005     transformed_event.y = ty;
24006 
24007     if ((type & CTX_DRAG_PRESS) ||
24008         (type & CTX_DRAG_MOTION) ||
24009         (type & CTX_MOTION))   /* probably a worthwhile check for the performance
24010                                   benefit
24011                                 */
24012     {
24013       tx = transformed_event.start_x;
24014       ty = transformed_event.start_y;
24015       _ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
24016       transformed_event.start_x = tx;
24017       transformed_event.start_y = ty;
24018     }
24019 
24020 
24021     tx = transformed_event.delta_x;
24022     ty = transformed_event.delta_y;
24023     _ctx_matrix_apply_transform (&item->inv_matrix, &tx, &ty);
24024     transformed_event.delta_x = tx;
24025     transformed_event.delta_y = ty;
24026   }
24027 
24028   transformed_event.state = ctx->events.modifier_state;
24029   transformed_event.type = type;
24030 
24031   for (i = item->cb_count-1; i >= 0; i--)
24032   {
24033     if (item->cb[i].types & type)
24034     {
24035       item->cb[i].cb (&transformed_event, item->cb[i].data1, item->cb[i].data2);
24036       event->stop_propagate = transformed_event.stop_propagate; /* copy back the response */
24037       if (event->stop_propagate)
24038         return event->stop_propagate;
24039     }
24040   }
24041   return 0;
24042 }
24043 #endif
24044 
24045 #if CTX_EVENTS
24046 
24047 #if !__COSMOPOLITAN__
24048 #include <stdatomic.h>
24049 #endif
24050 
24051 int ctx_native_events = 0;
24052 #if CTX_SDL
24053 int ctx_sdl_events = 0;
24054 int ctx_sdl_consume_events (Ctx *ctx);
24055 #endif
24056 
24057 #if CTX_FB
24058 int ctx_fb_events = 0;
24059 int ctx_fb_consume_events (Ctx *ctx);
24060 #endif
24061 
24062 #if CTX_KMS
24063 int ctx_kms_events = 0;
24064 int ctx_kms_consume_events (Ctx *ctx);
24065 #endif
24066 
24067 int ctx_nct_consume_events (Ctx *ctx);
24068 int ctx_nct_has_event (Ctx  *n, int delay_ms);
24069 int ctx_ctx_consume_events (Ctx *ctx);
24070 
24071 
24072 
ctx_consume_events(Ctx * ctx)24073 void ctx_consume_events (Ctx *ctx)
24074 {
24075 #if CTX_SDL
24076   if (ctx_sdl_events)
24077     ctx_sdl_consume_events (ctx);
24078   else
24079 #endif
24080 #if CTX_FB
24081   if (ctx_fb_events)
24082     ctx_fb_consume_events (ctx);
24083   else
24084 #endif
24085 #if CTX_KMS
24086   if (ctx_kms_events)
24087     ctx_kms_consume_events (ctx);
24088   else
24089 #endif
24090   if (ctx_native_events)
24091     ctx_ctx_consume_events (ctx);
24092   else
24093     ctx_nct_consume_events (ctx);
24094 }
24095 
ctx_has_event(Ctx * ctx,int timeout)24096 int ctx_has_event (Ctx *ctx, int timeout)
24097 {
24098 #if CTX_SDL
24099   if (ctx_sdl_events)
24100   {
24101     return SDL_WaitEventTimeout (NULL, timeout);
24102   }
24103   else
24104 #endif
24105 #if CTX_FB
24106   if (ctx_fb_events)
24107   {
24108     return ctx_nct_has_event (ctx, timeout);
24109   }
24110   else
24111 #endif
24112   if (ctx_native_events)
24113   {
24114     return ctx_nct_has_event (ctx, timeout);
24115   }
24116   else
24117   {
24118     return ctx_nct_has_event (ctx, timeout);
24119   }
24120 
24121   ctx_consume_events (ctx);
24122   if (ctx->events.events)
24123     return 1;
24124   return 0;
24125 }
24126 
24127 #if CTX_FB
24128 static int ctx_fb_get_mice_fd (Ctx *ctx);
24129 #endif
24130 
ctx_get_event_fds(Ctx * ctx,int * fd,int * count)24131 void ctx_get_event_fds (Ctx *ctx, int *fd, int *count)
24132 {
24133 #if CTX_SDL
24134   if (ctx_sdl_events)
24135   {
24136     *count = 0;
24137   }
24138   else
24139 #endif
24140 #if CTX_FB
24141   if (ctx_fb_events)
24142   {
24143     int mice_fd = ctx_fb_get_mice_fd (ctx);
24144     fd[0] = STDIN_FILENO;
24145     if (mice_fd)
24146     {
24147       fd[1] = mice_fd;
24148       *count = 2;
24149     }
24150     else
24151     {
24152       *count = 1;
24153     }
24154   }
24155   else
24156 #endif
24157   if (ctx_native_events)
24158   {
24159     fd[0] = STDIN_FILENO;
24160     *count = 1;
24161   }
24162   else
24163   {
24164     fd[0] = STDIN_FILENO;
24165     *count = 1;
24166   }
24167 }
24168 
ctx_get_event(Ctx * ctx)24169 CtxEvent *ctx_get_event (Ctx *ctx)
24170 {
24171   static CtxEvent event_copy;
24172   if (ctx->events.events)
24173     {
24174       event_copy = *((CtxEvent*)(ctx->events.events->data));
24175       ctx_list_remove (&ctx->events.events, ctx->events.events->data);
24176       return &event_copy;
24177     }
24178 
24179   _ctx_idle_iteration (ctx);
24180   if (!ctx->events.ctx_get_event_enabled)
24181     ctx->events.ctx_get_event_enabled = 1;
24182 
24183   ctx_consume_events (ctx);
24184 
24185   if (ctx->events.events)
24186     {
24187       event_copy = *((CtxEvent*)(ctx->events.events->data));
24188       ctx_list_remove (&ctx->events.events, ctx->events.events->data);
24189       return &event_copy;
24190     }
24191   return NULL;
24192 }
24193 
24194 static int
_ctx_emit_cb(Ctx * ctx,CtxList * items,CtxEvent * event,CtxEventType type,float x,float y)24195 _ctx_emit_cb (Ctx *ctx, CtxList *items, CtxEvent *event, CtxEventType type, float x, float y)
24196 {
24197   CtxList *l;
24198   event->stop_propagate = 0;
24199   for (l = items; l; l = l->next)
24200   {
24201     _ctx_emit_cb_item (ctx, l->data, event, type, x, y);
24202     if (event->stop_propagate)
24203       return event->stop_propagate;
24204   }
24205   return 0;
24206 }
24207 
24208 /*
24209  * update what is the currently hovered item and returns it.. and the list of hits
24210  * a well.
24211  *
24212  */
_ctx_update_item(Ctx * ctx,int device_no,float x,float y,CtxEventType type,CtxList ** hitlist)24213 static CtxItem *_ctx_update_item (Ctx *ctx, int device_no, float x, float y, CtxEventType type, CtxList **hitlist)
24214 {
24215   CtxItem *current = NULL;
24216 
24217   CtxList *l = _ctx_detect_list (ctx, x, y, type);
24218   if (l)
24219   {
24220     ctx_list_reverse (&l);
24221     current = l->data;
24222   }
24223   if (hitlist)
24224     *hitlist = l;
24225   else
24226     ctx_list_free (&l);
24227 
24228   if (ctx->events.prev[device_no] == NULL || current == NULL || (current->path_hash != ctx->events.prev[device_no]->path_hash))
24229   {
24230 // enter/leave should snapshot chain to root
24231 // and compare with previous snapshotted chain to root
24232 // and emit/enter/leave as appropriate..
24233 //
24234 // leave might be registered for emission on enter..emission?
24235 
24236 
24237     //int focus_radius = 2;
24238     if (current)
24239       _ctx_item_ref (current);
24240 
24241     if (ctx->events.prev[device_no])
24242     {
24243       {
24244 #if 0
24245         CtxIntRectangle rect = {floor(ctx->events.prev[device_no]->x0-focus_radius),
24246                              floor(ctx->events.prev[device_no]->y0-focus_radius),
24247                              ceil(ctx->events.prev[device_no]->x1)-floor(ctx->events.prev[device_no]->x0) + focus_radius * 2,
24248                              ceil(ctx->events.prev[device_no]->y1)-floor(ctx->events.prev[device_no]->y0) + focus_radius * 2};
24249         mrg_queue_draw (mrg, &rect);
24250 #endif
24251       }
24252 
24253       _ctx_emit_cb_item (ctx, ctx->events.prev[device_no], NULL, CTX_LEAVE, x, y);
24254       _ctx_item_unref (ctx->events.prev[device_no]);
24255       ctx->events.prev[device_no] = NULL;
24256     }
24257     if (current)
24258     {
24259 #if 0
24260       {
24261         CtxIntRectangle rect = {floor(current->x0-focus_radius),
24262                              floor(current->y0-focus_radius),
24263                              ceil(current->x1)-floor(current->x0) + focus_radius * 2,
24264                              ceil(current->y1)-floor(current->y0) + focus_radius * 2};
24265         mrg_queue_draw (mrg, &rect);
24266       }
24267 #endif
24268       _ctx_emit_cb_item (ctx, current, NULL, CTX_ENTER, x, y);
24269       ctx->events.prev[device_no] = current;
24270     }
24271   }
24272   current = _ctx_detect (ctx, x, y, type);
24273   //fprintf (stderr, "%p\n", current);
24274   return current;
24275 }
24276 
tap_and_hold_fire(Ctx * ctx,void * data)24277 static int tap_and_hold_fire (Ctx *ctx, void *data)
24278 {
24279   CtxGrab *grab = data;
24280   CtxList *list = NULL;
24281   ctx_list_prepend (&list, grab->item);
24282   CtxEvent event = {0, };
24283 
24284   event.ctx = ctx;
24285   event.time = ctx_ms (ctx);
24286 
24287   event.device_x =
24288   event.x = ctx->events.pointer_x[grab->device_no];
24289   event.device_y =
24290   event.y = ctx->events.pointer_y[grab->device_no];
24291 
24292   // XXX: x and y coordinates
24293   int ret = _ctx_emit_cb (ctx, list, &event, CTX_TAP_AND_HOLD,
24294       ctx->events.pointer_x[grab->device_no], ctx->events.pointer_y[grab->device_no]);
24295 
24296   ctx_list_free (&list);
24297 
24298   grab->timeout_id = 0;
24299 
24300   return 0;
24301 
24302   return ret;
24303 }
24304 
ctx_pointer_drop(Ctx * ctx,float x,float y,int device_no,uint32_t time,char * string)24305 int ctx_pointer_drop (Ctx *ctx, float x, float y, int device_no, uint32_t time,
24306                       char *string)
24307 {
24308   CtxList *l;
24309   CtxList *hitlist = NULL;
24310 
24311   ctx->events.pointer_x[device_no] = x;
24312   ctx->events.pointer_y[device_no] = y;
24313   if (device_no <= 3)
24314   {
24315     ctx->events.pointer_x[0] = x;
24316     ctx->events.pointer_y[0] = y;
24317   }
24318 
24319   if (device_no < 0) device_no = 0;
24320   if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
24321   CtxEvent *event = &ctx->events.drag_event[device_no];
24322 
24323   if (time == 0)
24324     time = ctx_ms (ctx);
24325 
24326   event->ctx = ctx;
24327   event->x = x;
24328   event->y = y;
24329 
24330   event->delta_x = event->delta_y = 0;
24331 
24332   event->device_no = device_no;
24333   event->string    = string;
24334   event->time      = time;
24335   event->stop_propagate = 0;
24336 
24337   _ctx_update_item (ctx, device_no, x, y, CTX_DROP, &hitlist);
24338 
24339   for (l = hitlist; l; l = l?l->next:NULL)
24340   {
24341     CtxItem *item = l->data;
24342     _ctx_emit_cb_item (ctx, item, event, CTX_DROP, x, y);
24343 
24344     if (event->stop_propagate)
24345     {
24346       ctx_list_free (&hitlist);
24347       return 0;
24348     }
24349   }
24350 
24351   //mrg_queue_draw (mrg, NULL); /* in case of style change, and more  */
24352   ctx_list_free (&hitlist);
24353 
24354   return 0;
24355 }
24356 
ctx_pointer_press(Ctx * ctx,float x,float y,int device_no,uint32_t time)24357 int ctx_pointer_press (Ctx *ctx, float x, float y, int device_no, uint32_t time)
24358 {
24359   CtxEvents *events = &ctx->events;
24360   CtxList *hitlist = NULL;
24361   events->pointer_x[device_no] = x;
24362   events->pointer_y[device_no] = y;
24363   if (device_no <= 3)
24364   {
24365     events->pointer_x[0] = x;
24366     events->pointer_y[0] = y;
24367   }
24368 
24369   if (device_no < 0) device_no = 0;
24370   if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
24371   CtxEvent *event = &events->drag_event[device_no];
24372 
24373   if (time == 0)
24374     time = ctx_ms (ctx);
24375 
24376   event->x = event->start_x = event->prev_x = x;
24377   event->y = event->start_y = event->prev_y = y;
24378 
24379   event->delta_x = event->delta_y = 0;
24380 
24381   event->device_no = device_no;
24382   event->time      = time;
24383   event->stop_propagate = 0;
24384 
24385   if (events->pointer_down[device_no] == 1)
24386   {
24387     fprintf (stderr, "events thought device %i was already down\n", device_no);
24388   }
24389   /* doing just one of these two should be enough? */
24390   events->pointer_down[device_no] = 1;
24391   switch (device_no)
24392   {
24393     case 1:
24394       events->modifier_state |= CTX_MODIFIER_STATE_BUTTON1;
24395       break;
24396     case 2:
24397       events->modifier_state |= CTX_MODIFIER_STATE_BUTTON2;
24398       break;
24399     case 3:
24400       events->modifier_state |= CTX_MODIFIER_STATE_BUTTON3;
24401       break;
24402     default:
24403       break;
24404   }
24405 
24406   CtxGrab *grab = NULL;
24407   CtxList *l;
24408 
24409   _ctx_update_item (ctx, device_no, x, y,
24410       CTX_PRESS | CTX_DRAG_PRESS | CTX_TAP | CTX_TAP_AND_HOLD, &hitlist);
24411 
24412   for (l = hitlist; l; l = l?l->next:NULL)
24413   {
24414     CtxItem *item = l->data;
24415     if (item &&
24416         ((item->types & CTX_DRAG)||
24417          (item->types & CTX_TAP) ||
24418          (item->types & CTX_TAP_AND_HOLD)))
24419     {
24420       grab = device_add_grab (ctx, device_no, item, item->types);
24421       grab->start_time = time;
24422 
24423       if (item->types & CTX_TAP_AND_HOLD)
24424       {
24425          grab->timeout_id = ctx_add_timeout (ctx, events->tap_delay_hold, tap_and_hold_fire, grab);
24426       }
24427     }
24428     _ctx_emit_cb_item (ctx, item, event, CTX_PRESS, x, y);
24429     if (!event->stop_propagate)
24430       _ctx_emit_cb_item (ctx, item, event, CTX_DRAG_PRESS, x, y);
24431 
24432     if (event->stop_propagate)
24433     {
24434       ctx_list_free (&hitlist);
24435       return 0;
24436     }
24437   }
24438 
24439   //events_queue_draw (mrg, NULL); /* in case of style change, and more  */
24440   ctx_list_free (&hitlist);
24441   return 0;
24442 }
24443 
_ctx_resized(Ctx * ctx,int width,int height,long time)24444 void _ctx_resized (Ctx *ctx, int width, int height, long time)
24445 {
24446   CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_PRESS);
24447   CtxEvent event = {0, };
24448 
24449   if (!time)
24450     time = ctx_ms (ctx);
24451 
24452   event.ctx = ctx;
24453   event.time = time;
24454   event.string = "resize-event"; /* gets delivered to clients as a key_down event, maybe message shouldbe used instead?
24455    */
24456 
24457   if (item)
24458   {
24459     event.stop_propagate = 0;
24460     _ctx_emit_cb_item (ctx, item, &event, CTX_KEY_PRESS, 0, 0);
24461   }
24462 
24463 }
24464 
ctx_pointer_release(Ctx * ctx,float x,float y,int device_no,uint32_t time)24465 int ctx_pointer_release (Ctx *ctx, float x, float y, int device_no, uint32_t time)
24466 {
24467   CtxEvents *events = &ctx->events;
24468   if (time == 0)
24469     time = ctx_ms (ctx);
24470 
24471   if (device_no < 0) device_no = 0;
24472   if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
24473   CtxEvent *event = &events->drag_event[device_no];
24474 
24475   event->time = time;
24476   event->x = x;
24477   event->ctx = ctx;
24478   event->y = y;
24479   event->device_no = device_no;
24480   event->stop_propagate = 0;
24481 
24482   switch (device_no)
24483   {
24484     case 1:
24485       if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON1)
24486         events->modifier_state -= CTX_MODIFIER_STATE_BUTTON1;
24487       break;
24488     case 2:
24489       if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON2)
24490         events->modifier_state -= CTX_MODIFIER_STATE_BUTTON2;
24491       break;
24492     case 3:
24493       if (events->modifier_state & CTX_MODIFIER_STATE_BUTTON3)
24494         events->modifier_state -= CTX_MODIFIER_STATE_BUTTON3;
24495       break;
24496     default:
24497       break;
24498   }
24499 
24500   //events_queue_draw (mrg, NULL); /* in case of style change */
24501 
24502   if (events->pointer_down[device_no] == 0)
24503   {
24504     fprintf (stderr, "device %i already up\n", device_no);
24505   }
24506   events->pointer_down[device_no] = 0;
24507 
24508   events->pointer_x[device_no] = x;
24509   events->pointer_y[device_no] = y;
24510   if (device_no <= 3)
24511   {
24512     events->pointer_x[0] = x;
24513     events->pointer_y[0] = y;
24514   }
24515   CtxList *hitlist = NULL;
24516   CtxList *grablist = NULL , *g= NULL;
24517   CtxGrab *grab;
24518 
24519   _ctx_update_item (ctx, device_no, x, y, CTX_RELEASE | CTX_DRAG_RELEASE, &hitlist);
24520   grablist = _ctx_device_get_grabs (ctx, device_no);
24521 
24522   for (g = grablist; g; g = g->next)
24523   {
24524     grab = g->data;
24525 
24526     if (!event->stop_propagate)
24527     {
24528       if (grab->item->types & CTX_TAP)
24529       {
24530         long delay = time - grab->start_time;
24531 
24532         if (delay > events->tap_delay_min &&
24533             delay < events->tap_delay_max &&
24534             (
24535               (event->start_x - x) * (event->start_x - x) +
24536               (event->start_y - y) * (event->start_y - y)) < ctx_pow2(events->tap_hysteresis)
24537             )
24538         {
24539           _ctx_emit_cb_item (ctx, grab->item, event, CTX_TAP, x, y);
24540         }
24541       }
24542 
24543       if (!event->stop_propagate && grab->item->types & CTX_DRAG_RELEASE)
24544       {
24545         _ctx_emit_cb_item (ctx, grab->item, event, CTX_DRAG_RELEASE, x, y);
24546       }
24547     }
24548 
24549     device_remove_grab (ctx, grab);
24550   }
24551 
24552   if (hitlist)
24553   {
24554     if (!event->stop_propagate)
24555       _ctx_emit_cb (ctx, hitlist, event, CTX_RELEASE, x, y);
24556     ctx_list_free (&hitlist);
24557   }
24558   ctx_list_free (&grablist);
24559   return 0;
24560 }
24561 
24562 /*  for multi-touch, we use a list of active grabs - thus a grab corresponds to
24563  *  a device id. even during drag-grabs events propagate; to stop that stop
24564  *  propagation.
24565  */
ctx_pointer_motion(Ctx * ctx,float x,float y,int device_no,uint32_t time)24566 int ctx_pointer_motion (Ctx *ctx, float x, float y, int device_no, uint32_t time)
24567 {
24568   CtxList *hitlist = NULL;
24569   CtxList *grablist = NULL, *g;
24570   CtxGrab *grab;
24571 
24572   if (device_no < 0) device_no = 0;
24573   if (device_no >= CTX_MAX_DEVICES) device_no = CTX_MAX_DEVICES-1;
24574   CtxEvent *event = &ctx->events.drag_event[device_no];
24575 
24576   if (time == 0)
24577     time = ctx_ms (ctx);
24578 
24579   event->ctx       = ctx;
24580   event->x         = x;
24581   event->y         = y;
24582   event->time      = time;
24583   event->device_no = device_no;
24584   event->stop_propagate = 0;
24585 
24586   ctx->events.pointer_x[device_no] = x;
24587   ctx->events.pointer_y[device_no] = y;
24588 
24589   if (device_no <= 3)
24590   {
24591     ctx->events.pointer_x[0] = x;
24592     ctx->events.pointer_y[0] = y;
24593   }
24594 
24595   grablist = _ctx_device_get_grabs (ctx, device_no);
24596   _ctx_update_item (ctx, device_no, x, y, CTX_MOTION, &hitlist);
24597 
24598   {
24599     CtxItem  *cursor_item = _ctx_detect (ctx, x, y, CTX_SET_CURSOR);
24600     if (cursor_item)
24601     {
24602       ctx_set_cursor (ctx, cursor_item->cursor);
24603     }
24604     else
24605     {
24606       ctx_set_cursor (ctx, CTX_CURSOR_ARROW);
24607     }
24608     CtxItem  *hovered_item = _ctx_detect (ctx, x, y, CTX_ANY);
24609     static CtxItem *prev_hovered_item = NULL;
24610     if (prev_hovered_item != hovered_item)
24611     {
24612       ctx_set_dirty (ctx, 1);
24613     }
24614     prev_hovered_item = hovered_item;
24615   }
24616 
24617   event->delta_x = x - event->prev_x;
24618   event->delta_y = y - event->prev_y;
24619   event->prev_x  = x;
24620   event->prev_y  = y;
24621 
24622   CtxList *remove_grabs = NULL;
24623 
24624   for (g = grablist; g; g = g->next)
24625   {
24626     grab = g->data;
24627 
24628     if ((grab->type & CTX_TAP) ||
24629         (grab->type & CTX_TAP_AND_HOLD))
24630     {
24631       if (
24632           (
24633             (event->start_x - x) * (event->start_x - x) +
24634             (event->start_y - y) * (event->start_y - y)) >
24635               ctx_pow2(ctx->events.tap_hysteresis)
24636          )
24637       {
24638         //fprintf (stderr, "-");
24639         ctx_list_prepend (&remove_grabs, grab);
24640       }
24641       else
24642       {
24643         //fprintf (stderr, ":");
24644       }
24645     }
24646 
24647     if (grab->type & CTX_DRAG_MOTION)
24648     {
24649       _ctx_emit_cb_item (ctx, grab->item, event, CTX_DRAG_MOTION, x, y);
24650       if (event->stop_propagate)
24651         break;
24652     }
24653   }
24654   if (remove_grabs)
24655   {
24656     for (g = remove_grabs; g; g = g->next)
24657       device_remove_grab (ctx, g->data);
24658     ctx_list_free (&remove_grabs);
24659   }
24660   if (hitlist)
24661   {
24662     if (!event->stop_propagate)
24663       _ctx_emit_cb (ctx, hitlist, event, CTX_MOTION, x, y);
24664     ctx_list_free (&hitlist);
24665   }
24666   ctx_list_free (&grablist);
24667   return 0;
24668 }
24669 
ctx_incoming_message(Ctx * ctx,const char * message,long time)24670 void ctx_incoming_message (Ctx *ctx, const char *message, long time)
24671 {
24672   CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_MESSAGE);
24673   CtxEvent event = {0, };
24674 
24675   if (!time)
24676     time = ctx_ms (ctx);
24677 
24678   if (item)
24679   {
24680     int i;
24681     event.ctx = ctx;
24682     event.type = CTX_MESSAGE;
24683     event.time = time;
24684     event.string = message;
24685 
24686     fprintf (stderr, "{%s|\n", message);
24687 
24688       for (i = 0; i < item->cb_count; i++)
24689       {
24690         if (item->cb[i].types & (CTX_MESSAGE))
24691         {
24692           event.state = ctx->events.modifier_state;
24693           item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
24694           if (event.stop_propagate)
24695             return;// event.stop_propagate;
24696         }
24697       }
24698   }
24699 }
24700 
ctx_scrolled(Ctx * ctx,float x,float y,CtxScrollDirection scroll_direction,uint32_t time)24701 int ctx_scrolled (Ctx *ctx, float x, float y, CtxScrollDirection scroll_direction, uint32_t time)
24702 {
24703   CtxList *hitlist = NULL;
24704   CtxList *l;
24705 
24706   int device_no = 0;
24707   ctx->events.pointer_x[device_no] = x;
24708   ctx->events.pointer_y[device_no] = y;
24709 
24710   CtxEvent *event = &ctx->events.drag_event[device_no];  /* XXX: might
24711                                        conflict with other code
24712                                        create a sibling member
24713                                        of drag_event?*/
24714   if (time == 0)
24715     time = ctx_ms (ctx);
24716 
24717   event->x         = event->start_x = event->prev_x = x;
24718   event->y         = event->start_y = event->prev_y = y;
24719   event->delta_x   = event->delta_y = 0;
24720   event->device_no = device_no;
24721   event->time      = time;
24722   event->stop_propagate = 0;
24723   event->scroll_direction = scroll_direction;
24724 
24725   _ctx_update_item (ctx, device_no, x, y, CTX_SCROLL, &hitlist);
24726 
24727   for (l = hitlist; l; l = l?l->next:NULL)
24728   {
24729     CtxItem *item = l->data;
24730 
24731     _ctx_emit_cb_item (ctx, item, event, CTX_SCROLL, x, y);
24732 
24733     if (event->stop_propagate)
24734       l = NULL;
24735   }
24736 
24737   //mrg_queue_draw (mrg, NULL); /* in case of style change, and more  */
24738   ctx_list_free (&hitlist);
24739   return 0;
24740 }
24741 
ctx_str_has_prefix(const char * string,const char * prefix)24742 static int ctx_str_has_prefix (const char *string, const char *prefix)
24743 {
24744   for (int i = 0; prefix[i]; i++)
24745   {
24746     if (!string[i]) return 0;
24747     if (string[i] != prefix[i]) return 0;
24748   }
24749   return 0;
24750 }
24751 
ctx_key_press(Ctx * ctx,unsigned int keyval,const char * string,uint32_t time)24752 int ctx_key_press (Ctx *ctx, unsigned int keyval,
24753                    const char *string, uint32_t time)
24754 {
24755   char event_type[128]="";
24756   float x, y; int b;
24757   sscanf (string, "%s %f %f %i", event_type, &x, &y, &b);
24758   if (!strcmp (event_type, "mouse-motion") ||
24759       !strcmp (event_type, "mouse-drag"))
24760     return ctx_pointer_motion (ctx, x, y, b, 0);
24761   else if (!strcmp (event_type, "mouse-press"))
24762     return ctx_pointer_press (ctx, x, y, b, 0);
24763   else if (!strcmp (event_type, "mouse-release"))
24764     return ctx_pointer_release (ctx, x, y, b, 0);
24765   //else if (!strcmp (event_type, "keydown"))
24766   //  return ctx_key_down (ctx, keyval, string + 8, time);
24767   //else if (!strcmp (event_type, "keyup"))
24768   //  return ctx_key_up (ctx, keyval, string + 6, time);
24769 
24770   CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_PRESS);
24771   CtxEvent event = {0,};
24772 
24773   if (time == 0)
24774     time = ctx_ms (ctx);
24775   if (item)
24776   {
24777     int i;
24778     event.ctx = ctx;
24779     event.type = CTX_KEY_PRESS;
24780     event.unicode = keyval;
24781     event.string = strdup(string);
24782     event.stop_propagate = 0;
24783     event.time = time;
24784 
24785     for (i = 0; i < item->cb_count; i++)
24786     {
24787       if (item->cb[i].types & (CTX_KEY_PRESS))
24788       {
24789         event.state = ctx->events.modifier_state;
24790         item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
24791         if (event.stop_propagate)
24792         {
24793           free ((void*)event.string);
24794           return event.stop_propagate;
24795         }
24796       }
24797     }
24798     free ((void*)event.string);
24799   }
24800   return 0;
24801 }
24802 
ctx_key_down(Ctx * ctx,unsigned int keyval,const char * string,uint32_t time)24803 int ctx_key_down (Ctx *ctx, unsigned int keyval,
24804                   const char *string, uint32_t time)
24805 {
24806   CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_DOWN);
24807   CtxEvent event = {0,};
24808 
24809   if (time == 0)
24810     time = ctx_ms (ctx);
24811   if (item)
24812   {
24813     int i;
24814     event.ctx     = ctx;
24815     event.type    = CTX_KEY_DOWN;
24816     event.unicode = keyval;
24817     event.string  = strdup(string);
24818     event.stop_propagate = 0;
24819     event.time    = time;
24820 
24821     for (i = 0; i < item->cb_count; i++)
24822     {
24823       if (item->cb[i].types & (CTX_KEY_DOWN))
24824       {
24825         event.state = ctx->events.modifier_state;
24826         item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
24827         if (event.stop_propagate)
24828         {
24829           free ((void*)event.string);
24830           return event.stop_propagate;
24831         }
24832       }
24833     }
24834     free ((void*)event.string);
24835   }
24836   return 0;
24837 }
24838 
ctx_key_up(Ctx * ctx,unsigned int keyval,const char * string,uint32_t time)24839 int ctx_key_up (Ctx *ctx, unsigned int keyval,
24840                 const char *string, uint32_t time)
24841 {
24842   CtxItem *item = _ctx_detect (ctx, 0, 0, CTX_KEY_UP);
24843   CtxEvent event = {0,};
24844 
24845   if (time == 0)
24846     time = ctx_ms (ctx);
24847   if (item)
24848   {
24849     int i;
24850     event.ctx = ctx;
24851     event.type = CTX_KEY_UP;
24852     event.unicode = keyval;
24853     event.string = strdup(string);
24854     event.stop_propagate = 0;
24855     event.time = time;
24856 
24857     for (i = 0; i < item->cb_count; i++)
24858     {
24859       if (item->cb[i].types & (CTX_KEY_UP))
24860       {
24861         event.state = ctx->events.modifier_state;
24862         item->cb[i].cb (&event, item->cb[i].data1, item->cb[i].data2);
24863         if (event.stop_propagate)
24864         {
24865           free ((void*)event.string);
24866           return event.stop_propagate;
24867         }
24868       }
24869     }
24870     free ((void*)event.string);
24871   }
24872   return 0;
24873 
24874   return 0;
24875 }
24876 
ctx_freeze(Ctx * ctx)24877 void ctx_freeze           (Ctx *ctx)
24878 {
24879   ctx->events.frozen ++;
24880 }
24881 
ctx_thaw(Ctx * ctx)24882 void ctx_thaw             (Ctx *ctx)
24883 {
24884   ctx->events.frozen --;
24885 }
ctx_events_frozen(Ctx * ctx)24886 int ctx_events_frozen (Ctx *ctx)
24887 {
24888   return ctx && ctx->events.frozen;
24889 }
ctx_events_clear_items(Ctx * ctx)24890 void ctx_events_clear_items (Ctx *ctx)
24891 {
24892   ctx_list_free (&ctx->events.items);
24893 }
ctx_events_width(Ctx * ctx)24894 int ctx_events_width (Ctx *ctx)
24895 {
24896   return ctx->events.width;
24897 }
ctx_events_height(Ctx * ctx)24898 int ctx_events_height (Ctx *ctx)
24899 {
24900   return ctx->events.height;
24901 }
24902 
ctx_pointer_x(Ctx * ctx)24903 float ctx_pointer_x (Ctx *ctx)
24904 {
24905   return ctx->events.pointer_x[0];
24906 }
24907 
ctx_pointer_y(Ctx * ctx)24908 float ctx_pointer_y (Ctx *ctx)
24909 {
24910   return ctx->events.pointer_y[0];
24911 }
24912 
ctx_pointer_is_down(Ctx * ctx,int no)24913 int ctx_pointer_is_down (Ctx *ctx, int no)
24914 {
24915   if (no < 0 || no > CTX_MAX_DEVICES) return 0;
24916   return ctx->events.pointer_down[no];
24917 }
24918 
_ctx_debug_overlays(Ctx * ctx)24919 void _ctx_debug_overlays (Ctx *ctx)
24920 {
24921   CtxList *a;
24922   ctx_save (ctx);
24923 
24924   ctx_line_width (ctx, 2);
24925   ctx_rgba (ctx, 0,0,0.8,0.5);
24926   for (a = ctx->events.items; a; a = a->next)
24927   {
24928     float current_x = ctx_pointer_x (ctx);
24929     float current_y = ctx_pointer_y (ctx);
24930     CtxItem *item = a->data;
24931     CtxMatrix matrix = item->inv_matrix;
24932 
24933     _ctx_matrix_apply_transform (&matrix, &current_x, &current_y);
24934 
24935     if (current_x >= item->x0 && current_x < item->x1 &&
24936         current_y >= item->y0 && current_y < item->y1)
24937     {
24938       ctx_matrix_invert (&matrix);
24939       ctx_set_matrix (ctx, &matrix);
24940       _mrg_restore_path (ctx, item->path);
24941       ctx_stroke (ctx);
24942     }
24943   }
24944   ctx_restore (ctx);
24945 }
24946 
ctx_set_render_threads(Ctx * ctx,int n_threads)24947 void ctx_set_render_threads   (Ctx *ctx, int n_threads)
24948 {
24949   // XXX
24950 }
ctx_get_render_threads(Ctx * ctx)24951 int ctx_get_render_threads   (Ctx *ctx)
24952 {
24953   return _ctx_max_threads;
24954 }
ctx_set_hash_cache(Ctx * ctx,int enable_hash_cache)24955 void ctx_set_hash_cache (Ctx *ctx, int enable_hash_cache)
24956 {
24957   _ctx_enable_hash_cache = enable_hash_cache;
24958 }
ctx_get_hash_cache(Ctx * ctx)24959 int ctx_get_hash_cache (Ctx *ctx)
24960 {
24961   return _ctx_enable_hash_cache;
24962 }
24963 
ctx_is_dirty(Ctx * ctx)24964 int ctx_is_dirty (Ctx *ctx)
24965 {
24966   return ctx->dirty;
24967 }
ctx_set_dirty(Ctx * ctx,int dirty)24968 void ctx_set_dirty (Ctx *ctx, int dirty)
24969 {
24970   ctx->dirty = dirty;
24971 }
24972 
24973 /*
24974  * centralized global API for managing file descriptors that
24975  * wake us up, this to remove sleeping and polling
24976  */
24977 
24978 #define CTX_MAX_LISTEN_FDS 128 // becomes max clients..
24979 
24980 static int _ctx_listen_fd[CTX_MAX_LISTEN_FDS];
24981 static int _ctx_listen_fds    = 0;
24982 static int _ctx_listen_max_fd = 0;
24983 
_ctx_add_listen_fd(int fd)24984 void _ctx_add_listen_fd (int fd)
24985 {
24986   _ctx_listen_fd[_ctx_listen_fds++]=fd;
24987   if (fd > _ctx_listen_max_fd)
24988     _ctx_listen_max_fd = fd;
24989 }
24990 
_ctx_remove_listen_fd(int fd)24991 void _ctx_remove_listen_fd (int fd)
24992 {
24993   for (int i = 0; i < _ctx_listen_fds; i++)
24994   {
24995     if (_ctx_listen_fd[i] == fd)
24996     {
24997       _ctx_listen_fd[i] = _ctx_listen_fd[_ctx_listen_fds-1];
24998       _ctx_listen_fds--;
24999       return;
25000     }
25001   }
25002 }
25003 
ctx_input_pending(Ctx * ctx,int timeout)25004 int ctx_input_pending (Ctx *ctx, int timeout)
25005 {
25006   struct timeval tv;
25007   fd_set fdset;
25008   FD_ZERO (&fdset);
25009   for (int i = 0; i < _ctx_listen_fds; i++)
25010   {
25011     FD_SET (_ctx_listen_fd[i], &fdset);
25012   }
25013   int input_fds[5];
25014   int n_fds;
25015   ctx_get_event_fds (ctx, input_fds, &n_fds);
25016   for (int i = 0; i < n_fds; i++)
25017   {
25018     FD_SET (input_fds[i], &fdset);
25019   }
25020 
25021   tv.tv_sec = 0;
25022   tv.tv_usec = timeout;
25023   tv.tv_sec = timeout / 1000000;
25024   tv.tv_usec = timeout % 1000000;
25025   int retval = select (_ctx_listen_max_fd + 1, &fdset, NULL, NULL, &tv);
25026   if (retval == -1)
25027   {
25028     perror ("select");
25029     return 0;
25030   }
25031   return retval;
25032 }
25033 
25034 void ctx_sdl_set_title (void *self, const char *new_title);
ctx_set_title(Ctx * ctx,const char * title)25035 void ctx_set_title (Ctx *ctx, const char *title)
25036 {
25037 #if CTX_SDL
25038      // XXX also check we're first/only client?
25039    if (ctx_renderer_is_sdl (ctx))
25040      ctx_sdl_set_title (ctx_get_renderer (ctx), title);
25041 #endif
25042 }
25043 
25044 #endif
25045 /* the parser comes in the end, nothing in ctx knows about the parser  */
25046 
25047 #if CTX_PARSER
25048 
25049 /* ctx parser, */
25050 
25051 #define CTX_ID_MAXLEN 64 // in use should not be more than 40!
25052                          // to offer headroom for multiplexing
25053 
25054 
25055 #define CTX_REPORT_COL_ROW 0
25056 
25057 struct
25058   _CtxParser
25059 {
25060   Ctx       *ctx;
25061   int        t_args; // total number of arguments seen for current command
25062   int        state;
25063 #if CTX_PARSER_FIXED_TEMP
25064   uint8_t    holding[CTX_PARSER_MAXLEN]; /*  */
25065 #else
25066   uint8_t   *holding;
25067 #endif
25068   int        hold_len;
25069   int        pos;
25070 
25071 #if CTX_REPORT_COL_ROW
25072   int        line; /*  for error reporting */
25073   int        col;  /*  for error reporting */
25074 #endif
25075   float      numbers[CTX_PARSER_MAX_ARGS+1];
25076   int        n_numbers;
25077   int        decimal;
25078   CtxCode    command;
25079   int        expected_args; /* low digits are literal higher values
25080                                carry special meaning */
25081   int        n_args;
25082   int        texture_done;
25083   uint8_t    texture_id[CTX_ID_MAXLEN]; // used in defineTexture only
25084   uint32_t   set_key_hash;
25085   float      pcx;
25086   float      pcy;
25087   int        color_components;
25088   int        color_stroke; // 0 is fill source  1 is stroke source
25089   CtxColorModel   color_model; // 1 gray 3 rgb 4 cmyk
25090   float      left_margin; // set by last user provided move_to
25091   int        width;       // <- maybe should be float
25092   int        height;
25093   float      cell_width;
25094   float      cell_height;
25095   int        cursor_x;    // <- leaking in from terminal
25096   int        cursor_y;
25097 
25098   int        translate_origin;
25099 
25100   CtxColorSpace   color_space_slot;
25101 
25102   void (*exit) (void *exit_data);
25103   void *exit_data;
25104   int   (*set_prop)(void *prop_data, uint32_t key, const char *data,  int len);
25105   int   (*get_prop)(void *prop_data, const char *key, char **data, int *len);
25106   void *prop_data;
25107   int   prev_byte;
25108 };
25109 
25110 void
ctx_parser_set_size(CtxParser * parser,int width,int height,float cell_width,float cell_height)25111 ctx_parser_set_size (CtxParser *parser,
25112                  int        width,
25113                  int        height,
25114                  float      cell_width,
25115                  float      cell_height)
25116 {
25117   if (cell_width > 0)
25118     parser->cell_width       = cell_width;
25119   if (cell_height > 0)
25120     parser->cell_height      = cell_height;
25121   if (width > 0)
25122     parser->width            = width;
25123   if (height > 0)
25124     parser->height           = height;
25125 }
25126 
25127 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)25128 ctx_parser_init (CtxParser *parser,
25129                  Ctx       *ctx,
25130                  int        width,
25131                  int        height,
25132                  float      cell_width,
25133                  float      cell_height,
25134                  int        cursor_x,
25135                  int        cursor_y,
25136   int   (*set_prop)(void *prop_data, uint32_t key, const char *data,  int len),
25137   int   (*get_prop)(void *prop_Data, const char *key, char **data, int *len),
25138                  void  *prop_data,
25139                  void (*exit) (void *exit_data),
25140                  void *exit_data
25141                 )
25142 {
25143   ctx_memset (parser, 0, sizeof (CtxParser) );
25144 #if CTX_REPORT_COL_ROW
25145   parser->line             = 1;
25146 #endif
25147   parser->ctx              = ctx;
25148   parser->cell_width       = cell_width;
25149   parser->cell_height      = cell_height;
25150   parser->cursor_x         = cursor_x;
25151   parser->cursor_y         = cursor_y;
25152   parser->width            = width;
25153   parser->height           = height;
25154   parser->exit             = exit;
25155   parser->exit_data        = exit_data;
25156   parser->color_model      = CTX_RGBA;
25157   parser->color_stroke     = 0;
25158   parser->color_components = 4;
25159   parser->command          = CTX_MOVE_TO;
25160   parser->set_prop         = set_prop;
25161   parser->get_prop         = get_prop;
25162   parser->prop_data        = prop_data;
25163   return parser;
25164 }
25165 
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)25166 CtxParser *ctx_parser_new (
25167   Ctx       *ctx,
25168   int        width,
25169   int        height,
25170   float      cell_width,
25171   float      cell_height,
25172   int        cursor_x,
25173   int        cursor_y,
25174   int   (*set_prop)(void *prop_data, uint32_t key, const char *data,  int len),
25175   int   (*get_prop)(void *prop_Data, const char *key, char **data, int *len),
25176   void  *prop_data,
25177   void (*exit) (void *exit_data),
25178   void *exit_data)
25179 {
25180   return ctx_parser_init ( (CtxParser *) ctx_calloc (sizeof (CtxParser), 1),
25181                            ctx,
25182                            width, height,
25183                            cell_width, cell_height,
25184                            cursor_x, cursor_y, set_prop, get_prop, prop_data,
25185                            exit, exit_data);
25186 }
25187 
ctx_parser_free(CtxParser * parser)25188 void ctx_parser_free (CtxParser *parser)
25189 {
25190 #if !CTX_PARSER_FIXED_TEMP
25191   if (parser->holding)
25192     free (parser->holding);
25193 #endif
25194   free (parser);
25195 }
25196 
25197 #define CTX_ARG_COLLECT_NUMBERS             50
25198 #define CTX_ARG_STRING_OR_NUMBER            100
25199 #define CTX_ARG_NUMBER_OF_COMPONENTS        200
25200 #define CTX_ARG_NUMBER_OF_COMPONENTS_PLUS_1 201
25201 
ctx_arguments_for_code(CtxCode code)25202 static int ctx_arguments_for_code (CtxCode code)
25203 {
25204   switch (code)
25205     {
25206       case CTX_SAVE:
25207       case CTX_START_GROUP:
25208       case CTX_END_GROUP:
25209       case CTX_IDENTITY:
25210       case CTX_CLOSE_PATH:
25211       case CTX_BEGIN_PATH:
25212       case CTX_RESET:
25213       case CTX_FLUSH:
25214       case CTX_RESTORE:
25215       case CTX_STROKE:
25216       case CTX_FILL:
25217       case CTX_NEW_PAGE:
25218       case CTX_CLIP:
25219       case CTX_EXIT:
25220         return 0;
25221       case CTX_GLOBAL_ALPHA:
25222       case CTX_COMPOSITING_MODE:
25223       case CTX_BLEND_MODE:
25224       case CTX_FONT_SIZE:
25225       case CTX_LINE_JOIN:
25226       case CTX_LINE_CAP:
25227       case CTX_LINE_WIDTH:
25228       case CTX_LINE_DASH_OFFSET:
25229       case CTX_IMAGE_SMOOTHING:
25230       case CTX_SHADOW_BLUR:
25231       case CTX_SHADOW_OFFSET_X:
25232       case CTX_SHADOW_OFFSET_Y:
25233       case CTX_FILL_RULE:
25234       case CTX_TEXT_ALIGN:
25235       case CTX_TEXT_BASELINE:
25236       case CTX_TEXT_DIRECTION:
25237       case CTX_MITER_LIMIT:
25238       case CTX_REL_VER_LINE_TO:
25239       case CTX_REL_HOR_LINE_TO:
25240       case CTX_HOR_LINE_TO:
25241       case CTX_VER_LINE_TO:
25242       case CTX_FONT:
25243       case CTX_ROTATE:
25244       case CTX_GLYPH:
25245         return 1;
25246       case CTX_TRANSLATE:
25247       case CTX_REL_SMOOTHQ_TO:
25248       case CTX_LINE_TO:
25249       case CTX_MOVE_TO:
25250       case CTX_SCALE:
25251       case CTX_REL_LINE_TO:
25252       case CTX_REL_MOVE_TO:
25253       case CTX_SMOOTHQ_TO:
25254         return 2;
25255       case CTX_LINEAR_GRADIENT:
25256       case CTX_REL_QUAD_TO:
25257       case CTX_QUAD_TO:
25258       case CTX_RECTANGLE:
25259       case CTX_FILL_RECT:
25260       case CTX_STROKE_RECT:
25261       case CTX_REL_SMOOTH_TO:
25262       case CTX_VIEW_BOX:
25263       case CTX_SMOOTH_TO:
25264         return 4;
25265       case CTX_ARC_TO:
25266       case CTX_REL_ARC_TO:
25267       case CTX_ROUND_RECTANGLE:
25268         return 5;
25269       case CTX_ARC:
25270       case CTX_CURVE_TO:
25271       case CTX_REL_CURVE_TO:
25272       case CTX_APPLY_TRANSFORM:
25273       case CTX_SOURCE_TRANSFORM:
25274       case CTX_RADIAL_GRADIENT:
25275         return 6;
25276       case CTX_STROKE_TEXT:
25277       case CTX_TEXT:
25278       case CTX_COLOR_SPACE:
25279       case CTX_DEFINE_GLYPH:
25280       case CTX_KERNING_PAIR:
25281       case CTX_TEXTURE:
25282       case CTX_DEFINE_TEXTURE:
25283         return CTX_ARG_STRING_OR_NUMBER;
25284       case CTX_LINE_DASH: /* append to current dashes for each argument encountered */
25285         return CTX_ARG_COLLECT_NUMBERS;
25286       //case CTX_SET_KEY:
25287       case CTX_COLOR:
25288       case CTX_SHADOW_COLOR:
25289         return CTX_ARG_NUMBER_OF_COMPONENTS;
25290       case CTX_GRADIENT_STOP:
25291         return CTX_ARG_NUMBER_OF_COMPONENTS_PLUS_1;
25292 
25293         default:
25294 #if 1
25295         case CTX_SET_RGBA_U8:
25296         case CTX_NOP:
25297         case CTX_NEW_EDGE:
25298         case CTX_EDGE:
25299         case CTX_EDGE_FLIPPED:
25300         case CTX_CONT:
25301         case CTX_DATA:
25302         case CTX_DATA_REV:
25303         case CTX_SET_PIXEL:
25304         case CTX_REL_LINE_TO_X4:
25305         case CTX_REL_LINE_TO_REL_CURVE_TO:
25306         case CTX_REL_CURVE_TO_REL_LINE_TO:
25307         case CTX_REL_CURVE_TO_REL_MOVE_TO:
25308         case CTX_REL_LINE_TO_X2:
25309         case CTX_MOVE_TO_REL_LINE_TO:
25310         case CTX_REL_LINE_TO_REL_MOVE_TO:
25311         case CTX_FILL_MOVE_TO:
25312         case CTX_REL_QUAD_TO_REL_QUAD_TO:
25313         case CTX_REL_QUAD_TO_S16:
25314         case CTX_STROKE_SOURCE:
25315 #endif
25316         return 0;
25317     }
25318 }
25319 
ctx_parser_set_command(CtxParser * parser,CtxCode code)25320 static int ctx_parser_set_command (CtxParser *parser, CtxCode code)
25321 {
25322   if (code < 150 && code >= 32)
25323   {
25324   parser->expected_args = ctx_arguments_for_code (code);
25325   parser->n_args = 0;
25326   parser->texture_done = 0;
25327   if (parser->expected_args >= CTX_ARG_NUMBER_OF_COMPONENTS)
25328     {
25329       parser->expected_args = (parser->expected_args % 100) + parser->color_components;
25330     }
25331   }
25332   return code;
25333 }
25334 
25335 static void ctx_parser_set_color_model (CtxParser *parser, CtxColorModel color_model, int stroke);
25336 
ctx_parser_resolve_command(CtxParser * parser,const uint8_t * str)25337 static int ctx_parser_resolve_command (CtxParser *parser, const uint8_t *str)
25338 {
25339   uint32_t ret = str[0]; /* if it is single char it already is the CtxCode */
25340 
25341   /* this is handled outside the hashing to make it possible to be case insensitive
25342    * with the rest.
25343    */
25344   if (str[0] == CTX_SET_KEY && str[1] && str[2] == 0)
25345   {
25346     switch (str[1])
25347     {
25348       case 'm': return ctx_parser_set_command (parser, CTX_COMPOSITING_MODE);
25349       case 'B': return ctx_parser_set_command (parser, CTX_BLEND_MODE);
25350       case 'l': return ctx_parser_set_command (parser, CTX_MITER_LIMIT);
25351       case 't': return ctx_parser_set_command (parser, CTX_TEXT_ALIGN);
25352       case 'b': return ctx_parser_set_command (parser, CTX_TEXT_BASELINE);
25353       case 'd': return ctx_parser_set_command (parser, CTX_TEXT_DIRECTION);
25354       case 'j': return ctx_parser_set_command (parser, CTX_LINE_JOIN);
25355       case 'c': return ctx_parser_set_command (parser, CTX_LINE_CAP);
25356       case 'w': return ctx_parser_set_command (parser, CTX_LINE_WIDTH);
25357       case 'D': return ctx_parser_set_command (parser, CTX_LINE_DASH_OFFSET);
25358       case 'S': return ctx_parser_set_command (parser, CTX_IMAGE_SMOOTHING);
25359       case 'C': return ctx_parser_set_command (parser, CTX_SHADOW_COLOR);
25360       case 's': return ctx_parser_set_command (parser, CTX_SHADOW_BLUR);
25361       case 'x': return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_X);
25362       case 'y': return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_Y);
25363       case 'a': return ctx_parser_set_command (parser, CTX_GLOBAL_ALPHA);
25364       case 'f': return ctx_parser_set_command (parser, CTX_FONT_SIZE);
25365       case 'r': return ctx_parser_set_command (parser, CTX_FILL_RULE);
25366     }
25367   }
25368 
25369   if (str[0] && str[1])
25370     {
25371       uint32_t str_hash;
25372       /* trim ctx_ and CTX_ prefix */
25373       if ( (str[0] == 'c' && str[1] == 't' && str[2] == 'x' && str[3] == '_') ||
25374            (str[0] == 'C' && str[1] == 'T' && str[2] == 'X' && str[3] == '_') )
25375         {
25376           str += 4;
25377         }
25378       if ( (str[0] == 's' && str[1] == 'e' && str[2] == 't' && str[3] == '_') )
25379         { str += 4; }
25380       str_hash = ctx_strhash ( (char *) str);
25381       switch (str_hash)
25382         {
25383           /* first a list of mappings to one_char hashes, handled in a
25384            * separate fast path switch without hashing
25385            */
25386           case CTX_arcTo:          ret = CTX_ARC_TO; break;
25387           case CTX_arc:            ret = CTX_ARC; break;
25388           case CTX_curveTo:        ret = CTX_CURVE_TO; break;
25389           case CTX_restore:        ret = CTX_RESTORE; break;
25390           case CTX_stroke:         ret = CTX_STROKE; break;
25391           case CTX_fill:           ret = CTX_FILL; break;
25392           case CTX_flush:          ret = CTX_FLUSH; break;
25393           case CTX_horLineTo:      ret = CTX_HOR_LINE_TO; break;
25394           case CTX_rotate:         ret = CTX_ROTATE; break;
25395           case CTX_color:          ret = CTX_COLOR; break;
25396           case CTX_lineTo:         ret = CTX_LINE_TO; break;
25397           case CTX_moveTo:         ret = CTX_MOVE_TO; break;
25398           case CTX_scale:          ret = CTX_SCALE; break;
25399           case CTX_newPage:        ret = CTX_NEW_PAGE; break;
25400           case CTX_quadTo:         ret = CTX_QUAD_TO; break;
25401           case CTX_viewBox:        ret = CTX_VIEW_BOX; break;
25402           case CTX_smooth_to:      ret = CTX_SMOOTH_TO; break;
25403           case CTX_smooth_quad_to: ret = CTX_SMOOTHQ_TO; break;
25404           case CTX_clear:          ret = CTX_COMPOSITE_CLEAR; break;
25405           case CTX_copy:           ret = CTX_COMPOSITE_COPY; break;
25406           case CTX_destinationOver:  ret = CTX_COMPOSITE_DESTINATION_OVER; break;
25407           case CTX_destinationIn:    ret = CTX_COMPOSITE_DESTINATION_IN; break;
25408           case CTX_destinationOut:   ret = CTX_COMPOSITE_DESTINATION_OUT; break;
25409           case CTX_sourceOver:       ret = CTX_COMPOSITE_SOURCE_OVER; break;
25410           case CTX_sourceAtop:       ret = CTX_COMPOSITE_SOURCE_ATOP; break;
25411           case CTX_destinationAtop:  ret = CTX_COMPOSITE_DESTINATION_ATOP; break;
25412           case CTX_sourceOut:        ret = CTX_COMPOSITE_SOURCE_OUT; break;
25413           case CTX_sourceIn:         ret = CTX_COMPOSITE_SOURCE_IN; break;
25414           case CTX_xor:              ret = CTX_COMPOSITE_XOR; break;
25415           case CTX_darken:           ret = CTX_BLEND_DARKEN; break;
25416           case CTX_lighten:          ret = CTX_BLEND_LIGHTEN; break;
25417           //case CTX_color:          ret = CTX_BLEND_COLOR; break;
25418           //
25419           //  XXX check that he special casing for color works
25420           //      it is the first collision and it is due to our own
25421           //      color, not w3c for now unique use of it
25422           //
25423           case CTX_hue:            ret = CTX_BLEND_HUE; break;
25424           case CTX_multiply:       ret = CTX_BLEND_MULTIPLY; break;
25425           case CTX_normal:         ret = CTX_BLEND_NORMAL;break;
25426           case CTX_screen:         ret = CTX_BLEND_SCREEN;break;
25427           case CTX_difference:     ret = CTX_BLEND_DIFFERENCE; break;
25428           case CTX_reset:          ret = CTX_RESET; break;
25429           case CTX_verLineTo:      ret = CTX_VER_LINE_TO; break;
25430           case CTX_exit:
25431           case CTX_done:           ret = CTX_EXIT; break;
25432           case CTX_closePath:      ret = CTX_CLOSE_PATH; break;
25433           case CTX_beginPath:
25434           case CTX_newPath:        ret = CTX_BEGIN_PATH; break;
25435           case CTX_relArcTo:       ret = CTX_REL_ARC_TO; break;
25436           case CTX_clip:           ret = CTX_CLIP; break;
25437           case CTX_relCurveTo:     ret = CTX_REL_CURVE_TO; break;
25438           case CTX_startGroup:     ret = CTX_START_GROUP; break;
25439           case CTX_endGroup:       ret = CTX_END_GROUP; break;
25440           case CTX_save:           ret = CTX_SAVE; break;
25441           case CTX_translate:      ret = CTX_TRANSLATE; break;
25442           case CTX_linearGradient: ret = CTX_LINEAR_GRADIENT; break;
25443           case CTX_relHorLineTo:   ret = CTX_REL_HOR_LINE_TO; break;
25444           case CTX_relLineTo:      ret = CTX_REL_LINE_TO; break;
25445           case CTX_relMoveTo:      ret = CTX_REL_MOVE_TO; break;
25446           case CTX_font:           ret = CTX_FONT; break;
25447           case CTX_radialGradient:ret = CTX_RADIAL_GRADIENT; break;
25448           case CTX_gradientAddStop:
25449           case CTX_addStop:        ret = CTX_GRADIENT_STOP; break;
25450           case CTX_relQuadTo:      ret = CTX_REL_QUAD_TO; break;
25451           case CTX_rectangle:
25452           case CTX_rect:           ret = CTX_RECTANGLE; break;
25453           case CTX_roundRectangle: ret = CTX_ROUND_RECTANGLE; break;
25454           case CTX_relSmoothTo:    ret = CTX_REL_SMOOTH_TO; break;
25455           case CTX_relSmoothqTo:   ret = CTX_REL_SMOOTHQ_TO; break;
25456           case CTX_strokeText:     ret = CTX_STROKE_TEXT; break;
25457           case CTX_strokeRect:     ret = CTX_STROKE_RECT; break;
25458           case CTX_fillRect:       ret = CTX_FILL_RECT; break;
25459           case CTX_relVerLineTo:   ret = CTX_REL_VER_LINE_TO; break;
25460           case CTX_text:           ret = CTX_TEXT; break;
25461           case CTX_identity:       ret = CTX_IDENTITY; break;
25462           case CTX_transform:      ret = CTX_APPLY_TRANSFORM; break;
25463           case CTX_sourceTransform: ret = CTX_SOURCE_TRANSFORM; break;
25464           case CTX_texture:        ret = CTX_TEXTURE; break;
25465           case CTX_defineTexture:  ret = CTX_DEFINE_TEXTURE; break;
25466 #if 0
25467           case CTX_rgbSpace:
25468             return ctx_parser_set_command (parser, CTX_SET_RGB_SPACE);
25469           case CTX_cmykSpace:
25470             return ctx_parser_set_command (parser, CTX_SET_CMYK_SPACE);
25471           case CTX_drgbSpace:
25472             return ctx_parser_set_command (parser, CTX_SET_DRGB_SPACE);
25473 #endif
25474           case CTX_defineGlyph:
25475             return ctx_parser_set_command (parser, CTX_DEFINE_GLYPH);
25476           case CTX_kerningPair:
25477             return ctx_parser_set_command (parser, CTX_KERNING_PAIR);
25478 
25479           case CTX_colorSpace:
25480             return ctx_parser_set_command (parser, CTX_COLOR_SPACE);
25481           case CTX_fillRule:
25482             return ctx_parser_set_command (parser, CTX_FILL_RULE);
25483           case CTX_fontSize:
25484           case CTX_setFontSize:
25485             return ctx_parser_set_command (parser, CTX_FONT_SIZE);
25486           case CTX_compositingMode:
25487             return ctx_parser_set_command (parser, CTX_COMPOSITING_MODE);
25488 
25489           case CTX_blend:
25490           case CTX_blending:
25491           case CTX_blendMode:
25492             return ctx_parser_set_command (parser, CTX_BLEND_MODE);
25493 
25494           case CTX_miterLimit:
25495             return ctx_parser_set_command (parser, CTX_MITER_LIMIT);
25496           case CTX_textAlign:
25497             return ctx_parser_set_command (parser, CTX_TEXT_ALIGN);
25498           case CTX_textBaseline:
25499             return ctx_parser_set_command (parser, CTX_TEXT_BASELINE);
25500           case CTX_textDirection:
25501             return ctx_parser_set_command (parser, CTX_TEXT_DIRECTION);
25502           case CTX_join:
25503           case CTX_lineJoin:
25504           case CTX_setLineJoin:
25505             return ctx_parser_set_command (parser, CTX_LINE_JOIN);
25506           case CTX_glyph:
25507             return ctx_parser_set_command (parser, CTX_GLYPH);
25508           case CTX_cap:
25509           case CTX_lineCap:
25510           case CTX_setLineCap:
25511             return ctx_parser_set_command (parser, CTX_LINE_CAP);
25512           case CTX_lineDash:
25513             return ctx_parser_set_command (parser, CTX_LINE_DASH);
25514           case CTX_lineWidth:
25515           case CTX_setLineWidth:
25516             return ctx_parser_set_command (parser, CTX_LINE_WIDTH);
25517           case CTX_lineDashOffset:
25518             return ctx_parser_set_command (parser, CTX_LINE_DASH_OFFSET);
25519           case CTX_imageSmoothing:
25520             return ctx_parser_set_command (parser, CTX_IMAGE_SMOOTHING);
25521           case CTX_shadowColor:
25522             return ctx_parser_set_command (parser, CTX_SHADOW_COLOR);
25523           case CTX_shadowBlur:
25524             return ctx_parser_set_command (parser, CTX_SHADOW_BLUR);
25525           case CTX_shadowOffsetX:
25526             return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_X);
25527           case CTX_shadowOffsetY:
25528             return ctx_parser_set_command (parser, CTX_SHADOW_OFFSET_Y);
25529           case CTX_globalAlpha:
25530             return ctx_parser_set_command (parser, CTX_GLOBAL_ALPHA);
25531 
25532           case CTX_strokeSource:
25533             return ctx_parser_set_command (parser, CTX_STROKE_SOURCE);
25534 
25535           /* strings are handled directly here,
25536            * instead of in the one-char handler, using return instead of break
25537            */
25538           case CTX_gray:
25539             ctx_parser_set_color_model (parser, CTX_GRAY, 0);
25540             return ctx_parser_set_command (parser, CTX_COLOR);
25541           case CTX_graya:
25542             ctx_parser_set_color_model (parser, CTX_GRAYA, 0);
25543             return ctx_parser_set_command (parser, CTX_COLOR);
25544           case CTX_rgb:
25545             ctx_parser_set_color_model (parser, CTX_RGB, 0);
25546             return ctx_parser_set_command (parser, CTX_COLOR);
25547           case CTX_drgb:
25548             ctx_parser_set_color_model (parser, CTX_DRGB, 0);
25549             return ctx_parser_set_command (parser, CTX_COLOR);
25550           case CTX_rgba:
25551             ctx_parser_set_color_model (parser, CTX_RGBA, 0);
25552             return ctx_parser_set_command (parser, CTX_COLOR);
25553           case CTX_drgba:
25554             ctx_parser_set_color_model (parser, CTX_DRGBA, 0);
25555             return ctx_parser_set_command (parser, CTX_COLOR);
25556           case CTX_cmyk:
25557             ctx_parser_set_color_model (parser, CTX_CMYK, 0);
25558             return ctx_parser_set_command (parser, CTX_COLOR);
25559           case CTX_cmyka:
25560             ctx_parser_set_color_model (parser, CTX_CMYKA, 0);
25561             return ctx_parser_set_command (parser, CTX_COLOR);
25562           case CTX_lab:
25563             ctx_parser_set_color_model (parser, CTX_LAB, 0);
25564             return ctx_parser_set_command (parser, CTX_COLOR);
25565           case CTX_laba:
25566             ctx_parser_set_color_model (parser, CTX_LABA, 0);
25567             return ctx_parser_set_command (parser, CTX_COLOR);
25568           case CTX_lch:
25569             ctx_parser_set_color_model (parser, CTX_LCH, 0);
25570             return ctx_parser_set_command (parser, CTX_COLOR);
25571           case CTX_lcha:
25572             ctx_parser_set_color_model (parser, CTX_LCHA, 0);
25573             return ctx_parser_set_command (parser, CTX_COLOR);
25574 
25575           /* and a full repeat of the above, with S for Stroke suffix */
25576           case CTX_grayS:
25577             ctx_parser_set_color_model (parser, CTX_GRAY, 1);
25578             return ctx_parser_set_command (parser, CTX_COLOR);
25579           case CTX_grayaS:
25580             ctx_parser_set_color_model (parser, CTX_GRAYA, 1);
25581             return ctx_parser_set_command (parser, CTX_COLOR);
25582           case CTX_rgbS:
25583             ctx_parser_set_color_model (parser, CTX_RGB, 1);
25584             return ctx_parser_set_command (parser, CTX_COLOR);
25585           case CTX_drgbS:
25586             ctx_parser_set_color_model (parser, CTX_DRGB, 1);
25587             return ctx_parser_set_command (parser, CTX_COLOR);
25588           case CTX_rgbaS:
25589             ctx_parser_set_color_model (parser, CTX_RGBA, 1);
25590             return ctx_parser_set_command (parser, CTX_COLOR);
25591           case CTX_drgbaS:
25592             ctx_parser_set_color_model (parser, CTX_DRGBA, 1);
25593             return ctx_parser_set_command (parser, CTX_COLOR);
25594           case CTX_cmykS:
25595             ctx_parser_set_color_model (parser, CTX_CMYK, 1);
25596             return ctx_parser_set_command (parser, CTX_COLOR);
25597           case CTX_cmykaS:
25598             ctx_parser_set_color_model (parser, CTX_CMYKA, 1);
25599             return ctx_parser_set_command (parser, CTX_COLOR);
25600           case CTX_labS:
25601             ctx_parser_set_color_model (parser, CTX_LAB, 1);
25602             return ctx_parser_set_command (parser, CTX_COLOR);
25603           case CTX_labaS:
25604             ctx_parser_set_color_model (parser, CTX_LABA, 1);
25605             return ctx_parser_set_command (parser, CTX_COLOR);
25606           case CTX_lchS:
25607             ctx_parser_set_color_model (parser, CTX_LCH, 1);
25608             return ctx_parser_set_command (parser, CTX_COLOR);
25609           case CTX_lchaS:
25610             ctx_parser_set_color_model (parser, CTX_LCHA, 1);
25611             return ctx_parser_set_command (parser, CTX_COLOR);
25612 
25613           /* words that correspond to low integer constants
25614           */
25615           case CTX_nonzero:     return CTX_FILL_RULE_WINDING;
25616           case CTX_non_zero:    return CTX_FILL_RULE_WINDING;
25617           case CTX_winding:     return CTX_FILL_RULE_WINDING;
25618           case CTX_evenOdd:
25619           case CTX_even_odd:    return CTX_FILL_RULE_EVEN_ODD;
25620           case CTX_bevel:       return CTX_JOIN_BEVEL;
25621           case CTX_round:       return CTX_JOIN_ROUND;
25622           case CTX_miter:       return CTX_JOIN_MITER;
25623           case CTX_none:        return CTX_CAP_NONE;
25624           case CTX_square:      return CTX_CAP_SQUARE;
25625           case CTX_start:       return CTX_TEXT_ALIGN_START;
25626           case CTX_end:         return CTX_TEXT_ALIGN_END;
25627           case CTX_left:        return CTX_TEXT_ALIGN_LEFT;
25628           case CTX_right:       return CTX_TEXT_ALIGN_RIGHT;
25629           case CTX_center:      return CTX_TEXT_ALIGN_CENTER;
25630           case CTX_top:         return CTX_TEXT_BASELINE_TOP;
25631           case CTX_bottom :     return CTX_TEXT_BASELINE_BOTTOM;
25632           case CTX_middle:      return CTX_TEXT_BASELINE_MIDDLE;
25633           case CTX_alphabetic:  return CTX_TEXT_BASELINE_ALPHABETIC;
25634           case CTX_hanging:     return CTX_TEXT_BASELINE_HANGING;
25635           case CTX_ideographic: return CTX_TEXT_BASELINE_IDEOGRAPHIC;
25636 
25637           case CTX_userRGB:     return CTX_COLOR_SPACE_USER_RGB;
25638           case CTX_deviceRGB:   return CTX_COLOR_SPACE_DEVICE_RGB;
25639           case CTX_userCMYK:    return CTX_COLOR_SPACE_USER_CMYK;
25640           case CTX_deviceCMYK:  return CTX_COLOR_SPACE_DEVICE_CMYK;
25641 #undef STR
25642 #undef LOWER
25643           default:
25644             ret = str_hash;
25645         }
25646     }
25647   if (ret == CTX_CLOSE_PATH2)
25648    {
25649      ret = CTX_CLOSE_PATH;
25650    }
25651 
25652   return ctx_parser_set_command (parser, (CtxCode) ret);
25653 }
25654 
25655 enum
25656 {
25657   CTX_PARSER_NEUTRAL = 0,
25658   CTX_PARSER_NUMBER,
25659   CTX_PARSER_NEGATIVE_NUMBER,
25660   CTX_PARSER_WORD,
25661   CTX_PARSER_COMMENT,
25662   CTX_PARSER_STRING_APOS,
25663   CTX_PARSER_STRING_QUOT,
25664   CTX_PARSER_STRING_APOS_ESCAPED,
25665   CTX_PARSER_STRING_QUOT_ESCAPED,
25666   CTX_PARSER_STRING_A85,
25667   CTX_PARSER_STRING_YENC,
25668 } CTX_STATE;
25669 
ctx_parser_set_color_model(CtxParser * parser,CtxColorModel color_model,int stroke)25670 static void ctx_parser_set_color_model (CtxParser *parser, CtxColorModel color_model, int stroke)
25671 {
25672   parser->color_model      = color_model;
25673   parser->color_stroke     = stroke;
25674   parser->color_components = ctx_color_model_get_components (color_model);
25675 }
25676 
ctx_parser_get_color_rgba(CtxParser * parser,int offset,float * red,float * green,float * blue,float * alpha)25677 static void ctx_parser_get_color_rgba (CtxParser *parser, int offset, float *red, float *green, float *blue, float *alpha)
25678 {
25679   /* XXX - this function is to be deprecated */
25680   *alpha = 1.0;
25681   switch (parser->color_model)
25682     {
25683       case CTX_GRAYA:
25684         *alpha = parser->numbers[offset + 1];
25685         /* FALLTHROUGH */
25686       case CTX_GRAY:
25687         *red = *green = *blue = parser->numbers[offset + 0];
25688         break;
25689       default:
25690       case CTX_LABA: // NYI - needs RGB profile
25691       case CTX_LCHA: // NYI - needs RGB profile
25692       case CTX_RGBA:
25693         *alpha = parser->numbers[offset + 3];
25694         /* FALLTHROUGH */
25695       case CTX_LAB: // NYI
25696       case CTX_LCH: // NYI
25697       case CTX_RGB:
25698         *red = parser->numbers[offset + 0];
25699         *green = parser->numbers[offset + 1];
25700         *blue = parser->numbers[offset + 2];
25701         break;
25702       case CTX_CMYKA:
25703         *alpha = parser->numbers[offset + 4];
25704         /* FALLTHROUGH */
25705       case CTX_CMYK:
25706         /* should use profile instead  */
25707         *red = (1.0-parser->numbers[offset + 0]) *
25708                (1.0 - parser->numbers[offset + 3]);
25709         *green = (1.0-parser->numbers[offset + 1]) *
25710                  (1.0 - parser->numbers[offset + 3]);
25711         *blue = (1.0-parser->numbers[offset + 2]) *
25712                 (1.0 - parser->numbers[offset + 3]);
25713         break;
25714     }
25715 }
25716 
ctx_parser_dispatch_command(CtxParser * parser)25717 static void ctx_parser_dispatch_command (CtxParser *parser)
25718 {
25719   CtxCode cmd = parser->command;
25720   Ctx *ctx = parser->ctx;
25721 
25722   if (parser->expected_args != CTX_ARG_STRING_OR_NUMBER &&
25723       parser->expected_args != CTX_ARG_COLLECT_NUMBERS &&
25724       parser->expected_args != parser->n_numbers)
25725     {
25726 #if CTX_REPORT_COL_ROW
25727          fprintf (stderr, "ctx:%i:%i %c got %i instead of %i args\n",
25728                parser->line, parser->col,
25729                cmd, parser->n_numbers, parser->expected_args);
25730 #endif
25731       //return;
25732     }
25733 
25734 #define arg(a)  (parser->numbers[a])
25735   parser->command = CTX_NOP;
25736   //parser->n_args = 0;
25737   switch (cmd)
25738     {
25739       default:
25740         break; // to silence warnings about missing ones
25741       case CTX_PRESERVE:
25742         ctx_preserve (ctx);
25743         break;
25744       case CTX_FILL:
25745         ctx_fill (ctx);
25746         break;
25747       case CTX_SAVE:
25748         ctx_save (ctx);
25749         break;
25750       case CTX_START_GROUP:
25751         ctx_start_group (ctx);
25752         break;
25753       case CTX_END_GROUP:
25754         ctx_end_group (ctx);
25755         break;
25756       case CTX_STROKE:
25757         ctx_stroke (ctx);
25758         break;
25759       case CTX_STROKE_SOURCE:
25760         ctx_stroke_source (ctx);
25761         break;
25762       case CTX_RESTORE:
25763         ctx_restore (ctx);
25764         break;
25765 #if CTX_ENABLE_CM
25766       case CTX_COLOR_SPACE:
25767         if (parser->n_numbers == 1)
25768         {
25769           parser->color_space_slot = (CtxColorSpace) arg(0);
25770           parser->command = CTX_COLOR_SPACE; // did this work without?
25771         }
25772         else
25773         {
25774           ctx_colorspace (ctx, (CtxColorSpace)parser->color_space_slot,
25775                                parser->holding, parser->pos);
25776         }
25777         break;
25778 #endif
25779       case CTX_KERNING_PAIR:
25780         switch (parser->n_args)
25781         {
25782           case 0:
25783             parser->numbers[0] = ctx_utf8_to_unichar ((char*)parser->holding);
25784             break;
25785           case 1:
25786             parser->numbers[1] = ctx_utf8_to_unichar ((char*)parser->holding);
25787             break;
25788           case 2:
25789             parser->numbers[2] = strtod ((char*)parser->holding, NULL);
25790             {
25791               CtxEntry e = {CTX_KERNING_PAIR, };
25792               e.data.u16[0] = parser->numbers[0];
25793               e.data.u16[1] = parser->numbers[1];
25794               e.data.s32[1] = parser->numbers[2] * 256;
25795               ctx_process (ctx, &e);
25796             }
25797             break;
25798         }
25799         parser->command = CTX_KERNING_PAIR;
25800         parser->n_args ++; // make this more generic?
25801         break;
25802       case CTX_TEXTURE:
25803         if (parser->texture_done)
25804         {
25805         }
25806         else
25807         if (parser->n_numbers == 2)
25808         {
25809           const char *eid = (char*)parser->holding;
25810           float x0 = arg(0);
25811           float x1 = arg(1);
25812           ctx_texture (ctx, eid, x0, x1);
25813           parser->texture_done = 1;
25814         }
25815         parser->command = CTX_TEXTURE;
25816         //parser->n_args++;
25817         break;
25818       case CTX_DEFINE_TEXTURE:
25819         if (parser->texture_done)
25820         {
25821           if (parser->texture_done++ == 1)
25822           {
25823              const char *eid = (char*)parser->texture_id;
25824              int width  = arg(0);
25825              int height = arg(1);
25826              CtxPixelFormat format = (CtxPixelFormat)arg(2);
25827              int stride = ctx_pixel_format_get_stride (format, width);
25828              int data_len = stride * height;
25829              if (format == CTX_FORMAT_YUV420)
25830                  data_len = height * width + 2*(height/2) * (width/2);
25831 
25832 
25833              if (parser->pos != data_len)
25834              {
25835              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,
25836                                parser->pos,
25837                                stride * height,
25838                                parser->holding[0],
25839                                parser->holding[1],
25840                                parser->holding[2],
25841                                parser->holding[3]
25842                                );
25843              }
25844              else
25845              ctx_define_texture (ctx, eid, width, height, stride, format, parser->holding, NULL);
25846           }
25847         }
25848         else
25849         {
25850         switch (parser->n_numbers)
25851         {
25852           case 0:
25853              strncpy ((char*)parser->texture_id, (char*)parser->holding, sizeof(parser->texture_id));
25854              parser->texture_id[sizeof(parser->texture_id)-1]=0;
25855              break;
25856           case 1:
25857           case 2:
25858              break;
25859           case 3:
25860              parser->texture_done = 1;
25861              break;
25862           default:
25863              fprintf (stderr, "!!%i\n", parser->n_numbers);
25864              break;
25865         }
25866         }
25867         parser->command = CTX_DEFINE_TEXTURE;
25868         break;
25869 
25870 
25871       case CTX_DEFINE_GLYPH:
25872         /* XXX : reuse n_args logic - to enforce order */
25873         if (parser->n_numbers == 1)
25874         {
25875           CtxEntry e = {CTX_DEFINE_GLYPH, };
25876           e.data.u32[0] = parser->color_space_slot;
25877           e.data.u32[1] = arg(0) * 256;
25878           ctx_process (ctx, &e);
25879         }
25880         else
25881         {
25882           int unichar = ctx_utf8_to_unichar ((char*)parser->holding);
25883           parser->color_space_slot = (CtxColorSpace)unichar;
25884         }
25885         parser->command = CTX_DEFINE_GLYPH;
25886         break;
25887 
25888       case CTX_COLOR:
25889         {
25890           switch (parser->color_model)
25891             {
25892               case CTX_GRAY:
25893               case CTX_GRAYA:
25894               case CTX_RGB:
25895               case CTX_RGBA:
25896               case CTX_DRGB:
25897               case CTX_DRGBA:
25898                 ctx_color_raw (ctx, parser->color_model, parser->numbers, parser->color_stroke);
25899                 break;
25900 #if CTX_ENABLE_CMYK
25901               case CTX_CMYK:
25902               case CTX_CMYKA:
25903                 ctx_color_raw (ctx, parser->color_model, parser->numbers, parser->color_stroke);
25904                 break;
25905 #else
25906               /* when there is no cmyk support at all in rasterizer
25907                * do a naive mapping to RGB on input.
25908                */
25909               case CTX_CMYK:
25910               case CTX_CMYKA:
25911               case CTX_DCMYKA:
25912                 {
25913                   float rgba[4] = {1,1,1,1.0f};
25914 
25915                   ctx_cmyk_to_rgb (arg(0), arg(1), arg(2), arg(3), &rgba[0], &rgba[1], &rgba[2]);
25916                   if (parser->color_model == CTX_CMYKA)
25917                     { rgba[3] = arg(4); }
25918                   ctx_color_raw (ctx, CTX_RGBA, rgba, parser->color_stroke);
25919                 }
25920                 break;
25921 #endif
25922               case CTX_LAB:
25923               case CTX_LCH:
25924               default:
25925                 break;
25926             }
25927         }
25928         break;
25929       case CTX_LINE_DASH:
25930         if (parser->n_numbers)
25931         {
25932           ctx_line_dash (ctx, parser->numbers, parser->n_numbers);
25933         }
25934         else
25935         {
25936           ctx_line_dash (ctx, NULL, 0);
25937         }
25938         //append_dash_val (ctx, arg(0));
25939         break;
25940       case CTX_ARC_TO:
25941         ctx_arc_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4));
25942         break;
25943       case CTX_REL_ARC_TO:
25944         ctx_rel_arc_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4) );
25945         break;
25946       case CTX_REL_SMOOTH_TO:
25947         {
25948           float cx = parser->pcx;
25949           float cy = parser->pcy;
25950           float ax = 2 * ctx_x (ctx) - cx;
25951           float ay = 2 * ctx_y (ctx) - cy;
25952           ctx_curve_to (ctx, ax, ay, arg(0) +  cx, arg(1) + cy,
25953                         arg(2) + cx, arg(3) + cy);
25954           parser->pcx = arg(0) + cx;
25955           parser->pcy = arg(1) + cy;
25956         }
25957         break;
25958       case CTX_SMOOTH_TO:
25959         {
25960           float ax = 2 * ctx_x (ctx) - parser->pcx;
25961           float ay = 2 * ctx_y (ctx) - parser->pcy;
25962           ctx_curve_to (ctx, ax, ay, arg(0), arg(1),
25963                         arg(2), arg(3) );
25964           parser->pcx = arg(0);
25965           parser->pcx = arg(1);
25966         }
25967         break;
25968       case CTX_SMOOTHQ_TO:
25969         ctx_quad_to (ctx, parser->pcx, parser->pcy, arg(0), arg(1) );
25970         break;
25971       case CTX_REL_SMOOTHQ_TO:
25972         {
25973           float cx = parser->pcx;
25974           float cy = parser->pcy;
25975           parser->pcx = 2 * ctx_x (ctx) - parser->pcx;
25976           parser->pcy = 2 * ctx_y (ctx) - parser->pcy;
25977           ctx_quad_to (ctx, parser->pcx, parser->pcy, arg(0) +  cx, arg(1) + cy);
25978         }
25979         break;
25980       case CTX_VER_LINE_TO:
25981         ctx_line_to (ctx, ctx_x (ctx), arg(0) );
25982         parser->command = CTX_VER_LINE_TO;
25983         parser->pcx = ctx_x (ctx);
25984         parser->pcy = ctx_y (ctx);
25985         break;
25986       case CTX_HOR_LINE_TO:
25987         ctx_line_to (ctx, arg(0), ctx_y (ctx) );
25988         parser->command = CTX_HOR_LINE_TO;
25989         parser->pcx = ctx_x (ctx);
25990         parser->pcy = ctx_y (ctx);
25991         break;
25992       case CTX_REL_HOR_LINE_TO:
25993         ctx_rel_line_to (ctx, arg(0), 0.0f);
25994         parser->command = CTX_REL_HOR_LINE_TO;
25995         parser->pcx = ctx_x (ctx);
25996         parser->pcy = ctx_y (ctx);
25997         break;
25998       case CTX_REL_VER_LINE_TO:
25999         ctx_rel_line_to (ctx, 0.0f, arg(0) );
26000         parser->command = CTX_REL_VER_LINE_TO;
26001         parser->pcx = ctx_x (ctx);
26002         parser->pcy = ctx_y (ctx);
26003         break;
26004       case CTX_ARC:
26005         ctx_arc (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
26006         break;
26007       case CTX_APPLY_TRANSFORM:
26008         ctx_apply_transform (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
26009         break;
26010       case CTX_SOURCE_TRANSFORM:
26011         ctx_source_transform (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
26012         break;
26013       case CTX_CURVE_TO:
26014         ctx_curve_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
26015         parser->pcx = arg(2);
26016         parser->pcy = arg(3);
26017         parser->command = CTX_CURVE_TO;
26018         break;
26019       case CTX_REL_CURVE_TO:
26020         parser->pcx = arg(2) + ctx_x (ctx);
26021         parser->pcy = arg(3) + ctx_y (ctx);
26022         ctx_rel_curve_to (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
26023         parser->command = CTX_REL_CURVE_TO;
26024         break;
26025       case CTX_LINE_TO:
26026         ctx_line_to (ctx, arg(0), arg(1) );
26027         parser->command = CTX_LINE_TO;
26028         parser->pcx = arg(0);
26029         parser->pcy = arg(1);
26030         break;
26031       case CTX_MOVE_TO:
26032         ctx_move_to (ctx, arg(0), arg(1) );
26033         parser->command = CTX_LINE_TO;
26034         parser->pcx = arg(0);
26035         parser->pcy = arg(1);
26036         parser->left_margin = parser->pcx;
26037         break;
26038       case CTX_FONT_SIZE:
26039         ctx_font_size (ctx, arg(0) );
26040         break;
26041       case CTX_MITER_LIMIT:
26042         ctx_miter_limit (ctx, arg(0) );
26043         break;
26044       case CTX_SCALE:
26045         ctx_scale (ctx, arg(0), arg(1) );
26046         break;
26047       case CTX_QUAD_TO:
26048         parser->pcx = arg(0);
26049         parser->pcy = arg(1);
26050         ctx_quad_to (ctx, arg(0), arg(1), arg(2), arg(3) );
26051         parser->command = CTX_QUAD_TO;
26052         break;
26053       case CTX_REL_QUAD_TO:
26054         parser->pcx = arg(0) + ctx_x (ctx);
26055         parser->pcy = arg(1) + ctx_y (ctx);
26056         ctx_rel_quad_to (ctx, arg(0), arg(1), arg(2), arg(3) );
26057         parser->command = CTX_REL_QUAD_TO;
26058         break;
26059       case CTX_CLIP:
26060         ctx_clip (ctx);
26061         break;
26062       case CTX_TRANSLATE:
26063         ctx_translate (ctx, arg(0), arg(1) );
26064         break;
26065       case CTX_ROTATE:
26066         ctx_rotate (ctx, arg(0) );
26067         break;
26068       case CTX_FONT:
26069         ctx_font (ctx, (char *) parser->holding);
26070         break;
26071 
26072       case CTX_STROKE_TEXT:
26073       case CTX_TEXT:
26074         if (parser->n_numbers == 1)
26075           { ctx_rel_move_to (ctx, -parser->numbers[0], 0.0); }  //  XXX : scale by font(size)
26076         else
26077           {
26078             for (char *c = (char *) parser->holding; c; )
26079               {
26080                 char *next_nl = ctx_strchr (c, '\n');
26081                 if (next_nl)
26082                   { *next_nl = 0; }
26083                 /* do our own layouting on a per-word basis?, to get justified
26084                  * margins? then we'd want explict margins rather than the
26085                  * implicit ones from move_to's .. making move_to work within
26086                  * margins.
26087                  */
26088                 if (cmd == CTX_STROKE_TEXT)
26089                   { ctx_text_stroke (ctx, c); }
26090                 else
26091                   { ctx_text (ctx, c); }
26092                 if (next_nl)
26093                   {
26094                     *next_nl = '\n'; // swap it newline back in
26095                     ctx_move_to (ctx, parser->left_margin, ctx_y (ctx) +
26096                                  ctx_get_font_size (ctx) );
26097                     c = next_nl + 1;
26098                     if (c[0] == 0)
26099                       { c = NULL; }
26100                   }
26101                 else
26102                   {
26103                     c = NULL;
26104                   }
26105               }
26106           }
26107         if (cmd == CTX_STROKE_TEXT)
26108           { parser->command = CTX_STROKE_TEXT; }
26109         else
26110           { parser->command = CTX_TEXT; }
26111         break;
26112       case CTX_REL_LINE_TO:
26113         ctx_rel_line_to (ctx, arg(0), arg(1) );
26114         parser->pcx += arg(0);
26115         parser->pcy += arg(1);
26116         break;
26117       case CTX_REL_MOVE_TO:
26118         ctx_rel_move_to (ctx, arg(0), arg(1) );
26119         parser->pcx += arg(0);
26120         parser->pcy += arg(1);
26121         parser->left_margin = ctx_x (ctx);
26122         break;
26123       case CTX_LINE_WIDTH:
26124         ctx_line_width (ctx, arg(0));
26125         break;
26126       case CTX_LINE_DASH_OFFSET:
26127         ctx_line_dash_offset (ctx, arg(0));
26128         break;
26129       case CTX_IMAGE_SMOOTHING:
26130         ctx_image_smoothing (ctx, arg(0));
26131         break;
26132       case CTX_SHADOW_COLOR:
26133         ctx_shadow_rgba (ctx, arg(0), arg(1), arg(2), arg(3));
26134         break;
26135       case CTX_SHADOW_BLUR:
26136         ctx_shadow_blur (ctx, arg(0) );
26137         break;
26138       case CTX_SHADOW_OFFSET_X:
26139         ctx_shadow_offset_x (ctx, arg(0) );
26140         break;
26141       case CTX_SHADOW_OFFSET_Y:
26142         ctx_shadow_offset_y (ctx, arg(0) );
26143         break;
26144       case CTX_LINE_JOIN:
26145         ctx_line_join (ctx, (CtxLineJoin) arg(0) );
26146         break;
26147       case CTX_LINE_CAP:
26148         ctx_line_cap (ctx, (CtxLineCap) arg(0) );
26149         break;
26150       case CTX_COMPOSITING_MODE:
26151         ctx_compositing_mode (ctx, (CtxCompositingMode) arg(0) );
26152         break;
26153       case CTX_BLEND_MODE:
26154         {
26155           int blend_mode = arg(0);
26156           if (blend_mode == CTX_COLOR) blend_mode = CTX_BLEND_COLOR;
26157           ctx_blend_mode (ctx, (CtxBlend)blend_mode);
26158         }
26159         break;
26160       case CTX_FILL_RULE:
26161         ctx_fill_rule (ctx, (CtxFillRule) arg(0) );
26162         break;
26163       case CTX_TEXT_ALIGN:
26164         ctx_text_align (ctx, (CtxTextAlign) arg(0) );
26165         break;
26166       case CTX_TEXT_BASELINE:
26167         ctx_text_baseline (ctx, (CtxTextBaseline) arg(0) );
26168         break;
26169       case CTX_TEXT_DIRECTION:
26170         ctx_text_direction (ctx, (CtxTextDirection) arg(0) );
26171         break;
26172       case CTX_IDENTITY:
26173         ctx_identity (ctx);
26174         break;
26175       case CTX_RECTANGLE:
26176         ctx_rectangle (ctx, arg(0), arg(1), arg(2), arg(3) );
26177         break;
26178       case CTX_FILL_RECT:
26179         ctx_rectangle (ctx, arg(0), arg(1), arg(2), arg(3) );
26180         ctx_fill (ctx);
26181         break;
26182       case CTX_STROKE_RECT:
26183         ctx_rectangle (ctx, arg(0), arg(1), arg(2), arg(3) );
26184         ctx_stroke (ctx);
26185         break;
26186       case CTX_ROUND_RECTANGLE:
26187         ctx_round_rectangle (ctx, arg(0), arg(1), arg(2), arg(3), arg(4));
26188         break;
26189       case CTX_VIEW_BOX:
26190         ctx_view_box (ctx, arg(0), arg(1), arg(2), arg(3) );
26191         break;
26192       case CTX_LINEAR_GRADIENT:
26193         ctx_linear_gradient (ctx, arg(0), arg(1), arg(2), arg(3) );
26194         break;
26195       case CTX_RADIAL_GRADIENT:
26196         ctx_radial_gradient (ctx, arg(0), arg(1), arg(2), arg(3), arg(4), arg(5) );
26197         break;
26198       case CTX_GRADIENT_STOP:
26199         {
26200           float red, green, blue, alpha;
26201           ctx_parser_get_color_rgba (parser, 1, &red, &green, &blue, &alpha);
26202           ctx_gradient_add_stop (ctx, arg(0), red, green, blue, alpha);
26203         }
26204         break;
26205       case CTX_GLOBAL_ALPHA:
26206         ctx_global_alpha (ctx, arg(0) );
26207         break;
26208       case CTX_BEGIN_PATH:
26209         ctx_begin_path (ctx);
26210         break;
26211       case CTX_GLYPH:
26212         ctx_glyph (ctx, arg(0), 0);
26213         break;
26214       case CTX_CLOSE_PATH:
26215         ctx_close_path (ctx);
26216         break;
26217       case CTX_EXIT:
26218         if (parser->exit)
26219           { parser->exit (parser->exit_data);
26220             return;
26221           }
26222         break;
26223       case CTX_FLUSH:
26224         //ctx_flush (ctx);
26225         break;
26226       case CTX_RESET:
26227         ctx_reset (ctx);
26228         if (parser->translate_origin)
26229         {
26230           ctx_translate (ctx,
26231                          (parser->cursor_x-1) * parser->cell_width * 1.0,
26232                          (parser->cursor_y-1) * parser->cell_height * 1.0);
26233         }
26234         break;
26235     }
26236 #undef arg
26237 //  parser->n_numbers = 0;
26238 }
26239 
ctx_parser_holding_append(CtxParser * parser,int byte)26240 static inline void ctx_parser_holding_append (CtxParser *parser, int byte)
26241 {
26242 #if !CTX_PARSER_FIXED_TEMP
26243   if (CTX_UNLIKELY(parser->hold_len < parser->pos + 1 + 1))
26244   {
26245     int new_len = parser->hold_len * 2;
26246     if (new_len < 512) new_len = 512;
26247     parser->holding = (uint8_t*)realloc (parser->holding, new_len);
26248     parser->hold_len = new_len;
26249   }
26250 #endif
26251 
26252   parser->holding[parser->pos++]=byte;
26253 #if CTX_PARSER_FIXED_TEMP
26254   if (CTX_UNLIKELY(parser->pos > (int) sizeof (parser->holding)-2))
26255     { parser->pos = sizeof (parser->holding)-2; }
26256 #endif
26257   parser->holding[parser->pos]=0;
26258 }
26259 
ctx_parser_transform_percent(CtxParser * parser,CtxCode code,int arg_no,float * value)26260 static void ctx_parser_transform_percent (CtxParser *parser, CtxCode code, int arg_no, float *value)
26261 {
26262   int big   = parser->width;
26263   int small = parser->height;
26264   if (big < small)
26265     {
26266       small = parser->width;
26267       big   = parser->height;
26268     }
26269   switch (code)
26270     {
26271       case CTX_RADIAL_GRADIENT:
26272       case CTX_ARC:
26273         switch (arg_no)
26274           {
26275             case 0:
26276             case 3:
26277               *value *= (parser->width/100.0);
26278               break;
26279             case 1:
26280             case 4:
26281               *value *= (parser->height/100.0);
26282               break;
26283             case 2:
26284             case 5:
26285               *value *= small/100.0;
26286               break;
26287           }
26288         break;
26289       case CTX_FONT_SIZE:
26290       case CTX_MITER_LIMIT:
26291       case CTX_LINE_WIDTH:
26292       case CTX_LINE_DASH_OFFSET:
26293         {
26294           *value *= (small/100.0);
26295         }
26296         break;
26297       case CTX_ARC_TO:
26298       case CTX_REL_ARC_TO:
26299         if (arg_no > 3)
26300           {
26301             *value *= (small/100.0);
26302           }
26303         else
26304           {
26305             if (arg_no % 2 == 0)
26306               { *value  *= ( (parser->width) /100.0); }
26307             else
26308               { *value *= ( (parser->height) /100.0); }
26309           }
26310         break;
26311       case CTX_ROUND_RECTANGLE:
26312         if (arg_no == 4)
26313         {
26314           { *value *= ((parser->height)/100.0); }
26315           return;
26316         }
26317         /* FALLTHROUGH */
26318       default: // even means x coord
26319         if (arg_no % 2 == 0)
26320           { *value  *= ((parser->width)/100.0); }
26321         else
26322           { *value *= ((parser->height)/100.0); }
26323         break;
26324     }
26325 }
26326 
ctx_parser_transform_percent_height(CtxParser * parser,CtxCode code,int arg_no,float * value)26327 static void ctx_parser_transform_percent_height (CtxParser *parser, CtxCode code, int arg_no, float *value)
26328 {
26329   *value *= (parser->height/100.0);
26330 }
26331 
ctx_parser_transform_percent_width(CtxParser * parser,CtxCode code,int arg_no,float * value)26332 static void ctx_parser_transform_percent_width (CtxParser *parser, CtxCode code, int arg_no, float *value)
26333 {
26334   *value *= (parser->height/100.0);
26335 }
26336 
ctx_parser_transform_cell(CtxParser * parser,CtxCode code,int arg_no,float * value)26337 static void ctx_parser_transform_cell (CtxParser *parser, CtxCode code, int arg_no, float *value)
26338 {
26339   float small = parser->cell_width;
26340   if (small > parser->cell_height)
26341     { small = parser->cell_height; }
26342   switch (code)
26343     {
26344       case CTX_RADIAL_GRADIENT:
26345       case CTX_ARC:
26346         switch (arg_no)
26347           {
26348             case 0:
26349             case 3:
26350               *value *= parser->cell_width;
26351               break;
26352             case 1:
26353             case 4:
26354               *value *= parser->cell_height;
26355               break;
26356             case 2:
26357             case 5:
26358               *value *= small; // use height?
26359               break;
26360           }
26361         break;
26362       case CTX_MITER_LIMIT:
26363       case CTX_FONT_SIZE:
26364       case CTX_LINE_WIDTH:
26365       case CTX_LINE_DASH_OFFSET:
26366         {
26367           *value *= parser->cell_height;
26368         }
26369         break;
26370       case CTX_ARC_TO:
26371       case CTX_REL_ARC_TO:
26372         if (arg_no > 3)
26373           {
26374             *value *= small;
26375           }
26376         else
26377           {
26378             *value *= (arg_no%2==0) ?parser->cell_width:parser->cell_height;
26379           }
26380         break;
26381       case CTX_RECTANGLE:
26382         if (arg_no % 2 == 0)
26383           { *value *= parser->cell_width; }
26384         else
26385           {
26386             if (! (arg_no > 1) )
26387               { (*value) -= 1.0f; }
26388             *value *= parser->cell_height;
26389           }
26390         break;
26391       default: // even means x coord odd means y coord
26392         *value *= (arg_no%2==0) ?parser->cell_width:parser->cell_height;
26393         break;
26394     }
26395 }
26396 
26397 // %h %v %m %M
26398 
ctx_parser_number_done(CtxParser * parser)26399 static void ctx_parser_number_done (CtxParser *parser)
26400 {
26401 
26402 }
26403 
ctx_parser_word_done(CtxParser * parser)26404 static void ctx_parser_word_done (CtxParser *parser)
26405 {
26406   parser->holding[parser->pos]=0;
26407   //int old_args = parser->expected_args;
26408   int command = ctx_parser_resolve_command (parser, parser->holding);
26409   if ((command >= 0 && command < 32)
26410       || (command > 150) || (command < 0)
26411       )  // special case low enum values
26412     {                   // and enum values too high to be
26413                         // commands - permitting passing words
26414                         // for strings in some cases
26415       parser->numbers[parser->n_numbers] = command;
26416 
26417       // trigger transition from number
26418       parser->state = CTX_PARSER_NUMBER;
26419       char c = ',';
26420       ctx_parser_feed_bytes (parser, &c, 1);
26421     }
26422   else if (command > 0)
26423     {
26424 #if 0
26425       if (old_args == CTX_ARG_COLLECT_NUMBERS ||
26426           old_args == CTX_ARG_STRING_OR_NUMBER)
26427       {
26428         int tmp1 = parser->command;
26429         int tmp2 = parser->expected_args;
26430         int tmp3 = parser->n_numbers;
26431  //     int tmp4 = parser->n_args;
26432         ctx_parser_dispatch_command (parser);
26433         parser->command = (CtxCode)tmp1;
26434         parser->expected_args = tmp2;
26435         parser->n_numbers = tmp3;
26436  //     parser->n_args = tmp4;
26437       }
26438 #endif
26439 
26440       parser->command = (CtxCode) command;
26441       parser->n_numbers = 0;
26442       parser->n_args = 0;
26443       if (parser->expected_args == 0)
26444         {
26445           ctx_parser_dispatch_command (parser);
26446         }
26447     }
26448   else
26449     {
26450       /* interpret char by char */
26451       uint8_t buf[16]=" ";
26452       for (int i = 0; parser->pos && parser->holding[i] > ' '; i++)
26453         {
26454           buf[0] = parser->holding[i];
26455           parser->command = (CtxCode) ctx_parser_resolve_command (parser, buf);
26456           parser->n_numbers = 0;
26457           parser->n_args = 0;
26458           if (parser->command > 0)
26459             {
26460               if (parser->expected_args == 0)
26461                 {
26462                   ctx_parser_dispatch_command (parser);
26463                 }
26464             }
26465           else
26466             {
26467               ctx_log ("unhandled command '%c'\n", buf[0]);
26468             }
26469         }
26470     }
26471 }
26472 
ctx_parser_string_done(CtxParser * parser)26473 static void ctx_parser_string_done (CtxParser *parser)
26474 {
26475   if (parser->expected_args == CTX_ARG_STRING_OR_NUMBER)
26476   {
26477           /*
26478     if (parser->state != CTX_PARSER_NUMBER &&
26479         parser->state != CTX_PARSER_NEGATIVE_NUMBER &&
26480         parser->state != CTX_PARSER_STRING_A85 &&
26481         parser->state != CTX_PARSER_STRING_APOS &&
26482         parser->state != CTX_PARSER_STRING_QUOT
26483         )
26484         */
26485     {
26486     int tmp1 = parser->command;
26487     int tmp2 = parser->expected_args;
26488     int tmp3 = parser->n_numbers;
26489     int tmp4 = parser->n_args;
26490     ctx_parser_dispatch_command (parser);
26491     parser->command = (CtxCode)tmp1;
26492     parser->expected_args = tmp2;
26493     parser->n_numbers = tmp3;
26494     parser->n_args = tmp4;
26495     }
26496   }
26497   else
26498   {
26499     ctx_parser_dispatch_command (parser);
26500   }
26501 }
26502 
ctx_parser_feed_byte(CtxParser * parser,char byte)26503 static inline void ctx_parser_feed_byte (CtxParser *parser, char byte)
26504 {
26505 #if CTX_REPORT_COL_ROW
26506     if (CTX_UNLIKELY(byte == '\n'))
26507     {
26508         parser->col=0;
26509         parser->line++;
26510     }
26511     else
26512     {
26513         parser->col++;
26514     }
26515 #endif
26516 
26517     if (CTX_LIKELY(parser->state == CTX_PARSER_STRING_YENC))
26518     {
26519         if (CTX_UNLIKELY((parser->prev_byte == '=') && (byte == 'y')))
26520         {
26521           parser->state = CTX_PARSER_NEUTRAL;
26522                  //   fprintf (stderr, "got %i\n", parser->pos);
26523           parser->pos = ctx_ydec ((char*)parser->holding, (char*)parser->holding, parser->pos) - 1;
26524 #if 0
26525           if (parser->pos > 5)
26526                     fprintf (stderr, "dec got %i %c %c %c %c\n", parser->pos,
26527                                     parser->holding[0],
26528                                     parser->holding[1],
26529                                     parser->holding[2],
26530                                     parser->holding[3]
26531                                     );
26532 #endif
26533           ctx_parser_string_done (parser);
26534         }
26535         else
26536         {
26537           ctx_parser_holding_append (parser, byte);
26538         }
26539         parser->prev_byte = byte;
26540         return;
26541     }
26542     else if (parser->state == CTX_PARSER_STRING_A85)
26543     {
26544         /* since these are our largest bulk transfers, minimize
26545          * overhead for this case. */
26546         if (CTX_LIKELY(byte!='~'))
26547         {
26548           ctx_parser_holding_append (parser, byte);
26549         }
26550         else
26551         {
26552           parser->state = CTX_PARSER_NEUTRAL;
26553                  //   fprintf (stderr, "got %i\n", parser->pos);
26554           parser->pos = ctx_a85dec ((char*)parser->holding, (char*)parser->holding, parser->pos);
26555                  //   fprintf (stderr, "dec got %i\n", parser->pos);
26556           ctx_parser_string_done (parser);
26557         }
26558         return;
26559     }
26560   switch (parser->state)
26561     {
26562       case CTX_PARSER_NEUTRAL:
26563         switch (byte)
26564           {
26565             case  0: case  1: case  2: case  3:  case 4:  case 5:
26566             case  6: case  7: case  8: case 11: case 12: case 14:
26567             case 15: case 16: case 17: case 18: case 19: case 20:
26568             case 21: case 22: case 23: case 24: case 25: case 26:
26569             case 27: case 28: case 29: case 30: case 31:
26570               break;
26571             case ' ': case '\t': case '\r': case '\n':
26572             case ';': case ',':
26573             case '(': case ')':
26574             case '{': case '}':
26575             //case '=':
26576               break;
26577             case '#':
26578               parser->state = CTX_PARSER_COMMENT;
26579               break;
26580             case '\'':
26581               parser->state = CTX_PARSER_STRING_APOS;
26582               parser->pos = 0;
26583               parser->holding[0] = 0;
26584               break;
26585             case '=':
26586               parser->state = CTX_PARSER_STRING_YENC;
26587               parser->pos = 0;
26588               parser->holding[0] = 0;
26589               break;
26590             case '~':
26591               parser->state = CTX_PARSER_STRING_A85;
26592               parser->pos = 0;
26593               parser->holding[0] = 0;
26594               break;
26595             case '"':
26596               parser->state = CTX_PARSER_STRING_QUOT;
26597               parser->pos = 0;
26598               parser->holding[0] = 0;
26599               break;
26600             case '-':
26601               parser->state = CTX_PARSER_NEGATIVE_NUMBER;
26602               parser->numbers[parser->n_numbers] = 0;
26603               parser->decimal = 0;
26604               break;
26605             case '0': case '1': case '2': case '3': case '4':
26606             case '5': case '6': case '7': case '8': case '9':
26607               parser->state = CTX_PARSER_NUMBER;
26608               parser->numbers[parser->n_numbers] = 0;
26609               parser->numbers[parser->n_numbers] += (byte - '0');
26610               parser->decimal = 0;
26611               break;
26612             case '.':
26613               parser->state = CTX_PARSER_NUMBER;
26614               parser->numbers[parser->n_numbers] = 0;
26615               parser->decimal = 1;
26616               break;
26617             default:
26618               parser->state = CTX_PARSER_WORD;
26619               parser->pos = 0;
26620               ctx_parser_holding_append (parser, byte);
26621               break;
26622           }
26623         break;
26624       case CTX_PARSER_NUMBER:
26625       case CTX_PARSER_NEGATIVE_NUMBER:
26626         {
26627           switch (byte)
26628             {
26629               case 0: case 1: case 2: case 3: case 4: case 5:
26630               case 6: case 7: case 8:
26631               case 11: case 12: case 14: case 15: case 16:
26632               case 17: case 18: case 19: case 20: case 21:
26633               case 22: case 23: case 24: case 25: case 26:
26634               case 27: case 28: case 29: case 30: case 31:
26635                 parser->state = CTX_PARSER_NEUTRAL;
26636                 break;
26637               case ' ':
26638               case '\t':
26639               case '\r':
26640               case '\n':
26641               case ';':
26642               case ',':
26643               case '(':
26644               case ')':
26645               case '{':
26646               case '}':
26647               case '=':
26648                 if (parser->state == CTX_PARSER_NEGATIVE_NUMBER)
26649                   { parser->numbers[parser->n_numbers] *= -1; }
26650                 parser->state = CTX_PARSER_NEUTRAL;
26651                 break;
26652               case '#':
26653                 parser->state = CTX_PARSER_COMMENT;
26654                 break;
26655               case '-':
26656                 if (parser->state == CTX_PARSER_NEGATIVE_NUMBER)
26657                   { parser->numbers[parser->n_numbers] *= -1; }
26658                 parser->state = CTX_PARSER_NEGATIVE_NUMBER;
26659                 parser->numbers[parser->n_numbers+1] = 0;
26660                 parser->n_numbers ++;
26661                 parser->decimal = 0;
26662                 break;
26663               case '.':
26664                 //if (parser->decimal) // TODO permit .13.32.43 to equivalent to .12 .32 .43
26665                 parser->decimal = 1;
26666                 break;
26667               case '0': case '1': case '2': case '3': case '4':
26668               case '5': case '6': case '7': case '8': case '9':
26669                 if (parser->decimal)
26670                   {
26671                     parser->decimal *= 10;
26672                     parser->numbers[parser->n_numbers] += (byte - '0') / (1.0 * parser->decimal);
26673                   }
26674                 else
26675                   {
26676                     parser->numbers[parser->n_numbers] *= 10;
26677                     parser->numbers[parser->n_numbers] += (byte - '0');
26678                   }
26679                 break;
26680               case '@': // cells
26681                 if (parser->state == CTX_PARSER_NEGATIVE_NUMBER)
26682                   { parser->numbers[parser->n_numbers] *= -1; }
26683                 {
26684                 float fval = parser->numbers[parser->n_numbers];
26685                 ctx_parser_transform_cell (parser, parser->command, parser->n_numbers, &fval);
26686                 parser->numbers[parser->n_numbers]= fval;
26687                 }
26688                 parser->state = CTX_PARSER_NEUTRAL;
26689                 break;
26690               case '%': // percent of width/height
26691                 if (parser->state == CTX_PARSER_NEGATIVE_NUMBER)
26692                   { parser->numbers[parser->n_numbers] *= -1; }
26693                 {
26694                 float fval = parser->numbers[parser->n_numbers];
26695                 ctx_parser_transform_percent (parser, parser->command, parser->n_numbers, &fval);
26696                 parser->numbers[parser->n_numbers]= fval;
26697                 }
26698                 parser->state = CTX_PARSER_NEUTRAL;
26699                 break;
26700               case '^': // percent of height
26701                 if (parser->state == CTX_PARSER_NEGATIVE_NUMBER)
26702                   { parser->numbers[parser->n_numbers] *= -1; }
26703                 {
26704                 float fval = parser->numbers[parser->n_numbers];
26705                 ctx_parser_transform_percent_height (parser, parser->command, parser->n_numbers, &fval);
26706                 parser->numbers[parser->n_numbers]= fval;
26707                 }
26708                 parser->state = CTX_PARSER_NEUTRAL;
26709                 break;
26710               case '~': // percent of width
26711                 if (parser->state == CTX_PARSER_NEGATIVE_NUMBER)
26712                   { parser->numbers[parser->n_numbers] *= -1; }
26713                 {
26714                 float fval = parser->numbers[parser->n_numbers];
26715                 ctx_parser_transform_percent_width (parser, parser->command, parser->n_numbers, &fval);
26716                 parser->numbers[parser->n_numbers]= fval;
26717                 }
26718                 parser->state = CTX_PARSER_NEUTRAL;
26719                 break;
26720               default:
26721                 if (parser->state == CTX_PARSER_NEGATIVE_NUMBER)
26722                   { parser->numbers[parser->n_numbers] *= -1; }
26723                 parser->state = CTX_PARSER_WORD;
26724                 parser->pos = 0;
26725                 ctx_parser_holding_append (parser, byte);
26726                 break;
26727             }
26728           if ( (parser->state != CTX_PARSER_NUMBER) &&
26729                (parser->state != CTX_PARSER_NEGATIVE_NUMBER))
26730             {
26731               parser->n_numbers ++;
26732               ctx_parser_number_done (parser);
26733 
26734               if (parser->n_numbers == parser->expected_args ||
26735                   parser->expected_args == CTX_ARG_COLLECT_NUMBERS ||
26736                   parser->expected_args == CTX_ARG_STRING_OR_NUMBER)
26737                 {
26738                   int tmp1 = parser->n_numbers;
26739                   int tmp2 = parser->n_args;
26740                   CtxCode tmp3 = parser->command;
26741                   int tmp4 = parser->expected_args;
26742                   ctx_parser_dispatch_command (parser);
26743                   parser->command = tmp3;
26744                   switch (parser->command)
26745                   {
26746                     case CTX_DEFINE_TEXTURE:
26747                     case CTX_TEXTURE:
26748                       parser->n_numbers = tmp1;
26749                       parser->n_args = tmp2;
26750                       break;
26751                           default:
26752                       parser->n_numbers = 0;
26753                       parser->n_args = 0;
26754                       break;
26755                   }
26756                   parser->expected_args = tmp4;
26757                 }
26758               if (parser->n_numbers > CTX_PARSER_MAX_ARGS)
26759                 { parser->n_numbers = CTX_PARSER_MAX_ARGS;
26760                 }
26761             }
26762         }
26763         break;
26764       case CTX_PARSER_WORD:
26765         switch (byte)
26766           {
26767             case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
26768             case 8: case 11: case 12: case 14: case 15: case 16: case 17:
26769             case 18: case 19: case 20: case 21: case 22: case 23: case 24:
26770             case 25: case 26: case 27: case 28: case 29: case 30: case 31:
26771             case ' ': case '\t': case '\r': case '\n':
26772             case ';': case ',':
26773             case '(': case ')': case '=': case '{': case '}':
26774               parser->state = CTX_PARSER_NEUTRAL;
26775               break;
26776             case '#':
26777               parser->state = CTX_PARSER_COMMENT;
26778               break;
26779             case '-':
26780               parser->state = CTX_PARSER_NEGATIVE_NUMBER;
26781               parser->numbers[parser->n_numbers] = 0;
26782               parser->decimal = 0;
26783               break;
26784             case '0': case '1': case '2': case '3': case '4':
26785             case '5': case '6': case '7': case '8': case '9':
26786               parser->state = CTX_PARSER_NUMBER;
26787               parser->numbers[parser->n_numbers] = 0;
26788               parser->numbers[parser->n_numbers] += (byte - '0');
26789               parser->decimal = 0;
26790               break;
26791             case '.':
26792               parser->state = CTX_PARSER_NUMBER;
26793               parser->numbers[parser->n_numbers] = 0;
26794               parser->decimal = 1;
26795               break;
26796             default:
26797               ctx_parser_holding_append (parser, byte);
26798               break;
26799           }
26800         if (parser->state != CTX_PARSER_WORD)
26801           {
26802             ctx_parser_word_done (parser);
26803           }
26804         break;
26805       case CTX_PARSER_STRING_A85:
26806         if (CTX_LIKELY(byte!='~'))
26807         {
26808           ctx_parser_holding_append (parser, byte);
26809         }
26810         else
26811         {
26812           parser->state = CTX_PARSER_NEUTRAL;
26813                  //   fprintf (stderr, "got %i\n", parser->pos);
26814           parser->pos = ctx_a85dec ((char*)parser->holding, (char*)parser->holding, parser->pos);
26815                  //   fprintf (stderr, "dec got %i\n", parser->pos);
26816           ctx_parser_string_done (parser);
26817         }
26818         break;
26819       case CTX_PARSER_STRING_APOS:
26820         switch (byte)
26821           {
26822             case '\\': parser->state = CTX_PARSER_STRING_APOS_ESCAPED; break;
26823             case '\'': parser->state = CTX_PARSER_NEUTRAL;
26824               ctx_parser_string_done (parser);
26825               break;
26826             default:
26827               ctx_parser_holding_append (parser, byte); break;
26828           }
26829         break;
26830       case CTX_PARSER_STRING_APOS_ESCAPED:
26831         switch (byte)
26832           {
26833             case '0': byte = '\0'; break;
26834             case 'b': byte = '\b'; break;
26835             case 'f': byte = '\f'; break;
26836             case 'n': byte = '\n'; break;
26837             case 'r': byte = '\r'; break;
26838             case 't': byte = '\t'; break;
26839             case 'v': byte = '\v'; break;
26840             default: break;
26841           }
26842         ctx_parser_holding_append (parser, byte);
26843         parser->state = CTX_PARSER_STRING_APOS;
26844         break;
26845       case CTX_PARSER_STRING_QUOT_ESCAPED:
26846         switch (byte)
26847           {
26848             case '0': byte = '\0'; break;
26849             case 'b': byte = '\b'; break;
26850             case 'f': byte = '\f'; break;
26851             case 'n': byte = '\n'; break;
26852             case 'r': byte = '\r'; break;
26853             case 't': byte = '\t'; break;
26854             case 'v': byte = '\v'; break;
26855             default: break;
26856           }
26857         ctx_parser_holding_append (parser, byte);
26858         parser->state = CTX_PARSER_STRING_QUOT;
26859         break;
26860       case CTX_PARSER_STRING_QUOT:
26861         switch (byte)
26862           {
26863             case '\\':
26864               parser->state = CTX_PARSER_STRING_QUOT_ESCAPED;
26865               break;
26866             case '"':
26867               parser->state = CTX_PARSER_NEUTRAL;
26868               ctx_parser_string_done (parser);
26869               break;
26870             default:
26871               ctx_parser_holding_append (parser, byte);
26872               break;
26873           }
26874         break;
26875       case CTX_PARSER_COMMENT:
26876         switch (byte)
26877           {
26878             case '\r':
26879             case '\n':
26880               parser->state = CTX_PARSER_NEUTRAL;
26881             default:
26882               break;
26883           }
26884         break;
26885     }
26886 }
26887 
ctx_parser_feed_bytes(CtxParser * parser,const char * data,int count)26888 void ctx_parser_feed_bytes (CtxParser *parser, const char *data, int count)
26889 {
26890   for (int i = 0; i < count; i++)
26891     ctx_parser_feed_byte (parser, data[i]);
26892 }
26893 
ctx_parse(Ctx * ctx,const char * string)26894 void ctx_parse (Ctx *ctx, const char *string)
26895 {
26896   if (!string)
26897     return;
26898   CtxParser *parser = ctx_parser_new (ctx, ctx_width(ctx),
26899                                            ctx_height(ctx),
26900                                            ctx_get_font_size(ctx),
26901                                            ctx_get_font_size(ctx),
26902                                            0, 0, NULL, NULL, NULL, NULL, NULL);
26903   ctx_parser_feed_bytes (parser, string, strlen (string));
26904   ctx_parser_free (parser);
26905 }
26906 
26907 #endif
26908 
26909 static CtxFont ctx_fonts[CTX_MAX_FONTS];
26910 static int     ctx_font_count = 0;
26911 
26912 #if CTX_FONT_ENGINE_STB
26913 static float
26914 ctx_glyph_width_stb (CtxFont *font, Ctx *ctx, uint32_t unichar);
26915 static float
26916 ctx_glyph_kern_stb (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unicharB);
26917 static int
26918 ctx_glyph_stb (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke);
26919 
26920 CtxFontEngine ctx_font_engine_stb =
26921 {
26922 #if CTX_FONTS_FROM_FILE
26923   ctx_load_font_ttf_file,
26924 #endif
26925   ctx_load_font_ttf,
26926   ctx_glyph_stb,
26927   ctx_glyph_width_stb,
26928   ctx_glyph_kern_stb,
26929 };
26930 
26931 int
ctx_load_font_ttf(const char * name,const void * ttf_contents,int length)26932 ctx_load_font_ttf (const char *name, const void *ttf_contents, int length)
26933 {
26934   if (ctx_font_count >= CTX_MAX_FONTS)
26935     { return -1; }
26936   ctx_fonts[ctx_font_count].type = 1;
26937   ctx_fonts[ctx_font_count].name = (char *) malloc (strlen (name) + 1);
26938   ctx_strcpy ( (char *) ctx_fonts[ctx_font_count].name, name);
26939   if (!stbtt_InitFont (&ctx_fonts[ctx_font_count].stb.ttf_info, ttf_contents, 0) )
26940     {
26941       ctx_log ( "Font init failed\n");
26942       return -1;
26943     }
26944   ctx_fonts[ctx_font_count].engine = &ctx_font_engine_stb;
26945   ctx_font_count ++;
26946   return ctx_font_count-1;
26947 }
26948 
26949 #if CTX_FONTS_FROM_FILE
26950 int
ctx_load_font_ttf_file(const char * name,const char * path)26951 ctx_load_font_ttf_file (const char *name, const char *path)
26952 {
26953   uint8_t *contents = NULL;
26954   long length = 0;
26955   ctx_get_contents (path, &contents, &length);
26956   if (!contents)
26957     {
26958       ctx_log ( "File load failed\n");
26959       return -1;
26960     }
26961   return ctx_load_font_ttf (name, contents, length);
26962 }
26963 #endif
26964 
26965 static int
ctx_glyph_stb_find(CtxFont * font,uint32_t unichar)26966 ctx_glyph_stb_find (CtxFont *font, uint32_t unichar)
26967 {
26968   stbtt_fontinfo *ttf_info = &font->stb.ttf_info;
26969   int index = font->stb.cache_index;
26970   if (font->stb.cache_unichar == unichar)
26971     {
26972       return index;
26973     }
26974   font->stb.cache_unichar = 0;
26975   index = font->stb.cache_index = stbtt_FindGlyphIndex (ttf_info, unichar);
26976   font->stb.cache_unichar = unichar;
26977   return index;
26978 }
26979 
26980 static float
ctx_glyph_width_stb(CtxFont * font,Ctx * ctx,uint32_t unichar)26981 ctx_glyph_width_stb (CtxFont *font, Ctx *ctx, uint32_t unichar)
26982 {
26983   stbtt_fontinfo *ttf_info = &font->stb.ttf_info;
26984   float font_size          = ctx->state.gstate.font_size;
26985   float scale              = stbtt_ScaleForPixelHeight (ttf_info, font_size);
26986   int advance, lsb;
26987   int glyph = ctx_glyph_stb_find (font, unichar);
26988 
26989 #if CTX_EVENTS
26990   if (ctx_renderer_is_term (ctx))
26991     return 2;
26992 #endif
26993 
26994   if (glyph==0)
26995     { return 0.0f; }
26996   stbtt_GetGlyphHMetrics (ttf_info, glyph, &advance, &lsb);
26997   return (advance * scale);
26998 }
26999 
27000 static float
ctx_glyph_kern_stb(CtxFont * font,Ctx * ctx,uint32_t unicharA,uint32_t unicharB)27001 ctx_glyph_kern_stb (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unicharB)
27002 {
27003   stbtt_fontinfo *ttf_info = &font->stb.ttf_info;
27004   float font_size = ctx->state.gstate.font_size;
27005   float scale = stbtt_ScaleForPixelHeight (ttf_info, font_size);
27006   int glyphA = ctx_glyph_stb_find (font, unicharA);
27007   int glyphB = ctx_glyph_stb_find (font, unicharB);
27008   return stbtt_GetGlyphKernAdvance (ttf_info, glyphA, glyphB) * scale;
27009 }
27010 
27011 static int
ctx_glyph_stb(CtxFont * font,Ctx * ctx,uint32_t unichar,int stroke)27012 ctx_glyph_stb (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke)
27013 {
27014   stbtt_fontinfo *ttf_info = &font->stb.ttf_info;
27015   int glyph = ctx_glyph_stb_find (font, unichar);
27016   if (glyph==0)
27017     { return -1; }
27018   float font_size = ctx->state.gstate.font_size;
27019   int   baseline = ctx->state.y;
27020   float origin_x = ctx->state.x;
27021   float origin_y = baseline;
27022   float scale    = stbtt_ScaleForPixelHeight (ttf_info, font_size);;
27023   stbtt_vertex *vertices = NULL;
27024   ctx_begin_path (ctx);
27025   int num_verts = stbtt_GetGlyphShape (ttf_info, glyph, &vertices);
27026   for (int i = 0; i < num_verts; i++)
27027     {
27028       stbtt_vertex *vertex = &vertices[i];
27029       switch (vertex->type)
27030         {
27031           case STBTT_vmove:
27032             ctx_move_to (ctx,
27033                          origin_x + vertex->x * scale, origin_y - vertex->y * scale);
27034             break;
27035           case STBTT_vline:
27036             ctx_line_to (ctx,
27037                          origin_x + vertex->x * scale, origin_y - vertex->y * scale);
27038             break;
27039           case STBTT_vcubic:
27040             ctx_curve_to (ctx,
27041                           origin_x + vertex->cx  * scale, origin_y - vertex->cy  * scale,
27042                           origin_x + vertex->cx1 * scale, origin_y - vertex->cy1 * scale,
27043                           origin_x + vertex->x   * scale, origin_y - vertex->y   * scale);
27044             break;
27045           case STBTT_vcurve:
27046             ctx_quad_to (ctx,
27047                          origin_x + vertex->cx  * scale, origin_y - vertex->cy  * scale,
27048                          origin_x + vertex->x   * scale, origin_y - vertex->y   * scale);
27049             break;
27050         }
27051     }
27052   stbtt_FreeShape (ttf_info, vertices);
27053   if (stroke)
27054     {
27055       ctx_stroke (ctx);
27056     }
27057   else
27058     { ctx_fill (ctx); }
27059   return 0;
27060 }
27061 #endif
27062 
27063 #if CTX_FONT_ENGINE_CTX
27064 
ctx_font_find_glyph_cached(CtxFont * font,uint32_t glyph)27065 static int ctx_font_find_glyph_cached (CtxFont *font, uint32_t glyph)
27066 {
27067 #if 1
27068   int min       = 0;
27069   int max       = font->ctx.glyphs-1;
27070   uint32_t found;
27071 
27072   do {
27073     int pos = (min + max)/2;
27074     found = font->ctx.index[pos*2];
27075     if (found == glyph)
27076     {
27077       return font->ctx.index[pos*2+1];
27078     } else if (min == max)
27079       return -1;
27080     else if (min == max-1)
27081       return -1;
27082     else if (found < glyph)
27083     {
27084       min = pos;
27085     } else {
27086       max = pos;
27087     }
27088 
27089   } while (min != max);
27090 
27091   return -1;
27092 #else
27093   for (int i = 0; i < font->ctx.glyphs; i++)
27094     {
27095       if (font->ctx.index[i * 2] == glyph)
27096         { return font->ctx.index[i * 2 + 1]; }
27097     }
27098   return -1;
27099 #endif
27100 }
27101 
ctx_glyph_find_ctx(CtxFont * font,Ctx * ctx,uint32_t unichar)27102 static int ctx_glyph_find_ctx (CtxFont *font, Ctx *ctx, uint32_t unichar)
27103 {
27104   int ret = ctx_font_find_glyph_cached (font, unichar);
27105   if (ret >= 0) return ret;
27106 
27107   for (int i = 0; i < font->ctx.length; i++)
27108   {
27109     CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
27110     if (entry->code == CTX_DEFINE_GLYPH &&
27111         entry->data.u32[0] == unichar)
27112     {
27113        return i;
27114        // XXX this could be prone to insertion of valid header
27115        // data in included bitmaps.. is that an issue?
27116        //
27117     }
27118   }
27119   return -1;
27120 }
27121 
27122 
27123 static float
ctx_glyph_kern_ctx(CtxFont * font,Ctx * ctx,uint32_t unicharA,uint32_t unicharB)27124 ctx_glyph_kern_ctx (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unicharB)
27125 {
27126   float font_size = ctx->state.gstate.font_size;
27127   int first_kern = ctx_glyph_find_ctx (font, ctx, unicharA);
27128   if (first_kern < 0) return 0.0;
27129 
27130 #if CTX_EVENTS
27131   if (ctx_renderer_is_term (ctx) && (3.02 - font_size) < 0.03)
27132     return 0.0f;
27133 #endif
27134 
27135   for (int i = first_kern + 1; i < font->ctx.length; i++)
27136     {
27137       CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
27138       if (entry->code == CTX_KERNING_PAIR)
27139         {
27140           if (entry->data.u16[0] == unicharA && entry->data.u16[1] == unicharB)
27141             { return entry->data.s32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE; }
27142         }
27143       if (entry->code == CTX_DEFINE_GLYPH)
27144         return 0.0;
27145     }
27146   return 0.0;
27147 }
27148 #if 0
27149 static int ctx_glyph_find (Ctx *ctx, CtxFont *font, uint32_t unichar)
27150 {
27151   for (int i = 0; i < font->ctx.length; i++)
27152     {
27153       CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
27154       if (entry->code == CTX_DEFINE_GLYPH && entry->data.u32[0] == unichar)
27155         { return i; }
27156     }
27157   return 0;
27158 }
27159 #endif
27160 
27161 
27162 static float
ctx_glyph_width_ctx(CtxFont * font,Ctx * ctx,uint32_t unichar)27163 ctx_glyph_width_ctx (CtxFont *font, Ctx *ctx, uint32_t unichar)
27164 {
27165   CtxState *state = &ctx->state;
27166   float font_size = state->gstate.font_size;
27167   int   start     = ctx_glyph_find_ctx (font, ctx, unichar);
27168   if (start < 0)
27169     { return 0.0; }  // XXX : fallback
27170 
27171 #if CTX_EVENTS
27172   if (ctx_renderer_is_term (ctx) && (3.02 - font_size) < 0.03)
27173     return 2.0f;
27174 #endif
27175 
27176   for (int i = start; i < font->ctx.length; i++)
27177     {
27178       CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
27179       if (entry->code == CTX_DEFINE_GLYPH)
27180         if (entry->data.u32[0] == (unsigned) unichar)
27181           { return (entry->data.u32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE); }
27182     }
27183   return 0.0;
27184 }
27185 
27186 static int
ctx_glyph_drawlist(CtxFont * font,Ctx * ctx,CtxDrawlist * drawlist,uint32_t unichar,int stroke)27187 ctx_glyph_drawlist (CtxFont *font, Ctx *ctx, CtxDrawlist *drawlist, uint32_t unichar, int stroke)
27188 {
27189   CtxState *state = &ctx->state;
27190   CtxIterator iterator;
27191   float origin_x = state->x;
27192   float origin_y = state->y;
27193   ctx_current_point (ctx, &origin_x, &origin_y);
27194   int in_glyph = 0;
27195   float font_size = state->gstate.font_size;
27196   int start = 0;
27197   if (font->type == 0)
27198   {
27199   start = ctx_glyph_find_ctx (font, ctx, unichar);
27200   if (start < 0)
27201     { return -1; }  // XXX : fallback glyph
27202   }
27203   ctx_iterator_init (&iterator, drawlist, start, CTX_ITERATOR_EXPAND_BITPACK);
27204   CtxCommand *command;
27205 
27206   /* XXX :  do a binary search instead of a linear search */
27207   while ( (command= ctx_iterator_next (&iterator) ) )
27208     {
27209       CtxEntry *entry = &command->entry;
27210       if (in_glyph)
27211         {
27212           if (entry->code == CTX_DEFINE_GLYPH)
27213             {
27214               if (stroke)
27215                 { ctx_stroke (ctx); }
27216               else
27217                 {
27218 #if CTX_RASTERIZER
27219 #if CTX_ENABLE_SHADOW_BLUR
27220       if (ctx->renderer && ((CtxRasterizer*)(ctx->renderer))->in_shadow)
27221       {
27222         ctx_rasterizer_shadow_fill ((CtxRasterizer*)ctx->renderer);
27223         ((CtxRasterizer*)(ctx->renderer))->in_shadow = 1;
27224       }
27225       else
27226 #endif
27227 #endif
27228          ctx_fill (ctx);
27229 
27230                 }
27231               ctx_restore (ctx);
27232               return 0;
27233             }
27234           ctx_process (ctx, entry);
27235         }
27236       else if (entry->code == CTX_DEFINE_GLYPH && entry->data.u32[0] == unichar)
27237         {
27238           in_glyph = 1;
27239           ctx_save (ctx);
27240           ctx_translate (ctx, origin_x, origin_y);
27241           ctx_move_to (ctx, 0, 0);
27242           ctx_begin_path (ctx);
27243           ctx_scale (ctx, font_size / CTX_BAKE_FONT_SIZE,
27244                      font_size / CTX_BAKE_FONT_SIZE);
27245         }
27246     }
27247   if (stroke)
27248     { ctx_stroke (ctx);
27249     }
27250   else
27251     {
27252 
27253 #if CTX_RASTERIZER
27254 #if CTX_ENABLE_SHADOW_BLUR
27255       if (ctx->renderer && ((CtxRasterizer*)(ctx->renderer))->in_shadow)
27256       {
27257         ctx_rasterizer_shadow_fill ((CtxRasterizer*)ctx->renderer);
27258         ((CtxRasterizer*)(ctx->renderer))->in_shadow = 1;
27259       }
27260       else
27261 #endif
27262 #endif
27263       {
27264          ctx_fill (ctx);
27265       }
27266     }
27267   ctx_restore (ctx);
27268   return -1;
27269 }
27270 
27271 static int
ctx_glyph_ctx(CtxFont * font,Ctx * ctx,uint32_t unichar,int stroke)27272 ctx_glyph_ctx (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke)
27273 {
27274   CtxDrawlist drawlist = { (CtxEntry *) font->ctx.data,
27275                            font->ctx.length,
27276                            font->ctx.length, 0, 0
27277                          };
27278   return ctx_glyph_drawlist (font, ctx, &drawlist, unichar, stroke);
27279 }
27280 
27281 #if 0
27282 uint32_t ctx_glyph_no (Ctx *ctx, int no)
27283 {
27284   CtxFont *font = &ctx_fonts[ctx->state.gstate.font];
27285   if (no < 0 || no >= font->ctx.glyphs)
27286     { return 0; }
27287   return font->ctx.index[no*2];
27288 }
27289 #endif
27290 
ctx_font_init_ctx(CtxFont * font)27291 static void ctx_font_init_ctx (CtxFont *font)
27292 {
27293   int glyph_count = 0;
27294   for (int i = 0; i < font->ctx.length; i++)
27295     {
27296       CtxEntry *entry = &font->ctx.data[i];
27297       if (entry->code == CTX_DEFINE_GLYPH)
27298         { glyph_count ++; }
27299     }
27300   font->ctx.glyphs = glyph_count;
27301 #if CTX_DRAWLIST_STATIC
27302   static uint32_t idx[512]; // one might have to adjust this for
27303   // larger fonts XXX
27304   // should probably be made a #define
27305   font->ctx.index = &idx[0];
27306 #else
27307   font->ctx.index = (uint32_t *) malloc (sizeof (uint32_t) * 2 * glyph_count);
27308 #endif
27309   int no = 0;
27310   for (int i = 0; i < font->ctx.length; i++)
27311     {
27312       CtxEntry *entry = &font->ctx.data[i];
27313       if (entry->code == CTX_DEFINE_GLYPH)
27314         {
27315           font->ctx.index[no*2]   = entry->data.u32[0];
27316           font->ctx.index[no*2+1] = i;
27317           no++;
27318         }
27319     }
27320 }
27321 
27322 int
27323 ctx_load_font_ctx (const char *name, const void *data, int length);
27324 #if CTX_FONTS_FROM_FILE
27325 int
27326 ctx_load_font_ctx_file (const char *name, const char *path);
27327 #endif
27328 
27329 static CtxFontEngine ctx_font_engine_ctx =
27330 {
27331 #if CTX_FONTS_FROM_FILE
27332   ctx_load_font_ctx_file,
27333 #endif
27334   ctx_load_font_ctx,
27335   ctx_glyph_ctx,
27336   ctx_glyph_width_ctx,
27337   ctx_glyph_kern_ctx,
27338 };
27339 
27340 int
ctx_load_font_ctx(const char * name,const void * data,int length)27341 ctx_load_font_ctx (const char *name, const void *data, int length)
27342 {
27343   if (length % sizeof (CtxEntry) )
27344     { return -1; }
27345   if (ctx_font_count >= CTX_MAX_FONTS)
27346     { return -1; }
27347   ctx_fonts[ctx_font_count].type = 0;
27348   ctx_fonts[ctx_font_count].name = name;
27349   ctx_fonts[ctx_font_count].ctx.data = (CtxEntry *) data;
27350   ctx_fonts[ctx_font_count].ctx.length = length / sizeof (CtxEntry);
27351   ctx_font_init_ctx (&ctx_fonts[ctx_font_count]);
27352   ctx_fonts[ctx_font_count].engine = &ctx_font_engine_ctx;
27353   ctx_font_count++;
27354   return ctx_font_count-1;
27355 }
27356 
27357 #if CTX_FONTS_FROM_FILE
27358 int
ctx_load_font_ctx_file(const char * name,const char * path)27359 ctx_load_font_ctx_file (const char *name, const char *path)
27360 {
27361   uint8_t *contents = NULL;
27362   long length = 0;
27363   ctx_get_contents (path, &contents, &length);
27364   if (!contents)
27365     {
27366       ctx_log ( "File load failed\n");
27367       return -1;
27368     }
27369   return ctx_load_font_ctx (name, contents, length);
27370 }
27371 #endif
27372 #endif
27373 
27374 #if CTX_FONT_ENGINE_CTX_FS
27375 
27376 static float
ctx_glyph_kern_ctx_fs(CtxFont * font,Ctx * ctx,uint32_t unicharA,uint32_t unicharB)27377 ctx_glyph_kern_ctx_fs (CtxFont *font, Ctx *ctx, uint32_t unicharA, uint32_t unicharB)
27378 {
27379 #if 0
27380   float font_size = ctx->state.gstate.font_size;
27381   int first_kern = ctx_glyph_find_ctx (font, ctx, unicharA);
27382   if (first_kern < 0) return 0.0;
27383   for (int i = first_kern + 1; i < font->ctx.length; i++)
27384     {
27385       CtxEntry *entry = (CtxEntry *) &font->ctx.data[i];
27386       if (entry->code == CTX_KERNING_PAIR)
27387         {
27388           if (entry->data.u16[0] == unicharA && entry->data.u16[1] == unicharB)
27389             { return entry->data.s32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE; }
27390         }
27391       if (entry->code == CTX_DEFINE_GLYPH)
27392         return 0.0;
27393     }
27394 #endif
27395   return 0.0;
27396 }
27397 
27398 static float
ctx_glyph_width_ctx_fs(CtxFont * font,Ctx * ctx,uint32_t unichar)27399 ctx_glyph_width_ctx_fs (CtxFont *font, Ctx *ctx, uint32_t unichar)
27400 {
27401   CtxState *state = &ctx->state;
27402   char path[1024];
27403   sprintf (path, "%s/%010p", font->ctx_fs.path, unichar);
27404   uint8_t *data = NULL;
27405   long int len_bytes = 0;
27406   ctx_get_contents (path, &data, &len_bytes);
27407   float ret = 0.0;
27408   float font_size = state->gstate.font_size;
27409   if (data){
27410     Ctx *glyph_ctx = ctx_new ();
27411     ctx_parse (glyph_ctx, data);
27412     for (int i = 0; i < glyph_ctx->drawlist.count; i++)
27413     {
27414       CtxEntry *e = &glyph_ctx->drawlist.entries[i];
27415       if (e->code == CTX_DEFINE_GLYPH)
27416         ret = e->data.u32[1] / 255.0 * font_size / CTX_BAKE_FONT_SIZE;
27417     }
27418     free (data);
27419     ctx_free (glyph_ctx);
27420   }
27421   return ret;
27422 }
27423 
27424 static int
ctx_glyph_ctx_fs(CtxFont * font,Ctx * ctx,uint32_t unichar,int stroke)27425 ctx_glyph_ctx_fs (CtxFont *font, Ctx *ctx, uint32_t unichar, int stroke)
27426 {
27427   char path[1024];
27428   sprintf (path, "file://%s/%010p", font->ctx_fs.path, unichar);
27429   uint8_t *data = NULL;
27430   long int len_bytes = 0;
27431   ctx_get_contents (path, &data, &len_bytes);
27432 
27433   if (data){
27434     Ctx *glyph_ctx = ctx_new ();
27435     ctx_parse (glyph_ctx, data);
27436     int ret = ctx_glyph_drawlist (font, ctx, &(glyph_ctx->drawlist),
27437                                   unichar, stroke);
27438     free (data);
27439     ctx_free (glyph_ctx);
27440     return ret;
27441   }
27442   return -1;
27443 }
27444 
27445 int
27446 ctx_load_font_ctx_fs (const char *name, const void *data, int length);
27447 
27448 static CtxFontEngine ctx_font_engine_ctx_fs =
27449 {
27450 #if CTX_FONTS_FROM_FILE
27451   NULL,
27452 #endif
27453   ctx_load_font_ctx_fs,
27454   ctx_glyph_ctx_fs,
27455   ctx_glyph_width_ctx_fs,
27456   ctx_glyph_kern_ctx_fs,
27457 };
27458 
27459 int
ctx_load_font_ctx_fs(const char * name,const void * path,int length)27460 ctx_load_font_ctx_fs (const char *name, const void *path, int length) // length is ignored
27461 {
27462   if (ctx_font_count >= CTX_MAX_FONTS)
27463     { return -1; }
27464 
27465   ctx_fonts[ctx_font_count].type = 42;
27466   ctx_fonts[ctx_font_count].name = name;
27467   ctx_fonts[ctx_font_count].ctx_fs.path = strdup (path);
27468   int path_len = strlen (path);
27469   if (ctx_fonts[ctx_font_count].ctx_fs.path[path_len-1] == '/')
27470    ctx_fonts[ctx_font_count].ctx_fs.path[path_len-1] = 0;
27471   ctx_fonts[ctx_font_count].engine = &ctx_font_engine_ctx_fs;
27472   ctx_font_count++;
27473   return ctx_font_count-1;
27474 }
27475 
27476 #endif
27477 
27478 int
_ctx_glyph(Ctx * ctx,uint32_t unichar,int stroke)27479 _ctx_glyph (Ctx *ctx, uint32_t unichar, int stroke)
27480 {
27481   CtxFont *font = &ctx_fonts[ctx->state.gstate.font];
27482   // a begin-path here did not remove stray spikes in terminal
27483   return font->engine->glyph (font, ctx, unichar, stroke);
27484 }
27485 
27486 int
ctx_glyph(Ctx * ctx,uint32_t unichar,int stroke)27487 ctx_glyph (Ctx *ctx, uint32_t unichar, int stroke)
27488 {
27489 #if CTX_BACKEND_TEXT
27490   CtxEntry commands[3]; // 3 to silence incorrect warning from static analysis
27491   ctx_memset (commands, 0, sizeof (commands) );
27492   commands[0] = ctx_u32 (CTX_GLYPH, unichar, 0);
27493   commands[0].data.u8[4] = stroke;
27494   ctx_process (ctx, commands);
27495   return 0; // XXX is return value used?
27496 #else
27497   return _ctx_glyph (ctx, unichar, stroke);
27498 #endif
27499 }
27500 
27501 float
ctx_glyph_width(Ctx * ctx,int unichar)27502 ctx_glyph_width (Ctx *ctx, int unichar)
27503 {
27504   CtxFont *font = &ctx_fonts[ctx->state.gstate.font];
27505 
27506   return font->engine->glyph_width (font, ctx, unichar);
27507 }
27508 
27509 static float
ctx_glyph_kern(Ctx * ctx,int unicharA,int unicharB)27510 ctx_glyph_kern (Ctx *ctx, int unicharA, int unicharB)
27511 {
27512   CtxFont *font = &ctx_fonts[ctx->state.gstate.font];
27513   return font->engine->glyph_kern (font, ctx, unicharA, unicharB);
27514 }
27515 
27516 float
ctx_text_width(Ctx * ctx,const char * string)27517 ctx_text_width (Ctx        *ctx,
27518                 const char *string)
27519 {
27520   float sum = 0.0;
27521   if (!string)
27522     return 0.0f;
27523   for (const char *utf8 = string; *utf8; utf8 = ctx_utf8_skip (utf8, 1) )
27524     {
27525       sum += ctx_glyph_width (ctx, ctx_utf8_to_unichar (utf8) );
27526     }
27527   return sum;
27528 }
27529 
27530 static void
_ctx_glyphs(Ctx * ctx,CtxGlyph * glyphs,int n_glyphs,int stroke)27531 _ctx_glyphs (Ctx     *ctx,
27532              CtxGlyph *glyphs,
27533              int       n_glyphs,
27534              int       stroke)
27535 {
27536   for (int i = 0; i < n_glyphs; i++)
27537     {
27538       {
27539         uint32_t unichar = glyphs[i].index;
27540         ctx_move_to (ctx, glyphs[i].x, glyphs[i].y);
27541         ctx_glyph (ctx, unichar, stroke);
27542       }
27543     }
27544 }
27545 
27546 static void
_ctx_text(Ctx * ctx,const char * string,int stroke,int visible)27547 _ctx_text (Ctx        *ctx,
27548            const char *string,
27549            int         stroke,
27550            int         visible)
27551 {
27552   CtxState *state = &ctx->state;
27553   float x = ctx->state.x;
27554   switch ( (int) ctx_state_get (state, CTX_text_align) )
27555     //switch (state->gstate.text_align)
27556     {
27557       case CTX_TEXT_ALIGN_START:
27558       case CTX_TEXT_ALIGN_LEFT:
27559         break;
27560       case CTX_TEXT_ALIGN_CENTER:
27561         x -= ctx_text_width (ctx, string) /2;
27562         break;
27563       case CTX_TEXT_ALIGN_END:
27564       case CTX_TEXT_ALIGN_RIGHT:
27565         x -= ctx_text_width (ctx, string);
27566         break;
27567     }
27568   float y = ctx->state.y;
27569   float baseline_offset = 0.0f;
27570   switch ( (int) ctx_state_get (state, CTX_text_baseline) )
27571     {
27572       case CTX_TEXT_BASELINE_HANGING:
27573         /* XXX : crude */
27574         baseline_offset = ctx->state.gstate.font_size  * 0.55;
27575         break;
27576       case CTX_TEXT_BASELINE_TOP:
27577         /* XXX : crude */
27578         baseline_offset = ctx->state.gstate.font_size  * 0.7;
27579         break;
27580       case CTX_TEXT_BASELINE_BOTTOM:
27581         baseline_offset = -ctx->state.gstate.font_size * 0.1;
27582         break;
27583       case CTX_TEXT_BASELINE_ALPHABETIC:
27584       case CTX_TEXT_BASELINE_IDEOGRAPHIC:
27585         baseline_offset = 0.0f;
27586         break;
27587       case CTX_TEXT_BASELINE_MIDDLE:
27588         baseline_offset = ctx->state.gstate.font_size * 0.25;
27589         break;
27590     }
27591   float x0 = x;
27592   for (const char *utf8 = string; *utf8; utf8 = ctx_utf8_skip (utf8, 1) )
27593     {
27594       if (*utf8 == '\n')
27595         {
27596           y += ctx->state.gstate.font_size * ctx_state_get (state, CTX_line_spacing);
27597           x = x0;
27598           if (visible)
27599             { ctx_move_to (ctx, x, y); }
27600         }
27601       else
27602         {
27603           uint32_t unichar = ctx_utf8_to_unichar (utf8);
27604           if (visible)
27605             {
27606               ctx_move_to (ctx, x, y + baseline_offset);
27607               _ctx_glyph (ctx, unichar, stroke);
27608             }
27609           const char *next_utf8 = ctx_utf8_skip (utf8, 1);
27610           if (next_utf8)
27611             {
27612               x += ctx_glyph_width (ctx, unichar);
27613               x += ctx_glyph_kern (ctx, unichar, ctx_utf8_to_unichar (next_utf8) );
27614             }
27615           if (visible)
27616             { ctx_move_to (ctx, x, y); }
27617         }
27618     }
27619   if (!visible)
27620     { ctx_move_to (ctx, x, y); }
27621 }
27622 
27623 
27624 CtxGlyph *
ctx_glyph_allocate(int n_glyphs)27625 ctx_glyph_allocate (int n_glyphs)
27626 {
27627   return (CtxGlyph *) malloc (sizeof (CtxGlyph) * n_glyphs);
27628 }
27629 void
gtx_glyph_free(CtxGlyph * glyphs)27630 gtx_glyph_free     (CtxGlyph *glyphs)
27631 {
27632   free (glyphs);
27633 }
27634 
27635 void
ctx_glyphs(Ctx * ctx,CtxGlyph * glyphs,int n_glyphs)27636 ctx_glyphs (Ctx        *ctx,
27637             CtxGlyph   *glyphs,
27638             int         n_glyphs)
27639 {
27640   _ctx_glyphs (ctx, glyphs, n_glyphs, 0);
27641 }
27642 
27643 void
ctx_glyphs_stroke(Ctx * ctx,CtxGlyph * glyphs,int n_glyphs)27644 ctx_glyphs_stroke (Ctx        *ctx,
27645                    CtxGlyph   *glyphs,
27646                    int         n_glyphs)
27647 {
27648   _ctx_glyphs (ctx, glyphs, n_glyphs, 1);
27649 }
27650 
27651 void
ctx_text(Ctx * ctx,const char * string)27652 ctx_text (Ctx        *ctx,
27653           const char *string)
27654 {
27655   if (!string)
27656     return;
27657 #if CTX_BACKEND_TEXT
27658   ctx_process_cmd_str (ctx, CTX_TEXT, string, 0, 0);
27659   _ctx_text (ctx, string, 0, 0);
27660 #else
27661   _ctx_text (ctx, string, 0, 1);
27662 #endif
27663 }
27664 
27665 
27666 void
ctx_fill_text(Ctx * ctx,const char * string,float x,float y)27667 ctx_fill_text (Ctx *ctx, const char *string,
27668                float x, float y)
27669 {
27670   ctx_move_to (ctx, x, y);
27671   ctx_text (ctx, string);
27672 }
27673 
27674 void
ctx_text_stroke(Ctx * ctx,const char * string)27675 ctx_text_stroke (Ctx        *ctx,
27676                  const char *string)
27677 {
27678   if (!string)
27679     return;
27680 #if CTX_BACKEND_TEXT
27681   ctx_process_cmd_str (ctx, CTX_STROKE_TEXT, string, 0, 0);
27682   _ctx_text (ctx, string, 1, 0);
27683 #else
27684   _ctx_text (ctx, string, 1, 1);
27685 #endif
27686 }
27687 
27688 void
ctx_stroke_text(Ctx * ctx,const char * string,float x,float y)27689 ctx_stroke_text (Ctx *ctx, const char *string,
27690                float x, float y)
27691 {
27692   ctx_move_to (ctx, x, y);
27693   ctx_text_stroke (ctx, string);
27694 }
27695 
_ctx_resolve_font(const char * name)27696 static int _ctx_resolve_font (const char *name)
27697 {
27698   for (int i = 0; i < ctx_font_count; i ++)
27699     {
27700       if (!ctx_strcmp (ctx_fonts[i].name, name) )
27701         { return i; }
27702     }
27703   for (int i = 0; i < ctx_font_count; i ++)
27704     {
27705       if (ctx_strstr (ctx_fonts[i].name, name) )
27706         { return i; }
27707     }
27708   return -1;
27709 }
27710 
ctx_resolve_font(const char * name)27711 int ctx_resolve_font (const char *name)
27712 {
27713   int ret = _ctx_resolve_font (name);
27714   if (ret >= 0)
27715     { return ret; }
27716   if (!ctx_strcmp (name, "regular") )
27717     {
27718       int ret = _ctx_resolve_font ("sans");
27719       if (ret >= 0) { return ret; }
27720       ret = _ctx_resolve_font ("serif");
27721       if (ret >= 0) { return ret; }
27722     }
27723   return 0;
27724 }
27725 
ctx_font_setup(void)27726 static void ctx_font_setup (void)
27727 {
27728   static int initialized = 0;
27729   if (initialized) { return; }
27730   initialized = 1;
27731 #if CTX_FONT_ENGINE_CTX
27732   ctx_font_count = 0; // oddly - this is needed in arduino
27733 
27734 #if CTX_FONT_ENGINE_CTX_FS
27735   ctx_load_font_ctx_fs ("sans-ctx", "/tmp/ctx-regular", 0);
27736 #else
27737 #if CTX_FONT_ascii
27738   ctx_load_font_ctx ("sans-ctx", ctx_font_ascii, sizeof (ctx_font_ascii) );
27739 #endif
27740 #if CTX_FONT_regular
27741   ctx_load_font_ctx ("sans-ctx", ctx_font_regular, sizeof (ctx_font_regular) );
27742 #endif
27743 #endif
27744 
27745 #if CTX_FONT_mono
27746   ctx_load_font_ctx ("mono-ctx", ctx_font_mono, sizeof (ctx_font_mono) );
27747 #endif
27748 #if CTX_FONT_bold
27749   ctx_load_font_ctx ("bold-ctx", ctx_font_bold, sizeof (ctx_font_bold) );
27750 #endif
27751 #if CTX_FONT_italic
27752   ctx_load_font_ctx ("italic-ctx", ctx_font_italic, sizeof (ctx_font_italic) );
27753 #endif
27754 #if CTX_FONT_sans
27755   ctx_load_font_ctx ("sans-ctx", ctx_font_sans, sizeof (ctx_font_sans) );
27756 #endif
27757 #if CTX_FONT_serif
27758   ctx_load_font_ctx ("serif-ctx", ctx_font_serif, sizeof (ctx_font_serif) );
27759 #endif
27760 #if CTX_FONT_symbol
27761   ctx_load_font_ctx ("symbol-ctx", ctx_font_symbol, sizeof (ctx_font_symbol) );
27762 #endif
27763 #if CTX_FONT_emoji
27764   ctx_load_font_ctx ("emoji-ctx", ctx_font_emoji, sizeof (ctx_font_emoji) );
27765 #endif
27766 #endif
27767 
27768 #if NOTO_EMOJI_REGULAR
27769   ctx_load_font_ttf ("sans-NotoEmoji_Regular", ttf_NotoEmoji_Regular_ttf, ttf_NotoEmoji_Regular_ttf_len);
27770 #endif
27771 #if ROBOTO_LIGHT
27772   ctx_load_font_ttf ("sans-light-Roboto_Light", ttf_Roboto_Light_ttf, ttf_Roboto_Light_ttf_len);
27773 #endif
27774 #if ROBOTO_REGULAR
27775   ctx_load_font_ttf ("sans-Roboto_Regular", ttf_Roboto_Regular_ttf, ttf_Roboto_Regular_ttf_len);
27776 #endif
27777 #if ROBOTO_BOLD
27778   ctx_load_font_ttf ("sans-bold-Roboto_Bold", ttf_Roboto_Bold_ttf, ttf_Roboto_Bold_ttf_len);
27779 #endif
27780 #if DEJAVU_SANS
27781   ctx_load_font_ttf ("sans-DejaVuSans", ttf_DejaVuSans_ttf, ttf_DejaVuSans_ttf_len);
27782 #endif
27783 #if VERA
27784   ctx_load_font_ttf ("sans-Vera", ttf_Vera_ttf, ttf_Vera_ttf_len);
27785 #endif
27786 #if UNSCII_16
27787   ctx_load_font_ttf ("mono-unscii16", ttf_unscii_16_ttf, ttf_unscii_16_ttf_len);
27788 #endif
27789 #if XA000_MONO
27790   ctx_load_font_ttf ("mono-0xA000", ttf_0xA000_Mono_ttf, ttf_0xA000_Mono_ttf_len);
27791 #endif
27792 #if DEJAVU_SANS_MONO
27793   ctx_load_font_ttf ("mono-DejaVuSansMono", ttf_DejaVuSansMono_ttf, ttf_DejaVuSansMono_ttf_len);
27794 #endif
27795 #if NOTO_MONO_REGULAR
27796   ctx_load_font_ttf ("mono-NotoMono_Regular", ttf_NotoMono_Regular_ttf, ttf_NotoMono_Regular_ttf_len);
27797 #endif
27798 }
27799 
27800 
27801 
27802 #if !__COSMOPOLITAN__
27803 #include <stdarg.h>
27804 #include <stdio.h>
27805 #include <stdlib.h>
27806 #include <string.h>
27807 #endif
27808 
27809 //#include "ctx.h"
27810 /* instead of including ctx.h we declare the few utf8
27811  * functions we use
27812  */
27813 uint32_t ctx_utf8_to_unichar (const char *input);
27814 int ctx_unichar_to_utf8 (uint32_t  ch, uint8_t  *dest);
27815 int ctx_utf8_strlen (const char *s);
27816 
ctx_string_init(CtxString * string,int initial_size)27817 static void ctx_string_init (CtxString *string, int initial_size)
27818 {
27819   string->allocated_length = initial_size;
27820   string->length = 0;
27821   string->utf8_length = 0;
27822   string->str = (char*)malloc (string->allocated_length + 1);
27823   string->str[0]='\0';
27824 }
27825 
ctx_string_destroy(CtxString * string)27826 static void ctx_string_destroy (CtxString *string)
27827 {
27828   if (string->str)
27829     {
27830       free (string->str);
27831       string->str = NULL;
27832     }
27833 }
27834 
ctx_string_clear(CtxString * string)27835 void ctx_string_clear (CtxString *string)
27836 {
27837   string->length = 0;
27838   string->utf8_length = 0;
27839   string->str[string->length]=0;
27840 }
27841 
27842 
ctx_string_pre_alloc(CtxString * string,int size)27843 void ctx_string_pre_alloc (CtxString *string, int size)
27844 {
27845   char *old = string->str;
27846   string->allocated_length = CTX_MAX (size + 2, string->length + 2);
27847   string->str = (char*)realloc (old, string->allocated_length);
27848 }
27849 
27850 
_ctx_string_append_byte(CtxString * string,char val)27851 static inline void _ctx_string_append_byte (CtxString *string, char  val)
27852 {
27853   if (CTX_LIKELY((val & 0xC0) != 0x80))
27854     { string->utf8_length++; }
27855   if (CTX_UNLIKELY(string->length + 2 >= string->allocated_length))
27856     {
27857       char *old = string->str;
27858       string->allocated_length = CTX_MAX (string->allocated_length * 2, string->length + 2);
27859       string->str = (char*)realloc (old, string->allocated_length);
27860     }
27861   string->str[string->length++] = val;
27862   string->str[string->length] = '\0';
27863 }
27864 
ctx_string_append_byte(CtxString * string,char val)27865 void ctx_string_append_byte (CtxString *string, char  val)
27866 {
27867   _ctx_string_append_byte (string, val);
27868 }
27869 
ctx_string_append_unichar(CtxString * string,unsigned int unichar)27870 void ctx_string_append_unichar (CtxString *string, unsigned int unichar)
27871 {
27872   char *str;
27873   char utf8[5];
27874   utf8[ctx_unichar_to_utf8 (unichar, (unsigned char *) utf8)]=0;
27875   str = utf8;
27876   while (str && *str)
27877     {
27878       _ctx_string_append_byte (string, *str);
27879       str++;
27880     }
27881 }
27882 
_ctx_string_append_str(CtxString * string,const char * str)27883 static inline void _ctx_string_append_str (CtxString *string, const char *str)
27884 {
27885   if (!str) { return; }
27886   while (*str)
27887     {
27888       _ctx_string_append_byte (string, *str);
27889       str++;
27890     }
27891 }
27892 
ctx_string_append_utf8char(CtxString * string,const char * str)27893 void ctx_string_append_utf8char (CtxString *string, const char *str)
27894 {
27895   if (!str) { return; }
27896   int len = ctx_utf8_len (*str);
27897   for (int i = 0; i < len && *str; i++)
27898     {
27899       _ctx_string_append_byte (string, *str);
27900       str++;
27901     }
27902 }
27903 
ctx_string_append_str(CtxString * string,const char * str)27904 void ctx_string_append_str (CtxString *string, const char *str)
27905 {
27906   _ctx_string_append_str (string, str);
27907 }
27908 
ctx_string_new_with_size(const char * initial,int initial_size)27909 CtxString *ctx_string_new_with_size (const char *initial, int initial_size)
27910 {
27911   CtxString *string = (CtxString*)ctx_calloc (sizeof (CtxString), 1);
27912   ctx_string_init (string, initial_size);
27913   if (initial)
27914     { _ctx_string_append_str (string, initial); }
27915   return string;
27916 }
27917 
ctx_string_new(const char * initial)27918 CtxString *ctx_string_new (const char *initial)
27919 {
27920   return ctx_string_new_with_size (initial, 8);
27921 }
27922 
ctx_string_append_data(CtxString * string,const char * str,int len)27923 void ctx_string_append_data (CtxString *string, const char *str, int len)
27924 {
27925   int i;
27926   for (i = 0; i<len; i++)
27927     { _ctx_string_append_byte (string, str[i]); }
27928 }
27929 
ctx_string_append_string(CtxString * string,CtxString * string2)27930 void ctx_string_append_string (CtxString *string, CtxString *string2)
27931 {
27932   const char *str = ctx_string_get (string2);
27933   while (str && *str)
27934     {
27935       _ctx_string_append_byte (string, *str);
27936       str++;
27937     }
27938 }
27939 
ctx_string_get(CtxString * string)27940 const char *ctx_string_get (CtxString *string)
27941 {
27942   return string->str;
27943 }
27944 
ctx_string_get_utf8length(CtxString * string)27945 int ctx_string_get_utf8length (CtxString *string)
27946 {
27947   return string->utf8_length;
27948 }
27949 
ctx_string_get_length(CtxString * string)27950 int ctx_string_get_length (CtxString *string)
27951 {
27952   return string->length;
27953 }
27954 
27955 void
ctx_string_free(CtxString * string,int freealloc)27956 ctx_string_free (CtxString *string, int freealloc)
27957 {
27958   if (freealloc)
27959     {
27960       ctx_string_destroy (string);
27961     }
27962 #if 0
27963   if (string->is_line)
27964   {
27965     VtLine *line = (VtLine*)string;
27966     if (line->style)
27967       { free (line->style); }
27968     if (line->ctx)
27969       { ctx_free (line->ctx); }
27970     if (line->ctx_copy)
27971       { ctx_free (line->ctx_copy); }
27972   }
27973 #endif
27974   free (string);
27975 }
27976 
ctx_string_dissolve(CtxString * string)27977 char       *ctx_string_dissolve       (CtxString *string)
27978 {
27979   char *ret = string->str;
27980   ctx_string_free (string, 0);
27981   return ret;
27982 }
27983 
27984 void
ctx_string_set(CtxString * string,const char * new_string)27985 ctx_string_set (CtxString *string, const char *new_string)
27986 {
27987   ctx_string_clear (string);
27988   _ctx_string_append_str (string, new_string);
27989 }
27990 
ctx_strdup(const char * str)27991 static char *ctx_strdup (const char *str)
27992 {
27993   int len = strlen (str);
27994   char *ret = (char*)malloc (len + 1);
27995   memcpy (ret, str, len);
27996   ret[len]=0;
27997   return ret;
27998 }
27999 
ctx_string_replace_utf8(CtxString * string,int pos,const char * new_glyph)28000 void ctx_string_replace_utf8 (CtxString *string, int pos, const char *new_glyph)
28001 {
28002 #if 1
28003   int old_len = string->utf8_length;
28004 #else
28005   int old_len = ctx_utf8_strlen (string->str);// string->utf8_length;
28006 #endif
28007   if (CTX_LIKELY(pos == old_len))
28008     {
28009       _ctx_string_append_str (string, new_glyph);
28010       return;
28011     }
28012 
28013   char tmpg[3]=" ";
28014   int new_len = ctx_utf8_len (*new_glyph);
28015   if (new_len <= 1 && new_glyph[0] < 32)
28016     {
28017       new_len = 1;
28018       tmpg[0]=new_glyph[0]+64;
28019       new_glyph = tmpg;
28020     }
28021   {
28022     for (int i = old_len; i <= pos + 2; i++)
28023       {
28024         _ctx_string_append_byte (string, ' ');
28025         old_len++;
28026       }
28027   }
28028   if (string->length + new_len  >= string->allocated_length - 2)
28029     {
28030       char *tmp;
28031       char *defer;
28032       string->allocated_length = string->length + new_len + 2;
28033       tmp = (char*) ctx_calloc (string->allocated_length + 1 + 8, 1);
28034       strcpy (tmp, string->str);
28035       defer = string->str;
28036       string->str = tmp;
28037       free (defer);
28038     }
28039   char *p = (char *) ctx_utf8_skip (string->str, pos);
28040   int prev_len = ctx_utf8_len (*p);
28041   char *rest;
28042   if (*p == 0 || * (p+prev_len) == 0)
28043     {
28044       rest = ctx_strdup ("");
28045     }
28046   else
28047     {
28048       if (p + prev_len >= string->length  + string->str)
28049         { rest = ctx_strdup (""); }
28050       else
28051         { rest = ctx_strdup (p + prev_len); }
28052     }
28053   memcpy (p, new_glyph, new_len);
28054   memcpy (p + new_len, rest, strlen (rest) + 1);
28055   string->length += new_len;
28056   string->length -= prev_len;
28057   free (rest);
28058   //string->length = strlen (string->str);
28059   //string->utf8_length = ctx_utf8_strlen (string->str);
28060 }
28061 
ctx_string_replace_unichar(CtxString * string,int pos,uint32_t unichar)28062 void ctx_string_replace_unichar (CtxString *string, int pos, uint32_t unichar)
28063 {
28064   uint8_t utf8[8];
28065   ctx_unichar_to_utf8 (unichar, utf8);
28066   ctx_string_replace_utf8 (string, pos, (char *) utf8);
28067 }
28068 
ctx_string_get_unichar(CtxString * string,int pos)28069 uint32_t ctx_string_get_unichar (CtxString *string, int pos)
28070 {
28071   char *p = (char *) ctx_utf8_skip (string->str, pos);
28072   if (!p)
28073     { return 0; }
28074   return ctx_utf8_to_unichar (p);
28075 }
28076 
ctx_string_insert_utf8(CtxString * string,int pos,const char * new_glyph)28077 void ctx_string_insert_utf8 (CtxString *string, int pos, const char *new_glyph)
28078 {
28079   int new_len = ctx_utf8_len (*new_glyph);
28080   int old_len = string->utf8_length;
28081   char tmpg[3]=" ";
28082   if (old_len == pos && 0)
28083     {
28084       ctx_string_append_str (string, new_glyph);
28085       return;
28086     }
28087   if (new_len <= 1 && new_glyph[0] < 32)
28088     {
28089       tmpg[0]=new_glyph[0]+64;
28090       new_glyph = tmpg;
28091     }
28092   {
28093     for (int i = old_len; i <= pos; i++)
28094       {
28095         _ctx_string_append_byte (string, ' ');
28096         old_len++;
28097       }
28098   }
28099   if (string->length + new_len + 1  > string->allocated_length)
28100     {
28101       char *tmp;
28102       char *defer;
28103       string->allocated_length = string->length + new_len + 1;
28104       tmp = (char*) ctx_calloc (string->allocated_length + 1, 1);
28105       strcpy (tmp, string->str);
28106       defer = string->str;
28107       string->str = tmp;
28108       free (defer);
28109     }
28110   char *p = (char *) ctx_utf8_skip (string->str, pos);
28111   int prev_len = ctx_utf8_len (*p);
28112   char *rest;
28113   if ( (*p == 0 || * (p+prev_len) == 0) && pos != 0)
28114     {
28115       rest = ctx_strdup ("");
28116     }
28117   else
28118     {
28119       rest = ctx_strdup (p);
28120     }
28121   memcpy (p, new_glyph, new_len);
28122   memcpy (p + new_len, rest, strlen (rest) + 1);
28123   free (rest);
28124   string->length = strlen (string->str);
28125   string->utf8_length = ctx_utf8_strlen (string->str);
28126 }
28127 
ctx_string_insert_unichar(CtxString * string,int pos,uint32_t unichar)28128 void ctx_string_insert_unichar (CtxString *string, int pos, uint32_t unichar)
28129 {
28130   uint8_t utf8[5]="";
28131   utf8[ctx_unichar_to_utf8(unichar, utf8)]=0;
28132   ctx_string_insert_utf8 (string, pos, (char*)utf8);
28133 }
28134 
ctx_string_remove(CtxString * string,int pos)28135 void ctx_string_remove (CtxString *string, int pos)
28136 {
28137   int old_len = string->utf8_length;
28138   {
28139     for (int i = old_len; i <= pos; i++)
28140       {
28141         _ctx_string_append_byte (string, ' ');
28142         old_len++;
28143       }
28144   }
28145   char *p = (char *) ctx_utf8_skip (string->str, pos);
28146   int prev_len = ctx_utf8_len (*p);
28147   char *rest;
28148   if (!p || *p == 0)
28149     {
28150       return;
28151       rest = ctx_strdup ("");
28152       prev_len = 0;
28153     }
28154   else if (* (p+prev_len) == 0)
28155   {
28156       rest = ctx_strdup ("");
28157   }
28158   else
28159     {
28160       rest = ctx_strdup (p + prev_len);
28161     }
28162   strcpy (p, rest);
28163   string->str[string->length - prev_len] = 0;
28164   free (rest);
28165   string->length = strlen (string->str);
28166   string->utf8_length = ctx_utf8_strlen (string->str);
28167 }
28168 
ctx_strdup_printf(const char * format,...)28169 char *ctx_strdup_printf (const char *format, ...)
28170 {
28171   va_list ap;
28172   size_t needed;
28173   char *buffer;
28174   va_start (ap, format);
28175   needed = vsnprintf (NULL, 0, format, ap) + 1;
28176   buffer = (char*)malloc (needed);
28177   va_end (ap);
28178   va_start (ap, format);
28179   vsnprintf (buffer, needed, format, ap);
28180   va_end (ap);
28181   return buffer;
28182 }
28183 
ctx_string_append_printf(CtxString * string,const char * format,...)28184 void ctx_string_append_printf (CtxString *string, const char *format, ...)
28185 {
28186   va_list ap;
28187   size_t needed;
28188   char *buffer;
28189   va_start (ap, format);
28190   needed = vsnprintf (NULL, 0, format, ap) + 1;
28191   buffer = (char*)malloc (needed);
28192   va_end (ap);
28193   va_start (ap, format);
28194   vsnprintf (buffer, needed, format, ap);
28195   va_end (ap);
28196   ctx_string_append_str (string, buffer);
28197   free (buffer);
28198 }
28199 
ctx_string_new_printf(const char * format,...)28200 CtxString *ctx_string_new_printf (const char *format, ...)
28201 {
28202   CtxString *string = ctx_string_new ("");
28203   va_list ap;
28204   size_t needed;
28205   char *buffer;
28206   va_start (ap, format);
28207   needed = vsnprintf (NULL, 0, format, ap) + 1;
28208   buffer = (char*)malloc (needed);
28209   va_end (ap);
28210   va_start (ap, format);
28211   vsnprintf (buffer, needed, format, ap);
28212   va_end (ap);
28213   ctx_string_append_str (string, buffer);
28214   free (buffer);
28215   return string;
28216 }
28217 
28218 #if CTX_CAIRO
28219 
28220 typedef struct _CtxCairo CtxCairo;
28221 struct
28222   _CtxCairo
28223 {
28224   CtxImplementation vfuncs;
28225   Ctx              *ctx;
28226   cairo_t          *cr;
28227   cairo_pattern_t  *pat;
28228   cairo_surface_t  *image;
28229   int               preserve;
28230 };
28231 
28232 static void
ctx_cairo_process(CtxCairo * ctx_cairo,CtxCommand * c)28233 ctx_cairo_process (CtxCairo *ctx_cairo, CtxCommand *c)
28234 {
28235   CtxEntry *entry = (CtxEntry *) &c->entry;
28236   cairo_t *cr = ctx_cairo->cr;
28237   switch (entry->code)
28238     {
28239       case CTX_LINE_TO:
28240         cairo_line_to (cr, c->line_to.x, c->line_to.y);
28241         break;
28242       case CTX_REL_LINE_TO:
28243         cairo_rel_line_to (cr, c->rel_line_to.x, c->rel_line_to.y);
28244         break;
28245       case CTX_MOVE_TO:
28246         cairo_move_to (cr, c->move_to.x, c->move_to.y);
28247         break;
28248       case CTX_REL_MOVE_TO:
28249         cairo_rel_move_to (cr, ctx_arg_float (0), ctx_arg_float (1) );
28250         break;
28251       case CTX_CURVE_TO:
28252         cairo_curve_to (cr, ctx_arg_float (0), ctx_arg_float (1),
28253                         ctx_arg_float (2), ctx_arg_float (3),
28254                         ctx_arg_float (4), ctx_arg_float (5) );
28255         break;
28256       case CTX_REL_CURVE_TO:
28257         cairo_rel_curve_to (cr,ctx_arg_float (0), ctx_arg_float (1),
28258                             ctx_arg_float (2), ctx_arg_float (3),
28259                             ctx_arg_float (4), ctx_arg_float (5) );
28260         break;
28261       case CTX_PRESERVE:
28262         ctx_cairo->preserve = 1;
28263         break;
28264       case CTX_QUAD_TO:
28265         {
28266           double x0, y0;
28267           cairo_get_current_point (cr, &x0, &y0);
28268           float cx = ctx_arg_float (0);
28269           float cy = ctx_arg_float (1);
28270           float  x = ctx_arg_float (2);
28271           float  y = ctx_arg_float (3);
28272           cairo_curve_to (cr,
28273                           (cx * 2 + x0) / 3.0f, (cy * 2 + y0) / 3.0f,
28274                           (cx * 2 + x) / 3.0f,           (cy * 2 + y) / 3.0f,
28275                           x,                              y);
28276         }
28277         break;
28278       case CTX_REL_QUAD_TO:
28279         {
28280           double x0, y0;
28281           cairo_get_current_point (cr, &x0, &y0);
28282           float cx = ctx_arg_float (0) + x0;
28283           float cy = ctx_arg_float (1) + y0;
28284           float  x = ctx_arg_float (2) + x0;
28285           float  y = ctx_arg_float (3) + y0;
28286           cairo_curve_to (cr,
28287                           (cx * 2 + x0) / 3.0f, (cy * 2 + y0) / 3.0f,
28288                           (cx * 2 + x) / 3.0f,           (cy * 2 + y) / 3.0f,
28289                           x,                              y);
28290         }
28291         break;
28292       /* rotate/scale/translate does not occur in fully minified data stream */
28293       case CTX_ROTATE:
28294         cairo_rotate (cr, ctx_arg_float (0) );
28295         break;
28296       case CTX_SCALE:
28297         cairo_scale (cr, ctx_arg_float (0), ctx_arg_float (1) );
28298         break;
28299       case CTX_TRANSLATE:
28300         cairo_translate (cr, ctx_arg_float (0), ctx_arg_float (1) );
28301         break;
28302       case CTX_LINE_WIDTH:
28303         cairo_set_line_width (cr, ctx_arg_float (0) );
28304         break;
28305       case CTX_ARC:
28306 #if 0
28307         fprintf (stderr, "F %2.1f %2.1f %2.1f %2.1f %2.1f %2.1f\n",
28308                         ctx_arg_float(0),
28309                         ctx_arg_float(1),
28310                         ctx_arg_float(2),
28311                         ctx_arg_float(3),
28312                         ctx_arg_float(4),
28313                         ctx_arg_float(5),
28314                         ctx_arg_float(6));
28315 #endif
28316         if (ctx_arg_float (5) == 1)
28317           cairo_arc (cr, ctx_arg_float (0), ctx_arg_float (1),
28318                      ctx_arg_float (2), ctx_arg_float (3),
28319                      ctx_arg_float (4) );
28320         else
28321           cairo_arc_negative (cr, ctx_arg_float (0), ctx_arg_float (1),
28322                               ctx_arg_float (2), ctx_arg_float (3),
28323                               ctx_arg_float (4) );
28324         break;
28325       case CTX_SET_RGBA_U8:
28326         cairo_set_source_rgba (cr, ctx_u8_to_float (ctx_arg_u8 (0) ),
28327                                ctx_u8_to_float (ctx_arg_u8 (1) ),
28328                                ctx_u8_to_float (ctx_arg_u8 (2) ),
28329                                ctx_u8_to_float (ctx_arg_u8 (3) ) );
28330         break;
28331 #if 0
28332       case CTX_SET_RGBA_STROKE: // XXX : we need to maintain
28333         //       state for the two kinds
28334         cairo_set_source_rgba (cr, ctx_arg_u8 (0) /255.0,
28335                                ctx_arg_u8 (1) /255.0,
28336                                ctx_arg_u8 (2) /255.0,
28337                                ctx_arg_u8 (3) /255.0);
28338         break;
28339 #endif
28340       case CTX_RECTANGLE:
28341       case CTX_ROUND_RECTANGLE: // XXX - arcs
28342         cairo_rectangle (cr, c->rectangle.x, c->rectangle.y,
28343                          c->rectangle.width, c->rectangle.height);
28344         break;
28345       case CTX_SET_PIXEL:
28346         cairo_set_source_rgba (cr, ctx_u8_to_float (ctx_arg_u8 (0) ),
28347                                ctx_u8_to_float (ctx_arg_u8 (1) ),
28348                                ctx_u8_to_float (ctx_arg_u8 (2) ),
28349                                ctx_u8_to_float (ctx_arg_u8 (3) ) );
28350         cairo_rectangle (cr, ctx_arg_u16 (2), ctx_arg_u16 (3), 1, 1);
28351         cairo_fill (cr);
28352         break;
28353       case CTX_FILL:
28354         if (ctx_cairo->preserve)
28355         {
28356           cairo_fill_preserve (cr);
28357           ctx_cairo->preserve = 0;
28358         }
28359         else
28360         {
28361           cairo_fill (cr);
28362         }
28363         break;
28364       case CTX_STROKE:
28365         if (ctx_cairo->preserve)
28366         {
28367           cairo_stroke_preserve (cr);
28368           ctx_cairo->preserve = 0;
28369         }
28370         else
28371         {
28372           cairo_stroke (cr);
28373         }
28374         break;
28375       case CTX_IDENTITY:
28376         cairo_identity_matrix (cr);
28377         break;
28378       case CTX_CLIP:
28379         if (ctx_cairo->preserve)
28380         {
28381           cairo_clip_preserve (cr);
28382           ctx_cairo->preserve = 0;
28383         }
28384         else
28385         {
28386           cairo_clip (cr);
28387         }
28388         break;
28389         break;
28390       case CTX_BEGIN_PATH:
28391         cairo_new_path (cr);
28392         break;
28393       case CTX_CLOSE_PATH:
28394         cairo_close_path (cr);
28395         break;
28396       case CTX_SAVE:
28397         cairo_save (cr);
28398         break;
28399       case CTX_RESTORE:
28400         cairo_restore (cr);
28401         break;
28402       case CTX_FONT_SIZE:
28403         cairo_set_font_size (cr, ctx_arg_float (0) );
28404         break;
28405       case CTX_MITER_LIMIT:
28406         cairo_set_miter_limit (cr, ctx_arg_float (0) );
28407         break;
28408       case CTX_LINE_CAP:
28409         {
28410           int cairo_val = CAIRO_LINE_CAP_SQUARE;
28411           switch (ctx_arg_u8 (0) )
28412             {
28413               case CTX_CAP_ROUND:
28414                 cairo_val = CAIRO_LINE_CAP_ROUND;
28415                 break;
28416               case CTX_CAP_SQUARE:
28417                 cairo_val = CAIRO_LINE_CAP_SQUARE;
28418                 break;
28419               case CTX_CAP_NONE:
28420                 cairo_val = CAIRO_LINE_CAP_BUTT;
28421                 break;
28422             }
28423           cairo_set_line_cap (cr, cairo_val);
28424         }
28425         break;
28426       case CTX_BLEND_MODE:
28427         {
28428           // does not map to cairo
28429         }
28430         break;
28431       case CTX_COMPOSITING_MODE:
28432         {
28433           int cairo_val = CAIRO_OPERATOR_OVER;
28434           switch (ctx_arg_u8 (0) )
28435             {
28436               case CTX_COMPOSITE_SOURCE_OVER:
28437                 cairo_val = CAIRO_OPERATOR_OVER;
28438                 break;
28439               case CTX_COMPOSITE_COPY:
28440                 cairo_val = CAIRO_OPERATOR_SOURCE;
28441                 break;
28442             }
28443           cairo_set_operator (cr, cairo_val);
28444         }
28445         break;
28446       case CTX_LINE_JOIN:
28447         {
28448           int cairo_val = CAIRO_LINE_JOIN_ROUND;
28449           switch (ctx_arg_u8 (0) )
28450             {
28451               case CTX_JOIN_ROUND:
28452                 cairo_val = CAIRO_LINE_JOIN_ROUND;
28453                 break;
28454               case CTX_JOIN_BEVEL:
28455                 cairo_val = CAIRO_LINE_JOIN_BEVEL;
28456                 break;
28457               case CTX_JOIN_MITER:
28458                 cairo_val = CAIRO_LINE_JOIN_MITER;
28459                 break;
28460             }
28461           cairo_set_line_join (cr, cairo_val);
28462         }
28463         break;
28464       case CTX_LINEAR_GRADIENT:
28465         {
28466           if (ctx_cairo->pat)
28467             {
28468               cairo_pattern_destroy (ctx_cairo->pat);
28469               ctx_cairo->pat = NULL;
28470             }
28471           ctx_cairo->pat = cairo_pattern_create_linear (ctx_arg_float (0), ctx_arg_float (1),
28472                            ctx_arg_float (2), ctx_arg_float (3) );
28473           cairo_pattern_add_color_stop_rgba (ctx_cairo->pat, 0, 0, 0, 0, 1);
28474           cairo_pattern_add_color_stop_rgba (ctx_cairo->pat, 1, 1, 1, 1, 1);
28475           cairo_set_source (cr, ctx_cairo->pat);
28476         }
28477         break;
28478       case CTX_RADIAL_GRADIENT:
28479         {
28480           if (ctx_cairo->pat)
28481             {
28482               cairo_pattern_destroy (ctx_cairo->pat);
28483               ctx_cairo->pat = NULL;
28484             }
28485           ctx_cairo->pat = cairo_pattern_create_radial (ctx_arg_float (0), ctx_arg_float (1),
28486                            ctx_arg_float (2), ctx_arg_float (3),
28487                            ctx_arg_float (4), ctx_arg_float (5) );
28488           cairo_set_source (cr, ctx_cairo->pat);
28489         }
28490         break;
28491       case CTX_GRADIENT_STOP:
28492         cairo_pattern_add_color_stop_rgba (ctx_cairo->pat,
28493                                            ctx_arg_float (0),
28494                                            ctx_u8_to_float (ctx_arg_u8 (4) ),
28495                                            ctx_u8_to_float (ctx_arg_u8 (5) ),
28496                                            ctx_u8_to_float (ctx_arg_u8 (6) ),
28497                                            ctx_u8_to_float (ctx_arg_u8 (7) ) );
28498         break;
28499         // XXX  implement TEXTURE
28500 #if 0
28501       case CTX_LOAD_IMAGE:
28502         {
28503           if (image)
28504             {
28505               cairo_surface_destroy (image);
28506               image = NULL;
28507             }
28508           if (pat)
28509             {
28510               cairo_pattern_destroy (pat);
28511               pat = NULL;
28512             }
28513           image = cairo_image_surface_create_from_png (ctx_arg_string() );
28514           cairo_set_source_surface (cr, image, ctx_arg_float (0), ctx_arg_float (1) );
28515         }
28516         break;
28517 #endif
28518       case CTX_TEXT:
28519         /* XXX: implement some linebreaking/wrap, positioning
28520          *      behavior here?
28521          */
28522         cairo_show_text (cr, ctx_arg_string () );
28523         break;
28524       case CTX_CONT:
28525       case CTX_EDGE:
28526       case CTX_DATA:
28527       case CTX_DATA_REV:
28528       case CTX_FLUSH:
28529         break;
28530     }
28531   ctx_process (ctx_cairo->ctx, entry);
28532 }
28533 
ctx_cairo_free(CtxCairo * ctx_cairo)28534 void ctx_cairo_free (CtxCairo *ctx_cairo)
28535 {
28536   if (ctx_cairo->pat)
28537     { cairo_pattern_destroy (ctx_cairo->pat); }
28538   if (ctx_cairo->image)
28539     { cairo_surface_destroy (ctx_cairo->image); }
28540   free (ctx_cairo);
28541 }
28542 
28543 void
ctx_render_cairo(Ctx * ctx,cairo_t * cr)28544 ctx_render_cairo (Ctx *ctx, cairo_t *cr)
28545 {
28546   CtxIterator iterator;
28547   CtxCommand *command;
28548   CtxCairo    ctx_cairo = {{(void*)ctx_cairo_process, NULL, NULL}, ctx, cr, NULL, NULL};
28549   ctx_iterator_init (&iterator, &ctx->drawlist, 0,
28550                      CTX_ITERATOR_EXPAND_BITPACK);
28551   while ( (command = ctx_iterator_next (&iterator) ) )
28552     { ctx_cairo_process (&ctx_cairo, command); }
28553 }
28554 
28555 Ctx *
ctx_new_for_cairo(cairo_t * cr)28556 ctx_new_for_cairo (cairo_t *cr)
28557 {
28558   Ctx *ctx = ctx_new ();
28559   CtxCairo *ctx_cairo = calloc(sizeof(CtxCairo),1);
28560   ctx_cairo->vfuncs.free = (void*)ctx_cairo_free;
28561   ctx_cairo->vfuncs.process = (void*)ctx_cairo_process;
28562   ctx_cairo->ctx = ctx;
28563   ctx_cairo->cr = cr;
28564 
28565   ctx_set_renderer (ctx, (void*)ctx_cairo);
28566   return ctx;
28567 }
28568 
28569 #endif
28570 
28571 #if CTX_EVENTS
28572 
ctx_find_largest_matching_substring(const char * X,const char * Y,int m,int n,int * offsetY,int * offsetX)28573 static int ctx_find_largest_matching_substring
28574  (const char *X, const char *Y, int m, int n, int *offsetY, int *offsetX)
28575 {
28576   int longest_common_suffix[2][n+1];
28577   int best_length = 0;
28578   for (int i=0; i<=m; i++)
28579   {
28580     for (int j=0; j<=n; j++)
28581     {
28582       if (i == 0 || j == 0 || !(X[i-1] == Y[j-1]))
28583       {
28584         longest_common_suffix[i%2][j] = 0;
28585       }
28586       else
28587       {
28588           longest_common_suffix[i%2][j] = longest_common_suffix[(i-1)%2][j-1] + 1;
28589           if (best_length < longest_common_suffix[i%2][j])
28590           {
28591             best_length = longest_common_suffix[i%2][j];
28592             if (offsetY) *offsetY = j - best_length;
28593             if (offsetX) *offsetX = i - best_length;
28594           }
28595       }
28596     }
28597   }
28598   return best_length;
28599 }
28600 
28601 typedef struct CtxSpan {
28602   int from_prev;
28603   int start;
28604   int length;
28605 } CtxSpan;
28606 
28607 #define CHUNK_SIZE 32
28608 #define MIN_MATCH  7        // minimum match length to be encoded
28609 #define WINDOW_PADDING 16   // look-aside amount
28610 
28611 #if 0
28612 static void _dassert(int line, int condition, const char *str, int foo, int bar, int baz)
28613 {
28614   if (!condition)
28615   {
28616     FILE *f = fopen ("/tmp/cdebug", "a");
28617     fprintf (f, "%i: %s    %i %i %i\n", line, str, foo, bar, baz);
28618     fclose (f);
28619   }
28620 }
28621 #define dassert(cond, foo, bar, baz) _dassert(__LINE__, cond, #cond, foo, bar ,baz)
28622 #endif
28623 #define dassert(cond, foo, bar, baz)
28624 
28625 /* XXX repeated substring matching is slow, we'll be
28626  * better off with a hash-table with linked lists of
28627  * matching 3-4 characters in previous.. or even
28628  * a naive approach that expects rough alignment..
28629  */
encode_in_terms_of_previous(const char * src,int src_len,const char * prev,int prev_len,int * out_len,int max_ticks)28630 static char *encode_in_terms_of_previous (
28631                 const char *src,  int src_len,
28632                 const char *prev, int prev_len,
28633                 int *out_len,
28634                 int max_ticks)
28635 {
28636   CtxString *string = ctx_string_new ("");
28637   CtxList *encoded_list = NULL;
28638 
28639   /* TODO : make expected position offset in prev slide based on
28640    * matches and not be constant */
28641 
28642   long ticks_start = ctx_ticks ();
28643   int start = 0;
28644   int length = CHUNK_SIZE;
28645   for (start = 0; start < src_len; start += length)
28646   {
28647     CtxSpan *span = calloc (sizeof (CtxSpan), 1);
28648     span->start = start;
28649     if (start + length > src_len)
28650       span->length = src_len - start;
28651     else
28652       span->length = length;
28653     span->from_prev = 0;
28654     ctx_list_append (&encoded_list, span);
28655   }
28656 
28657   for (CtxList *l = encoded_list; l; l = l->next)
28658   {
28659     CtxSpan *span = l->data;
28660     if (!span->from_prev)
28661     {
28662       if (span->length >= MIN_MATCH)
28663       {
28664          int prev_pos = 0;
28665          int curr_pos = 0;
28666          assert(1);
28667 #if 0
28668          int prev_start =  0;
28669          int prev_window_length = prev_len;
28670 #else
28671          int window_padding = WINDOW_PADDING;
28672          int prev_start = span->start - window_padding;
28673          if (prev_start < 0)
28674            prev_start = 0;
28675 
28676          dassert(span->start>=0 , 0,0,0);
28677 
28678          int prev_window_length = prev_len - prev_start;
28679          if (prev_window_length > span->length + window_padding * 2 + span->start)
28680            prev_window_length = span->length + window_padding * 2 + span->start;
28681 #endif
28682          int match_len = 0;
28683          if (prev_window_length > 0)
28684            match_len = ctx_find_largest_matching_substring(prev + prev_start, src + span->start, prev_window_length, span->length, &curr_pos, &prev_pos);
28685 #if 1
28686          prev_pos += prev_start;
28687 #endif
28688 
28689          if (match_len >= MIN_MATCH)
28690          {
28691             int start  = span->start;
28692             int length = span->length;
28693 
28694             span->from_prev = 1;
28695             span->start     = prev_pos;
28696             span->length    = match_len;
28697             dassert (span->start >= 0, prev_pos, prev_start, span->start);
28698             dassert (span->length > 0, prev_pos, prev_start, span->length);
28699 
28700             if (curr_pos)
28701             {
28702               CtxSpan *prev = calloc (sizeof (CtxSpan), 1);
28703               prev->start = start;
28704               prev->length =  curr_pos;
28705             dassert (prev->start >= 0, prev_pos, prev_start, prev->start);
28706             dassert (prev->length > 0, prev_pos, prev_start, prev->length);
28707               prev->from_prev = 0;
28708               ctx_list_insert_before (&encoded_list, l, prev);
28709             }
28710 
28711 
28712             if (match_len + curr_pos < start + length)
28713             {
28714               CtxSpan *next = calloc (sizeof (CtxSpan), 1);
28715               next->start = start + curr_pos + match_len;
28716               next->length = (start + length) - next->start;
28717             dassert (next->start >= 0, prev_pos, prev_start, next->start);
28718       //    dassert (next->length > 0, prev_pos, prev_start, next->length);
28719               next->from_prev = 0;
28720               if (next->length)
28721               {
28722                 if (l->next)
28723                   ctx_list_insert_before (&encoded_list, l->next, next);
28724                 else
28725                   ctx_list_append (&encoded_list, next);
28726               }
28727               else
28728                 free (next);
28729             }
28730 
28731             if (curr_pos) // step one item back for forloop
28732             {
28733               CtxList *tmp = encoded_list;
28734               int found = 0;
28735               while (!found && tmp && tmp->next)
28736               {
28737                 if (tmp->next == l)
28738                 {
28739                   l = tmp;
28740                   break;
28741                 }
28742                 tmp = tmp->next;
28743               }
28744             }
28745          }
28746       }
28747     }
28748 
28749     if (ctx_ticks ()-ticks_start > (unsigned long)max_ticks)
28750       break;
28751   }
28752 
28753   /* merge adjecant prev span references  */
28754   {
28755     for (CtxList *l = encoded_list; l; l = l->next)
28756     {
28757       CtxSpan *span = l->data;
28758 again:
28759       if (l->next)
28760       {
28761         CtxSpan *next_span = l->next->data;
28762         if (span->from_prev && next_span->from_prev &&
28763             span->start + span->length ==
28764             next_span->start)
28765         {
28766            span->length += next_span->length;
28767            ctx_list_remove (&encoded_list, next_span);
28768            goto again;
28769         }
28770       }
28771     }
28772   }
28773 
28774   while (encoded_list)
28775   {
28776     CtxSpan *span = encoded_list->data;
28777     if (span->from_prev)
28778     {
28779       char ref[128];
28780       sprintf (ref, "%c%i %i%c", CTX_CODEC_CHAR, span->start, span->length, CTX_CODEC_CHAR);
28781       ctx_string_append_data (string, ref, strlen(ref));
28782     }
28783     else
28784     {
28785       for (int i = span->start; i< span->start+span->length; i++)
28786       {
28787         if (src[i] == CTX_CODEC_CHAR)
28788         {
28789           char bytes[2]={CTX_CODEC_CHAR, CTX_CODEC_CHAR};
28790           ctx_string_append_data (string, bytes, 2);
28791         }
28792         else
28793         {
28794           ctx_string_append_data (string, &src[i], 1);
28795         }
28796       }
28797     }
28798     free (span);
28799     ctx_list_remove (&encoded_list, span);
28800   }
28801 
28802   char *ret = string->str;
28803   if (out_len) *out_len = string->length;
28804   ctx_string_free (string, 0);
28805   return ret;
28806 }
28807 
28808 #if 0 // for documentation/reference purposes
28809 static char *decode_ctx (const char *encoded, int enc_len, const char *prev, int prev_len, int *out_len)
28810 {
28811   CtxString *string = ctx_string_new ("");
28812   char reference[32]="";
28813   int ref_len = 0;
28814   int in_ref = 0;
28815   for (int i = 0; i < enc_len; i++)
28816   {
28817     if (encoded[i] == CTX_CODEC_CHAR)
28818     {
28819       if (!in_ref)
28820       {
28821         in_ref = 1;
28822       }
28823       else
28824       {
28825         int start = atoi (reference);
28826         int len = 0;
28827         if (strchr (reference, ' '))
28828           len = atoi (strchr (reference, ' ')+1);
28829 
28830         if (start < 0)start = 0;
28831         if (start >= prev_len)start = prev_len-1;
28832         if (len + start > prev_len)
28833           len = prev_len - start;
28834 
28835         if (start == 0 && len == 0)
28836           ctx_string_append_byte (string, CTX_CODEC_CHAR);
28837         else
28838           ctx_string_append_data (string, prev + start, len);
28839         ref_len = 0;
28840         in_ref = 0;
28841       }
28842     }
28843     else
28844     {
28845       if (in_ref)
28846       {
28847         if (ref_len < 16)
28848         {
28849           reference[ref_len++] = encoded[i];
28850           reference[ref_len] = 0;
28851         }
28852       }
28853       else
28854       ctx_string_append_data (string, &encoded[i], 1);
28855     }
28856   }
28857   char *ret = string->str;
28858   if (out_len) *out_len = string->length;
28859   ctx_string_free (string, 0);
28860   return ret;
28861 }
28862 #endif
28863 
28864 #define CTX_START_STRING "U\n"  // or " reset "
28865 #define CTX_END_STRING   "\nX"  // or "\ndone"
28866 #define CTX_END_STRING2  "\n\e"
28867 
28868 int ctx_frame_ack = -1;
28869 static char *prev_frame_contents = NULL;
28870 static int   prev_frame_len = 0;
28871 
ctx_ctx_flush(CtxCtx * ctxctx)28872 static void ctx_ctx_flush (CtxCtx *ctxctx)
28873 {
28874 #if 0
28875   FILE *debug = fopen ("/tmp/ctx-debug", "a");
28876   fprintf (debug, "------\n");
28877 #endif
28878 
28879   if (ctx_native_events)
28880     fprintf (stdout, "\e[?201h");
28881   fprintf (stdout, "\e[H\e[?25l\e[?200h");
28882 #if 1
28883   fprintf (stdout, CTX_START_STRING);
28884   ctx_render_stream (ctxctx->ctx, stdout, 0);
28885   fprintf (stdout, CTX_END_STRING);
28886 #else
28887   {
28888     int cur_frame_len = 0;
28889     char *rest = ctx_render_string (ctxctx->ctx, 0, &cur_frame_len);
28890     char *cur_frame_contents = malloc (cur_frame_len + strlen(CTX_START_STRING) + strlen (CTX_END_STRING) + 1);
28891 
28892     cur_frame_contents[0]=0;
28893     strcat (cur_frame_contents, CTX_START_STRING);
28894     strcat (cur_frame_contents, rest);
28895     strcat (cur_frame_contents, CTX_END_STRING);
28896     free (rest);
28897     cur_frame_len += strlen (CTX_START_STRING) + strlen (CTX_END_STRING);
28898 
28899     if (prev_frame_contents && 0)  // XXX :
28900     {
28901       char *encoded;
28902       int encoded_len = 0;
28903       //uint64_t ticks_start = ctx_ticks ();
28904 
28905       encoded = encode_in_terms_of_previous (cur_frame_contents, cur_frame_len, prev_frame_contents, prev_frame_len, &encoded_len, 1000 * 10);
28906 //    encoded = strdup (cur_frame_contents);
28907 //    encoded_len = strlen (encoded);
28908       //uint64_t ticks_end = ctx_ticks ();
28909 
28910       fwrite (encoded, encoded_len, 1, stdout);
28911 //    fwrite (encoded, cur_frame_len, 1, stdout);
28912 #if 0
28913       fprintf (debug, "---prev-frame(%i)\n%s", (int)strlen(prev_frame_contents), prev_frame_contents);
28914       fprintf (debug, "---cur-frame(%i)\n%s", (int)strlen(cur_frame_contents), cur_frame_contents);
28915       fprintf (debug, "---encoded(%.4f %i)---\n%s--------\n",
28916                       (ticks_end-ticks_start)/1000.0,
28917                       (int)strlen(encoded), encoded);
28918 #endif
28919       free (encoded);
28920     }
28921     else
28922     {
28923       fwrite (cur_frame_contents, cur_frame_len, 1, stdout);
28924     }
28925 
28926     if (prev_frame_contents)
28927       free (prev_frame_contents);
28928     prev_frame_contents = cur_frame_contents;
28929     prev_frame_len = cur_frame_len;
28930   }
28931 #endif
28932 #if 0
28933     fclose (debug);
28934 #endif
28935   fprintf (stdout, CTX_END_STRING2);
28936 
28937   fprintf (stdout, "\e[5n");
28938   fflush (stdout);
28939 
28940   ctx_frame_ack = 0;
28941   do {
28942      ctx_consume_events (ctxctx->ctx);
28943   } while (ctx_frame_ack != 1);
28944 }
28945 
ctx_ctx_free(CtxCtx * ctx)28946 void ctx_ctx_free (CtxCtx *ctx)
28947 {
28948   nc_at_exit ();
28949   free (ctx);
28950   /* we're not destoring the ctx member, this is function is called in ctx' teardown */
28951 }
28952 
28953 
ctx_new_ctx(int width,int height)28954 Ctx *ctx_new_ctx (int width, int height)
28955 {
28956   float font_size = 12.0;
28957   Ctx *ctx = ctx_new ();
28958   CtxCtx *ctxctx = (CtxCtx*)calloc (sizeof (CtxCtx), 1);
28959   fprintf (stdout, "\e[?1049h");
28960   fflush (stdout);
28961   //fprintf (stderr, "\e[H");
28962   //fprintf (stderr, "\e[2J");
28963   ctx_native_events = 1;
28964   if (width <= 0 || height <= 0)
28965   {
28966     ctxctx->cols = ctx_terminal_cols ();
28967     ctxctx->rows = ctx_terminal_rows ();
28968     width  = ctxctx->width  = ctx_terminal_width ();
28969     height = ctxctx->height = ctx_terminal_height ();
28970     font_size = height / ctxctx->rows;
28971     ctx_font_size (ctx, font_size);
28972   }
28973   else
28974   {
28975     ctxctx->width  = width;
28976     ctxctx->height = height;
28977     ctxctx->cols   = width / 80;
28978     ctxctx->rows   = height / 24;
28979   }
28980   ctxctx->ctx = ctx;
28981   if (!ctx_native_events)
28982     _ctx_mouse (ctx, NC_MOUSE_DRAG);
28983   ctx_set_renderer (ctx, ctxctx);
28984   ctx_set_size (ctx, width, height);
28985   ctxctx->flush = (void(*)(void *))ctx_ctx_flush;
28986   ctxctx->free  = (void(*)(void *))ctx_ctx_free;
28987   return ctx;
28988 }
28989 
28990 void ctx_ctx_pcm (Ctx *ctx);
28991 
ctx_ctx_consume_events(Ctx * ctx)28992 int ctx_ctx_consume_events (Ctx *ctx)
28993 {
28994   //int ix, iy;
28995   CtxCtx *ctxctx = (CtxCtx*)ctx->renderer;
28996   const char *event = NULL;
28997 #if CTX_AUDIO
28998   ctx_ctx_pcm (ctx);
28999 #endif
29000   assert (ctx_native_events);
29001 
29002 #if 1
29003     { /* XXX : this is a work-around for signals not working properly, we are polling the
29004          size with an ioctl per consume-events
29005          */
29006       struct winsize ws;
29007       ioctl(0,TIOCGWINSZ,&ws);
29008       ctxctx->cols = ws.ws_col;
29009       ctxctx->rows = ws.ws_row;
29010       ctxctx->width = ws.ws_xpixel;
29011       ctxctx->height = ws.ws_ypixel;
29012       ctx_set_size (ctx, ctxctx->width, ctxctx->height);
29013     }
29014 #endif
29015     //char *cmd = ctx_strdup_printf ("touch /tmp/ctx-%ix%i", ctxctx->width, ctxctx->height);
29016     //system (cmd);
29017     //free (cmd);
29018 
29019   if (ctx_native_events)
29020     {
29021 
29022       float x = 0, y = 0;
29023       int b = 0;
29024       char event_type[128]="";
29025       event = ctx_native_get_event (ctx, 1000/120);
29026 
29027       if (event)
29028       {
29029       sscanf (event, "%s %f %f %i", event_type, &x, &y, &b);
29030       if (!strcmp (event_type, "idle"))
29031       {
29032       }
29033       else if (!strcmp (event_type, "mouse-press"))
29034       {
29035         ctx_pointer_press (ctx, x, y, b, 0);
29036       }
29037       else if (!strcmp (event_type, "mouse-drag")||
29038                !strcmp (event_type, "mouse-motion"))
29039       {
29040         ctx_pointer_motion (ctx, x, y, b, 0);
29041       }
29042       else if (!strcmp (event_type, "mouse-release"))
29043       {
29044         ctx_pointer_release (ctx, x, y, b, 0);
29045       }
29046       else if (!strcmp (event_type, "message"))
29047       {
29048         ctx_incoming_message (ctx, event + strlen ("message"), 0);
29049       } else if (!strcmp (event, "size-changed"))
29050       {
29051         fprintf (stdout, "\e[H\e[2J\e[?25l");
29052         ctxctx->cols = ctx_terminal_cols ();
29053         ctxctx->rows = ctx_terminal_rows ();
29054         ctxctx->width  = ctx_terminal_width ();
29055         ctxctx->height = ctx_terminal_height ();
29056 
29057         //system ("touch /tmp/ctx-abc");
29058 
29059         ctx_set_size (ctx, ctxctx->width, ctxctx->height);
29060 
29061         if (prev_frame_contents)
29062           free (prev_frame_contents);
29063         prev_frame_contents = NULL;
29064         prev_frame_len = 0;
29065         ctx_set_dirty (ctx, 1);
29066 
29067       //   ctx_key_press(ctx,0,"size-changed",0);
29068       }
29069       else if (!strcmp (event_type, "keyup"))
29070       {
29071         char buf[4]={ x, 0 };
29072         ctx_key_up (ctx, (int)x, buf, 0);
29073       }
29074       else if (!strcmp (event_type, "keydown"))
29075       {
29076         char buf[4]={ x, 0 };
29077         ctx_key_down (ctx, (int)x, buf, 0);
29078       }
29079       else
29080       {
29081         ctx_key_press (ctx, 0, event, 0);
29082       }
29083       }
29084     }
29085 
29086   return 1;
29087 }
29088 
ctx_renderer_is_ctx(Ctx * ctx)29089 int ctx_renderer_is_ctx (Ctx *ctx)
29090 {
29091   if (ctx->renderer &&
29092       ctx->renderer->free == (void*)ctx_ctx_free)
29093           return 1;
29094   return 0;
29095 }
29096 
29097 #endif
29098 
29099 #if CTX_TILED
29100 static inline int
ctx_tiled_threads_done(CtxTiled * tiled)29101 ctx_tiled_threads_done (CtxTiled *tiled)
29102 {
29103   int sum = 0;
29104   for (int i = 0; i < _ctx_max_threads; i++)
29105   {
29106      if (tiled->rendered_frame[i] == tiled->render_frame)
29107        sum ++;
29108   }
29109   return sum;
29110 }
29111 
29112 int _ctx_damage_control = 0;
29113 
ctx_tiled_free(CtxTiled * tiled)29114 void ctx_tiled_free (CtxTiled *tiled)
29115 {
29116   tiled->quit = 1;
29117   mtx_lock (&tiled->mtx);
29118   cnd_broadcast (&tiled->cond);
29119   mtx_unlock (&tiled->mtx);
29120 
29121   while (tiled->thread_quit < _ctx_max_threads)
29122     usleep (1000);
29123 
29124   if (tiled->pixels)
29125   {
29126     free (tiled->pixels);
29127   tiled->pixels = NULL;
29128   for (int i = 0 ; i < _ctx_max_threads; i++)
29129   {
29130     ctx_free (tiled->host[i]);
29131     tiled->host[i]=NULL;
29132   }
29133 
29134   ctx_free (tiled->ctx_copy);
29135   }
29136   // leak?
29137 }
29138 static unsigned char *sdl_icc = NULL;
29139 static long sdl_icc_length = 0;
29140 
ctx_tiled_flush(CtxTiled * tiled)29141 inline static void ctx_tiled_flush (CtxTiled *tiled)
29142 {
29143   if (tiled->shown_frame == tiled->render_frame)
29144   {
29145     int dirty_tiles = 0;
29146     ctx_set_drawlist (tiled->ctx_copy, &tiled->ctx->drawlist.entries[0],
29147                                            tiled->ctx->drawlist.count * 9);
29148     if (_ctx_enable_hash_cache)
29149     {
29150       Ctx *hasher = ctx_hasher_new (tiled->width, tiled->height,
29151                         CTX_HASH_COLS, CTX_HASH_ROWS);
29152       ctx_render_ctx (tiled->ctx_copy, hasher);
29153 
29154       for (int row = 0; row < CTX_HASH_ROWS; row++)
29155         for (int col = 0; col < CTX_HASH_COLS; col++)
29156         {
29157           uint8_t *new_hash = ctx_hasher_get_hash (hasher, col, row);
29158           if (new_hash && memcmp (new_hash, &tiled->hashes[(row * CTX_HASH_COLS + col) *  20], 20))
29159           {
29160             memcpy (&tiled->hashes[(row * CTX_HASH_COLS +  col)*20], new_hash, 20);
29161             tiled->tile_affinity[row * CTX_HASH_COLS + col] = 1;
29162             dirty_tiles++;
29163           }
29164           else
29165           {
29166             tiled->tile_affinity[row * CTX_HASH_COLS + col] = -1;
29167           }
29168         }
29169       free (((CtxHasher*)(hasher->renderer))->hashes);
29170       ctx_free (hasher);
29171     }
29172     else
29173     {
29174     for (int row = 0; row < CTX_HASH_ROWS; row++)
29175       for (int col = 0; col < CTX_HASH_COLS; col++)
29176         {
29177           tiled->tile_affinity[row * CTX_HASH_COLS + col] = 1;
29178           dirty_tiles++;
29179         }
29180     }
29181     int dirty_no = 0;
29182     if (dirty_tiles)
29183     for (int row = 0; row < CTX_HASH_ROWS; row++)
29184       for (int col = 0; col < CTX_HASH_COLS; col++)
29185       {
29186         if (tiled->tile_affinity[row * CTX_HASH_COLS + col] != -1)
29187         {
29188           tiled->tile_affinity[row * CTX_HASH_COLS + col] = dirty_no * (_ctx_max_threads) / dirty_tiles;
29189           dirty_no++;
29190           if (col > tiled->max_col) tiled->max_col = col;
29191           if (col < tiled->min_col) tiled->min_col = col;
29192           if (row > tiled->max_row) tiled->max_row = row;
29193           if (row < tiled->min_row) tiled->min_row = row;
29194         }
29195       }
29196 
29197     if (_ctx_damage_control)
29198     {
29199       for (int i = 0; i < tiled->width * tiled->height; i++)
29200       {
29201         tiled->pixels[i*4+2]  = (tiled->pixels[i*4+2] + 255)/2;
29202       }
29203     }
29204 
29205     tiled->render_frame = ++tiled->frame;
29206 
29207 #if 0
29208 
29209           //if (tiled->tile_affinity[hno]==no)
29210           {
29211             int x0 = ((tiled->width)/CTX_HASH_COLS) * 0;
29212             int y0 = ((tiled->height)/CTX_HASH_ROWS) * 0;
29213             int width = tiled->width / CTX_HASH_COLS;
29214             int height = tiled->height / CTX_HASH_ROWS;
29215             Ctx *host = tiled->host[0];
29216 
29217             CtxRasterizer *rasterizer = (CtxRasterizer*)host->renderer;
29218             int swap_red_green = ((CtxRasterizer*)(host->renderer))->swap_red_green;
29219             ctx_rasterizer_init (rasterizer,
29220                                  host, tiled->ctx, &host->state,
29221                                  &tiled->pixels[tiled->width * 4 * y0 + x0 * 4],
29222                                  0, 0, 1, 1,
29223                                  tiled->width*4, CTX_FORMAT_BGRA8,
29224                                  tiled->antialias);
29225             ((CtxRasterizer*)(host->renderer))->swap_red_green = swap_red_green;
29226             if (sdl_icc_length)
29227               ctx_colorspace (host, CTX_COLOR_SPACE_DEVICE_RGB, sdl_icc, sdl_icc_length);
29228 
29229             ctx_translate (host, -x0, -y0);
29230             ctx_render_ctx (tiled->ctx_copy, host);
29231           }
29232 #endif
29233 
29234 
29235     mtx_lock (&tiled->mtx);
29236     cnd_broadcast (&tiled->cond);
29237     mtx_unlock (&tiled->mtx);
29238   }
29239 }
29240 
29241 static
ctx_tiled_render_fun(void ** data)29242 void ctx_tiled_render_fun (void **data)
29243 {
29244   int      no = (size_t)data[0];
29245   CtxTiled *tiled = data[1];
29246 
29247   while (!tiled->quit)
29248   {
29249     Ctx *host = tiled->host[no];
29250 
29251     mtx_lock (&tiled->mtx);
29252     cnd_wait(&tiled->cond, &tiled->mtx);
29253     mtx_unlock (&tiled->mtx);
29254 
29255     if (tiled->render_frame != tiled->rendered_frame[no])
29256     {
29257       int hno = 0;
29258       for (int row = 0; row < CTX_HASH_ROWS; row++)
29259         for (int col = 0; col < CTX_HASH_COLS; col++, hno++)
29260         {
29261           if (tiled->tile_affinity[hno]==no)
29262           {
29263             int x0 = ((tiled->width)/CTX_HASH_COLS) * col;
29264             int y0 = ((tiled->height)/CTX_HASH_ROWS) * row;
29265             int width = tiled->width / CTX_HASH_COLS;
29266             int height = tiled->height / CTX_HASH_ROWS;
29267 
29268             CtxRasterizer *rasterizer = (CtxRasterizer*)host->renderer;
29269 #if 1 // merge horizontally adjecant tiles of same affinity into one job
29270             while (col + 1 < CTX_HASH_COLS &&
29271                    tiled->tile_affinity[hno+1] == no)
29272             {
29273               width += tiled->width / CTX_HASH_COLS;
29274               col++;
29275               hno++;
29276             }
29277 #endif
29278             int swap_red_green = ((CtxRasterizer*)(host->renderer))->swap_red_green;
29279             ctx_rasterizer_init (rasterizer,
29280                                  host, tiled->ctx, &host->state,
29281                                  &tiled->pixels[tiled->width * 4 * y0 + x0 * 4],
29282                                  0, 0, width, height,
29283                                  tiled->width*4, CTX_FORMAT_BGRA8,
29284                                  tiled->antialias);
29285             ((CtxRasterizer*)(host->renderer))->swap_red_green = swap_red_green;
29286             if (sdl_icc_length)
29287               ctx_colorspace (host, CTX_COLOR_SPACE_DEVICE_RGB, sdl_icc, sdl_icc_length);
29288 
29289             ctx_translate (host, -x0, -y0);
29290             ctx_render_ctx (tiled->ctx_copy, host);
29291           }
29292         }
29293       tiled->rendered_frame[no] = tiled->render_frame;
29294     }
29295   }
29296   tiled->thread_quit++; // need atomic?
29297 }
29298 
29299 
29300 static int       ctx_tiled_cursor_drawn   = 0;
29301 static int       ctx_tiled_cursor_drawn_x = 0;
29302 static int       ctx_tiled_cursor_drawn_y = 0;
29303 static CtxCursor ctx_tiled_cursor_drawn_shape = 0;
29304 
29305 
29306 #define CTX_FB_HIDE_CURSOR_FRAMES 200
29307 
29308 static int ctx_tiled_cursor_same_pos = CTX_FB_HIDE_CURSOR_FRAMES;
29309 
ctx_is_in_cursor(int x,int y,int size,CtxCursor shape)29310 static inline int ctx_is_in_cursor (int x, int y, int size, CtxCursor shape)
29311 {
29312   switch (shape)
29313   {
29314     case CTX_CURSOR_ARROW:
29315       if (x > ((size * 4)-y*4)) return 0;
29316       if (x < y && x > y / 16)
29317         return 1;
29318       return 0;
29319 
29320     case CTX_CURSOR_RESIZE_SE:
29321     case CTX_CURSOR_RESIZE_NW:
29322     case CTX_CURSOR_RESIZE_SW:
29323     case CTX_CURSOR_RESIZE_NE:
29324       {
29325         float theta = -45.0/180 * M_PI;
29326         float cos_theta;
29327         float sin_theta;
29328 
29329         if ((shape == CTX_CURSOR_RESIZE_SW) ||
29330             (shape == CTX_CURSOR_RESIZE_NE))
29331         {
29332           theta = -theta;
29333           cos_theta = cos (theta);
29334           sin_theta = sin (theta);
29335         }
29336         else
29337         {
29338           cos_theta = cos (theta);
29339           sin_theta = sin (theta);
29340         }
29341         int rot_x = x * cos_theta - y * sin_theta;
29342         int rot_y = y * cos_theta + x * sin_theta;
29343         x = rot_x;
29344         y = rot_y;
29345       }
29346       /*FALLTHROUGH*/
29347     case CTX_CURSOR_RESIZE_W:
29348     case CTX_CURSOR_RESIZE_E:
29349     case CTX_CURSOR_RESIZE_ALL:
29350       if (abs (x) < size/2 && abs (y) < size/2)
29351       {
29352         if (abs(y) < size/10)
29353         {
29354           return 1;
29355         }
29356       }
29357       if ((abs (x) - size/ (shape == CTX_CURSOR_RESIZE_ALL?2:2.7)) >= 0)
29358       {
29359         if (abs(y) < (size/2.8)-(abs(x) - (size/2)))
29360           return 1;
29361       }
29362       if (shape != CTX_CURSOR_RESIZE_ALL)
29363         break;
29364       /* FALLTHROUGH */
29365     case CTX_CURSOR_RESIZE_S:
29366     case CTX_CURSOR_RESIZE_N:
29367       if (abs (y) < size/2 && abs (x) < size/2)
29368       {
29369         if (abs(x) < size/10)
29370         {
29371           return 1;
29372         }
29373       }
29374       if ((abs (y) - size/ (shape == CTX_CURSOR_RESIZE_ALL?2:2.7)) >= 0)
29375       {
29376         if (abs(x) < (size/2.8)-(abs(y) - (size/2)))
29377           return 1;
29378       }
29379       break;
29380 #if 0
29381     case CTX_CURSOR_RESIZE_ALL:
29382       if (abs (x) < size/2 && abs (y) < size/2)
29383       {
29384         if (abs (x) < size/10 || abs(y) < size/10)
29385           return 1;
29386       }
29387       break;
29388 #endif
29389     default:
29390       return (x ^ y) & 1;
29391   }
29392   return 0;
29393 }
29394 
ctx_tiled_undraw_cursor(CtxTiled * tiled)29395 static void ctx_tiled_undraw_cursor (CtxTiled *tiled)
29396 {
29397     int cursor_size = ctx_height (tiled->ctx) / 28;
29398 
29399     if (ctx_tiled_cursor_drawn)
29400     {
29401       int no = 0;
29402       int startx = -cursor_size;
29403       int starty = -cursor_size;
29404       if (ctx_tiled_cursor_drawn_shape == CTX_CURSOR_ARROW)
29405         startx = starty = 0;
29406 
29407       for (int y = starty; y < cursor_size; y++)
29408       for (int x = startx; x < cursor_size; x++, no+=4)
29409       {
29410         if (x + ctx_tiled_cursor_drawn_x < tiled->width && y + ctx_tiled_cursor_drawn_y < tiled->height)
29411         {
29412           if (ctx_is_in_cursor (x, y, cursor_size, ctx_tiled_cursor_drawn_shape))
29413           {
29414             int o = ((ctx_tiled_cursor_drawn_y + y) * tiled->width + (ctx_tiled_cursor_drawn_x + x)) * 4;
29415             tiled->fb[o+0]^=0x88;
29416             tiled->fb[o+1]^=0x88;
29417             tiled->fb[o+2]^=0x88;
29418           }
29419         }
29420       }
29421 
29422     ctx_tiled_cursor_drawn = 0;
29423     }
29424 }
29425 
ctx_tiled_draw_cursor(CtxTiled * tiled)29426 static void ctx_tiled_draw_cursor (CtxTiled *tiled)
29427 {
29428     int cursor_x    = ctx_pointer_x (tiled->ctx);
29429     int cursor_y    = ctx_pointer_y (tiled->ctx);
29430     int cursor_size = ctx_height (tiled->ctx) / 28;
29431     CtxCursor cursor_shape = tiled->ctx->cursor;
29432     int no = 0;
29433 
29434     if (cursor_x == ctx_tiled_cursor_drawn_x &&
29435         cursor_y == ctx_tiled_cursor_drawn_y &&
29436         cursor_shape == ctx_tiled_cursor_drawn_shape)
29437       ctx_tiled_cursor_same_pos ++;
29438     else
29439       ctx_tiled_cursor_same_pos = 0;
29440 
29441     if (ctx_tiled_cursor_same_pos >= CTX_FB_HIDE_CURSOR_FRAMES)
29442     {
29443       if (ctx_tiled_cursor_drawn)
29444         ctx_tiled_undraw_cursor (tiled);
29445       return;
29446     }
29447 
29448     /* no need to flicker when stationary, motion flicker can also be removed
29449      * by combining the previous and next position masks when a motion has
29450      * occured..
29451      */
29452     if (ctx_tiled_cursor_same_pos && ctx_tiled_cursor_drawn)
29453       return;
29454 
29455     ctx_tiled_undraw_cursor (tiled);
29456 
29457     no = 0;
29458 
29459     int startx = -cursor_size;
29460     int starty = -cursor_size;
29461 
29462     if (cursor_shape == CTX_CURSOR_ARROW)
29463       startx = starty = 0;
29464 
29465     for (int y = starty; y < cursor_size; y++)
29466       for (int x = startx; x < cursor_size; x++, no+=4)
29467       {
29468         if (x + cursor_x < tiled->width && y + cursor_y < tiled->height)
29469         {
29470           if (ctx_is_in_cursor (x, y, cursor_size, cursor_shape))
29471           {
29472             int o = ((cursor_y + y) * tiled->width + (cursor_x + x)) * 4;
29473             tiled->fb[o+0]^=0x88;
29474             tiled->fb[o+1]^=0x88;
29475             tiled->fb[o+2]^=0x88;
29476           }
29477         }
29478       }
29479     ctx_tiled_cursor_drawn = 1;
29480     ctx_tiled_cursor_drawn_x = cursor_x;
29481     ctx_tiled_cursor_drawn_y = cursor_y;
29482     ctx_tiled_cursor_drawn_shape = cursor_shape;
29483 }
29484 
29485 #endif
29486 #if CTX_EVENTS
29487 
29488 
29489 #define evsource_has_event(es)   (es)->has_event((es))
29490 #define evsource_get_event(es)   (es)->get_event((es))
29491 #define evsource_destroy(es)     do{if((es)->destroy)(es)->destroy((es));}while(0)
29492 #define evsource_set_coord(es,x,y) do{if((es)->set_coord)(es)->set_coord((es),(x),(y));}while(0)
29493 #define evsource_get_fd(es)      ((es)->get_fd?(es)->get_fd((es)):0)
29494 
29495 
29496 
29497 static int mice_has_event ();
29498 static char *mice_get_event ();
29499 static void mice_destroy ();
29500 static int mice_get_fd (EvSource *ev_source);
29501 static void mice_set_coord (EvSource *ev_source, double x, double y);
29502 
29503 static EvSource ctx_ev_src_mice = {
29504   NULL,
29505   (void*)mice_has_event,
29506   (void*)mice_get_event,
29507   (void*)mice_destroy,
29508   mice_get_fd,
29509   mice_set_coord
29510 };
29511 
29512 typedef struct Mice
29513 {
29514   int     fd;
29515   double  x;
29516   double  y;
29517   int     button;
29518   int     prev_state;
29519 } Mice;
29520 
29521 Mice *_mrg_evsrc_coord = NULL;
29522 static int _ctx_mice_fd = 0;
29523 
_mmm_get_coords(Ctx * ctx,double * x,double * y)29524 void _mmm_get_coords (Ctx *ctx, double *x, double *y)
29525 {
29526   if (!_mrg_evsrc_coord)
29527     return;
29528   if (x)
29529     *x = _mrg_evsrc_coord->x;
29530   if (y)
29531     *y = _mrg_evsrc_coord->y;
29532 }
29533 
29534 static Mice  mice;
29535 static Mice* mrg_mice_this = &mice;
29536 
mmm_evsource_mice_init()29537 static int mmm_evsource_mice_init ()
29538 {
29539   unsigned char reset[]={0xff};
29540   /* need to detect which event */
29541 
29542   mrg_mice_this->prev_state = 0;
29543   mrg_mice_this->fd = open ("/dev/input/mice", O_RDONLY | O_NONBLOCK);
29544   if (mrg_mice_this->fd == -1)
29545   {
29546     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");
29547     return -1;
29548   }
29549   if (write (mrg_mice_this->fd, reset, 1) == -1)
29550   {
29551     // might happen if we're a regular user with only read permission
29552   }
29553   _ctx_mice_fd = mrg_mice_this->fd;
29554   _mrg_evsrc_coord = mrg_mice_this;
29555   return 0;
29556 }
29557 
mice_destroy()29558 static void mice_destroy ()
29559 {
29560   if (mrg_mice_this->fd != -1)
29561     close (mrg_mice_this->fd);
29562 }
29563 
mice_has_event()29564 static int mice_has_event ()
29565 {
29566   struct timeval tv;
29567   int retval;
29568 
29569   if (mrg_mice_this->fd == -1)
29570     return 0;
29571 
29572   fd_set rfds;
29573   FD_ZERO (&rfds);
29574   FD_SET(mrg_mice_this->fd, &rfds);
29575   tv.tv_sec = 0; tv.tv_usec = 0;
29576   retval = select (mrg_mice_this->fd+1, &rfds, NULL, NULL, &tv);
29577   if (retval == 1)
29578     return FD_ISSET (mrg_mice_this->fd, &rfds);
29579   return 0;
29580 }
29581 
mice_get_event()29582 static char *mice_get_event ()
29583 {
29584   const char *ret = "mouse-motion";
29585   double relx, rely;
29586   signed char buf[3];
29587   int n_read = 0;
29588   CtxTiled *tiled = (void*)ctx_ev_src_mice.priv;
29589   n_read = read (mrg_mice_this->fd, buf, 3);
29590   if (n_read == 0)
29591      return strdup ("");
29592   relx = buf[1];
29593   rely = -buf[2];
29594 
29595   if (relx < 0)
29596   {
29597     if (relx > -6)
29598     relx = - relx*relx;
29599     else
29600     relx = -36;
29601   }
29602   else
29603   {
29604     if (relx < 6)
29605     relx = relx*relx;
29606     else
29607     relx = 36;
29608   }
29609 
29610   if (rely < 0)
29611   {
29612     if (rely > -6)
29613     rely = - rely*rely;
29614     else
29615     rely = -36;
29616   }
29617   else
29618   {
29619     if (rely < 6)
29620     rely = rely*rely;
29621     else
29622     rely = 36;
29623   }
29624 
29625   mrg_mice_this->x += relx;
29626   mrg_mice_this->y += rely;
29627 
29628   if (mrg_mice_this->x < 0)
29629     mrg_mice_this->x = 0;
29630   if (mrg_mice_this->y < 0)
29631     mrg_mice_this->y = 0;
29632   if (mrg_mice_this->x >= tiled->width)
29633     mrg_mice_this->x = tiled->width -1;
29634   if (mrg_mice_this->y >= tiled->height)
29635     mrg_mice_this->y = tiled->height -1;
29636   int button = 0;
29637 
29638   if ((mrg_mice_this->prev_state & 1) != (buf[0] & 1))
29639     {
29640       if (buf[0] & 1)
29641         {
29642           ret = "mouse-press";
29643         }
29644       else
29645         {
29646           ret = "mouse-release";
29647         }
29648       button = 1;
29649     }
29650   else if (buf[0] & 1)
29651   {
29652     ret = "mouse-drag";
29653     button = 1;
29654   }
29655 
29656   if (!button)
29657   {
29658     if ((mrg_mice_this->prev_state & 2) != (buf[0] & 2))
29659     {
29660       if (buf[0] & 2)
29661         {
29662           ret = "mouse-press";
29663         }
29664       else
29665         {
29666           ret = "mouse-release";
29667         }
29668       button = 3;
29669     }
29670     else if (buf[0] & 2)
29671     {
29672       ret = "mouse-drag";
29673       button = 3;
29674     }
29675   }
29676 
29677   if (!button)
29678   {
29679     if ((mrg_mice_this->prev_state & 4) != (buf[0] & 4))
29680     {
29681       if (buf[0] & 4)
29682         {
29683           ret = "mouse-press";
29684         }
29685       else
29686         {
29687           ret = "mouse-release";
29688         }
29689       button = 2;
29690     }
29691     else if (buf[0] & 4)
29692     {
29693       ret = "mouse-drag";
29694       button = 2;
29695     }
29696   }
29697 
29698   mrg_mice_this->prev_state = buf[0];
29699 
29700   {
29701     char *r = malloc (64);
29702     sprintf (r, "%s %.0f %.0f %i", ret, mrg_mice_this->x, mrg_mice_this->y, button);
29703     return r;
29704   }
29705 
29706   return NULL;
29707 }
29708 
mice_get_fd(EvSource * ev_source)29709 static int mice_get_fd (EvSource *ev_source)
29710 {
29711   return mrg_mice_this->fd;
29712 }
29713 
mice_set_coord(EvSource * ev_source,double x,double y)29714 static void mice_set_coord (EvSource *ev_source, double x, double y)
29715 {
29716   mrg_mice_this->x = x;
29717   mrg_mice_this->y = y;
29718 }
29719 
evsource_mice_new(void)29720 static EvSource *evsource_mice_new (void)
29721 {
29722   if (mmm_evsource_mice_init () == 0)
29723     {
29724       mrg_mice_this->x = 0;
29725       mrg_mice_this->y = 0;
29726       return &ctx_ev_src_mice;
29727     }
29728   return NULL;
29729 }
29730 
29731 static int evsource_kb_has_event (void);
29732 static char *evsource_kb_get_event (void);
29733 static void evsource_kb_destroy (int sign);
29734 static int evsource_kb_get_fd (void);
29735 
29736 /* kept out of struct to be reachable by atexit */
29737 static EvSource ctx_ev_src_kb = {
29738   NULL,
29739   (void*)evsource_kb_has_event,
29740   (void*)evsource_kb_get_event,
29741   (void*)evsource_kb_destroy,
29742   (void*)evsource_kb_get_fd,
29743   NULL
29744 };
29745 
29746 static struct termios orig_attr;
29747 
real_evsource_kb_destroy(int sign)29748 static void real_evsource_kb_destroy (int sign)
29749 {
29750   static int done = 0;
29751 
29752   if (sign == 0)
29753     return;
29754 
29755   if (done)
29756     return;
29757   done = 1;
29758 
29759   switch (sign)
29760   {
29761     case  -11:break; /* will be called from atexit with sign==-11 */
29762     case   SIGSEGV: break;//fprintf (stderr, " SIGSEGV\n");break;
29763     case   SIGABRT: fprintf (stderr, " SIGABRT\n");break;
29764     case   SIGBUS:  fprintf (stderr, " SIGBUS\n");break;
29765     case   SIGKILL: fprintf (stderr, " SIGKILL\n");break;
29766     case   SIGINT:  fprintf (stderr, " SIGINT\n");break;
29767     case   SIGTERM: fprintf (stderr, " SIGTERM\n");break;
29768     case   SIGQUIT: fprintf (stderr, " SIGQUIT\n");break;
29769     default: fprintf (stderr, "sign: %i\n", sign);
29770              fprintf (stderr, "%i %i %i %i %i %i %i\n", SIGSEGV, SIGABRT, SIGBUS, SIGKILL, SIGINT, SIGTERM, SIGQUIT);
29771   }
29772   tcsetattr (STDIN_FILENO, TCSAFLUSH, &orig_attr);
29773   //fprintf (stderr, "evsource kb destroy\n");
29774 }
29775 
evsource_kb_destroy(int sign)29776 static void evsource_kb_destroy (int sign)
29777 {
29778   real_evsource_kb_destroy (-11);
29779 }
29780 
evsource_kb_init()29781 static int evsource_kb_init ()
29782 {
29783 //  ioctl(STDIN_FILENO, KDSKBMODE, K_RAW);
29784   atexit ((void*) real_evsource_kb_destroy);
29785   signal (SIGSEGV, (void*) real_evsource_kb_destroy);
29786   signal (SIGABRT, (void*) real_evsource_kb_destroy);
29787   signal (SIGBUS,  (void*) real_evsource_kb_destroy);
29788   signal (SIGKILL, (void*) real_evsource_kb_destroy);
29789   signal (SIGINT,  (void*) real_evsource_kb_destroy);
29790   signal (SIGTERM, (void*) real_evsource_kb_destroy);
29791   signal (SIGQUIT, (void*) real_evsource_kb_destroy);
29792 
29793   struct termios raw;
29794   if (tcgetattr (STDIN_FILENO, &orig_attr) == -1)
29795     {
29796       fprintf (stderr, "error initializing keyboard\n");
29797       return -1;
29798     }
29799   raw = orig_attr;
29800 
29801   cfmakeraw (&raw);
29802 
29803   raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
29804   if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &raw) < 0)
29805     return 0; // XXX? return other value?
29806 
29807   return 0;
29808 }
evsource_kb_has_event(void)29809 static int evsource_kb_has_event (void)
29810 {
29811   struct timeval tv;
29812   int retval;
29813 
29814   fd_set rfds;
29815   FD_ZERO (&rfds);
29816   FD_SET(STDIN_FILENO, &rfds);
29817   tv.tv_sec = 0; tv.tv_usec = 0;
29818   retval = select (STDIN_FILENO+1, &rfds, NULL, NULL, &tv);
29819   return retval == 1;
29820 }
29821 
29822 /* note that a nick can have multiple occurences, the labels
29823  * should be kept the same for all occurences of a combination.
29824  *
29825  * this table is taken from nchanterm.
29826  */
29827 typedef struct MmmKeyCode {
29828   char *nick;          /* programmers name for key */
29829   char  sequence[10];  /* terminal sequence */
29830 } MmmKeyCode;
29831 static const MmmKeyCode ufb_keycodes[]={
29832   {"up",                  "\e[A"},
29833   {"down",                "\e[B"},
29834   {"right",               "\e[C"},
29835   {"left",                "\e[D"},
29836 
29837   {"shift-up",            "\e[1;2A"},
29838   {"shift-down",          "\e[1;2B"},
29839   {"shift-right",         "\e[1;2C"},
29840   {"shift-left",          "\e[1;2D"},
29841 
29842   {"alt-up",              "\e[1;3A"},
29843   {"alt-down",            "\e[1;3B"},
29844   {"alt-right",           "\e[1;3C"},
29845   {"alt-left",            "\e[1;3D"},
29846   {"alt-shift-up",         "\e[1;4A"},
29847   {"alt-shift-down",       "\e[1;4B"},
29848   {"alt-shift-right",      "\e[1;4C"},
29849   {"alt-shift-left",       "\e[1;4D"},
29850 
29851   {"control-up",          "\e[1;5A"},
29852   {"control-down",        "\e[1;5B"},
29853   {"control-right",       "\e[1;5C"},
29854   {"control-left",        "\e[1;5D"},
29855 
29856   /* putty */
29857   {"control-up",          "\eOA"},
29858   {"control-down",        "\eOB"},
29859   {"control-right",       "\eOC"},
29860   {"control-left",        "\eOD"},
29861 
29862   {"control-shift-up",    "\e[1;6A"},
29863   {"control-shift-down",  "\e[1;6B"},
29864   {"control-shift-right", "\e[1;6C"},
29865   {"control-shift-left",  "\e[1;6D"},
29866 
29867   {"control-up",          "\eOa"},
29868   {"control-down",        "\eOb"},
29869   {"control-right",       "\eOc"},
29870   {"control-left",        "\eOd"},
29871 
29872   {"shift-up",            "\e[a"},
29873   {"shift-down",          "\e[b"},
29874   {"shift-right",         "\e[c"},
29875   {"shift-left",          "\e[d"},
29876 
29877   {"insert",              "\e[2~"},
29878   {"delete",              "\e[3~"},
29879   {"page-up",             "\e[5~"},
29880   {"page-down",           "\e[6~"},
29881   {"home",                "\eOH"},
29882   {"end",                 "\eOF"},
29883   {"home",                "\e[H"},
29884   {"end",                 "\e[F"},
29885  {"control-delete",       "\e[3;5~"},
29886   {"shift-delete",        "\e[3;2~"},
29887   {"control-shift-delete","\e[3;6~"},
29888 
29889   {"F1",         "\e[25~"},
29890   {"F2",         "\e[26~"},
29891   {"F3",         "\e[27~"},
29892   {"F4",         "\e[26~"},
29893 
29894 
29895   {"F1",         "\e[11~"},
29896   {"F2",         "\e[12~"},
29897   {"F3",         "\e[13~"},
29898   {"F4",         "\e[14~"},
29899   {"F1",         "\eOP"},
29900   {"F2",         "\eOQ"},
29901   {"F3",         "\eOR"},
29902   {"F4",         "\eOS"},
29903   {"F5",         "\e[15~"},
29904   {"F6",         "\e[16~"},
29905   {"F7",         "\e[17~"},
29906   {"F8",         "\e[18~"},
29907   {"F9",         "\e[19~"},
29908   {"F9",         "\e[20~"},
29909   {"F10",        "\e[21~"},
29910   {"F11",        "\e[22~"},
29911   {"F12",        "\e[23~"},
29912   {"tab",         {9, '\0'}},
29913   {"shift-tab",   {27, 9, '\0'}}, // also generated by alt-tab in linux console
29914   {"alt-space",   {27, ' ', '\0'}},
29915   {"shift-tab",   "\e[Z"},
29916   {"backspace",   {127, '\0'}},
29917   {"space",       " "},
29918   {"\e",          "\e"},
29919   {"return",      {10,0}},
29920   {"return",      {13,0}},
29921   /* this section could be autogenerated by code */
29922   {"control-a",   {1,0}},
29923   {"control-b",   {2,0}},
29924   {"control-c",   {3,0}},
29925   {"control-d",   {4,0}},
29926   {"control-e",   {5,0}},
29927   {"control-f",   {6,0}},
29928   {"control-g",   {7,0}},
29929   {"control-h",   {8,0}}, /* backspace? */
29930   {"control-i",   {9,0}},
29931   {"control-j",   {10,0}},
29932   {"control-k",   {11,0}},
29933   {"control-l",   {12,0}},
29934   {"control-n",   {14,0}},
29935   {"control-o",   {15,0}},
29936   {"control-p",   {16,0}},
29937   {"control-q",   {17,0}},
29938   {"control-r",   {18,0}},
29939   {"control-s",   {19,0}},
29940   {"control-t",   {20,0}},
29941   {"control-u",   {21,0}},
29942   {"control-v",   {22,0}},
29943   {"control-w",   {23,0}},
29944   {"control-x",   {24,0}},
29945   {"control-y",   {25,0}},
29946   {"control-z",   {26,0}},
29947   {"alt-`",       "\e`"},
29948   {"alt-0",       "\e0"},
29949   {"alt-1",       "\e1"},
29950   {"alt-2",       "\e2"},
29951   {"alt-3",       "\e3"},
29952   {"alt-4",       "\e4"},
29953   {"alt-5",       "\e5"},
29954   {"alt-6",       "\e6"},
29955   {"alt-7",       "\e7"}, /* backspace? */
29956   {"alt-8",       "\e8"},
29957   {"alt-9",       "\e9"},
29958   {"alt-+",       "\e+"},
29959   {"alt--",       "\e-"},
29960   {"alt-/",       "\e/"},
29961   {"alt-a",       "\ea"},
29962   {"alt-b",       "\eb"},
29963   {"alt-c",       "\ec"},
29964   {"alt-d",       "\ed"},
29965   {"alt-e",       "\ee"},
29966   {"alt-f",       "\ef"},
29967   {"alt-g",       "\eg"},
29968   {"alt-h",       "\eh"}, /* backspace? */
29969   {"alt-i",       "\ei"},
29970   {"alt-j",       "\ej"},
29971   {"alt-k",       "\ek"},
29972   {"alt-l",       "\el"},
29973   {"alt-n",       "\em"},
29974   {"alt-n",       "\en"},
29975   {"alt-o",       "\eo"},
29976   {"alt-p",       "\ep"},
29977   {"alt-q",       "\eq"},
29978   {"alt-r",       "\er"},
29979   {"alt-s",       "\es"},
29980   {"alt-t",       "\et"},
29981   {"alt-u",       "\eu"},
29982   {"alt-v",       "\ev"},
29983   {"alt-w",       "\ew"},
29984   {"alt-x",       "\ex"},
29985   {"alt-y",       "\ey"},
29986   {"alt-z",       "\ez"},
29987   /* Linux Console  */
29988   {"home",       "\e[1~"},
29989   {"end",        "\e[4~"},
29990   {"F1",         "\e[[A"},
29991   {"F2",         "\e[[B"},
29992   {"F3",         "\e[[C"},
29993   {"F4",         "\e[[D"},
29994   {"F5",         "\e[[E"},
29995   {"F6",         "\e[[F"},
29996   {"F7",         "\e[[G"},
29997   {"F8",         "\e[[H"},
29998   {"F9",         "\e[[I"},
29999   {"F10",        "\e[[J"},
30000   {"F11",        "\e[[K"},
30001   {"F12",        "\e[[L"},
30002   {NULL, }
30003 };
fb_keyboard_match_keycode(const char * buf,int length,const MmmKeyCode ** ret)30004 static int fb_keyboard_match_keycode (const char *buf, int length, const MmmKeyCode **ret)
30005 {
30006   int i;
30007   int matches = 0;
30008 
30009   if (!strncmp (buf, "\e[M", MIN(length,3)))
30010     {
30011       if (length >= 6)
30012         return 9001;
30013       return 2342;
30014     }
30015   for (i = 0; ufb_keycodes[i].nick; i++)
30016     if (!strncmp (buf, ufb_keycodes[i].sequence, length))
30017       {
30018         matches ++;
30019         if ((int)strlen (ufb_keycodes[i].sequence) == length && ret)
30020           {
30021             *ret = &ufb_keycodes[i];
30022             return 1;
30023           }
30024       }
30025   if (matches != 1 && ret)
30026     *ret = NULL;
30027   return matches==1?2:matches;
30028 }
30029 
30030 //int is_active (void *host)
30031 //{
30032 //        return 1;
30033 //}
30034 
evsource_kb_get_event(void)30035 static char *evsource_kb_get_event (void)
30036 {
30037   unsigned char buf[20];
30038   int length;
30039 
30040 
30041   for (length = 0; length < 10; length ++)
30042     if (read (STDIN_FILENO, &buf[length], 1) != -1)
30043       {
30044         const MmmKeyCode *match = NULL;
30045 
30046         //if (!is_active (ctx_ev_src_kb.priv))
30047         //  return NULL;
30048 
30049         /* special case ESC, so that we can use it alone in keybindings */
30050         if (length == 0 && buf[0] == 27)
30051           {
30052             struct timeval tv;
30053             fd_set rfds;
30054             FD_ZERO (&rfds);
30055             FD_SET (STDIN_FILENO, &rfds);
30056             tv.tv_sec = 0;
30057             tv.tv_usec = 1000 * 120;
30058             if (select (STDIN_FILENO+1, &rfds, NULL, NULL, &tv) == 0)
30059               return strdup ("escape");
30060           }
30061 
30062         switch (fb_keyboard_match_keycode ((void*)buf, length + 1, &match))
30063           {
30064             case 1: /* unique match */
30065               if (!match)
30066                 return NULL;
30067               return strdup (match->nick);
30068               break;
30069             case 0: /* no matches, bail*/
30070              {
30071                 static char ret[256]="";
30072                 if (length == 0 && ctx_utf8_len (buf[0])>1) /* read a
30073                                                              * single unicode
30074                                                              * utf8 character
30075                                                              */
30076                   {
30077                     int bytes = read (STDIN_FILENO, &buf[length+1], ctx_utf8_len(buf[0])-1);
30078                     if (bytes)
30079                     {
30080                       buf[ctx_utf8_len(buf[0])]=0;
30081                       strcpy (ret, (void*)buf);
30082                     }
30083                     return strdup(ret); //XXX: simplify
30084                   }
30085                 if (length == 0) /* ascii */
30086                   {
30087                     buf[1]=0;
30088                     strcpy (ret, (void*)buf);
30089                     return strdup(ret);
30090                   }
30091                 sprintf (ret, "unhandled %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c' %i:'%c'",
30092                     length >=0 ? buf[0] : 0,
30093                     length >=0 ? buf[0]>31?buf[0]:'?' : ' ',
30094                     length >=1 ? buf[1] : 0,
30095                     length >=1 ? buf[1]>31?buf[1]:'?' : ' ',
30096                     length >=2 ? buf[2] : 0,
30097                     length >=2 ? buf[2]>31?buf[2]:'?' : ' ',
30098                     length >=3 ? buf[3] : 0,
30099                     length >=3 ? buf[3]>31?buf[3]:'?' : ' ',
30100                     length >=4 ? buf[4] : 0,
30101                     length >=4 ? buf[4]>31?buf[4]:'?' : ' ',
30102                     length >=5 ? buf[5] : 0,
30103                     length >=5 ? buf[5]>31?buf[5]:'?' : ' ',
30104                     length >=6 ? buf[6] : 0,
30105                     length >=6 ? buf[6]>31?buf[6]:'?' : ' '
30106                     );
30107                 return strdup(ret);
30108             }
30109               return NULL;
30110             default: /* continue */
30111               break;
30112           }
30113       }
30114     else
30115       return strdup("key read eek");
30116   return strdup("fail");
30117 }
30118 
evsource_kb_get_fd(void)30119 static int evsource_kb_get_fd (void)
30120 {
30121   return STDIN_FILENO;
30122 }
30123 
30124 
evsource_kb_new(void)30125 static EvSource *evsource_kb_new (void)
30126 {
30127   if (evsource_kb_init() == 0)
30128   {
30129     return &ctx_ev_src_kb;
30130   }
30131   return NULL;
30132 }
30133 
event_check_pending(CtxTiled * tiled)30134 static int event_check_pending (CtxTiled *tiled)
30135 {
30136   int events = 0;
30137   for (int i = 0; i < tiled->evsource_count; i++)
30138   {
30139     while (evsource_has_event (tiled->evsource[i]))
30140     {
30141       char *event = evsource_get_event (tiled->evsource[i]);
30142       if (event)
30143       {
30144         if (tiled->vt_active)
30145         {
30146           ctx_key_press (tiled->ctx, 0, event, 0); // we deliver all events as key-press, the key_press handler disambiguates
30147           events++;
30148         }
30149         free (event);
30150       }
30151     }
30152   }
30153   return events;
30154 }
30155 
ctx_renderer_is_tiled(Ctx * ctx)30156 int ctx_renderer_is_tiled (Ctx *ctx)
30157 {
30158   return ctx_renderer_is_fb (ctx)
30159           || ctx_renderer_is_sdl (ctx)
30160        || ctx_renderer_is_kms (ctx)
30161      ;
30162 }
30163 
30164 #endif
30165 
30166 #if CTX_EVENTS
30167 
30168 #if !__COSMOPOLITAN__
30169 #include <fcntl.h>
30170 #include <sys/ioctl.h>
30171 #include <signal.h>
30172 #endif
30173 
30174 #if CTX_KMS || CTX_FB
30175 static char *ctx_fb_clipboard = NULL;
ctx_fb_set_clipboard(void * fb,const char * text)30176 static void ctx_fb_set_clipboard (void *fb, const char *text)
30177 {
30178   if (ctx_fb_clipboard)
30179     free (ctx_fb_clipboard);
30180   ctx_fb_clipboard = NULL;
30181   if (text)
30182   {
30183     ctx_fb_clipboard = strdup (text);
30184   }
30185 }
30186 
ctx_fb_get_clipboard(void * sdl)30187 static char *ctx_fb_get_clipboard (void *sdl)
30188 {
30189   if (ctx_fb_clipboard) return strdup (ctx_fb_clipboard);
30190   return strdup ("");
30191 }
30192 #endif
30193 
30194 
30195 #if CTX_KMS
30196 #ifdef __linux__
30197   #include <linux/kd.h>
30198 #endif
30199   //#include <linux/fb.h>
30200   //#include <linux/vt.h>
30201   #include <sys/mman.h>
30202   //#include <threads.h>
30203   #include <libdrm/drm.h>
30204   #include <libdrm/drm_mode.h>
30205 
30206 
30207 typedef struct _CtxKMS CtxKMS;
30208 struct _CtxKMS
30209 {
30210    CtxTiled tiled;
30211 #if 0
30212    void (*render) (void *fb, CtxCommand *command);
30213    void (*reset)  (void *fb);
30214    void (*flush)  (void *fb);
30215    char *(*get_clipboard) (void *ctxctx);
30216    void (*set_clipboard) (void *ctxctx, const char *text);
30217    void (*free)   (void *fb);
30218    Ctx          *ctx;
30219    int           width;
30220    int           height;
30221    int           cols; // unused
30222    int           rows; // unused
30223    int           was_down;
30224    uint8_t      *pixels;
30225    Ctx          *ctx_copy;
30226    Ctx          *host[CTX_MAX_THREADS];
30227    CtxAntialias  antialias;
30228    int           quit;
30229    _Atomic int   thread_quit;
30230    int           shown_frame;
30231    int           render_frame;
30232    int           rendered_frame[CTX_MAX_THREADS];
30233    int           frame;
30234    int           min_col; // hasher cols and rows
30235    int           min_row;
30236    int           max_col;
30237    int           max_row;
30238    uint8_t       hashes[CTX_HASH_ROWS * CTX_HASH_COLS *  20];
30239    int8_t        tile_affinity[CTX_HASH_ROWS * CTX_HASH_COLS]; // which render thread no is
30240                                                            // responsible for a tile
30241                                                            //
30242 
30243 
30244    int           pointer_down[3];
30245 #endif
30246    int           key_balance;
30247    int           key_repeat;
30248    int           lctrl;
30249    int           lalt;
30250    int           rctrl;
30251 
30252    int          fb_fd;
30253    char        *fb_path;
30254    int          fb_bits;
30255    int          fb_bpp;
30256    int          fb_mapped_size;
30257    //struct       fb_var_screeninfo vinfo;
30258    //struct       fb_fix_screeninfo finfo;
30259    int          vt;
30260    int          tty;
30261    int          is_kms;
30262    cnd_t        cond;
30263    mtx_t        mtx;
30264    struct drm_mode_crtc crtc;
30265 };
30266 
30267 
30268 #if UINTPTR_MAX == 0xffFFffFF
30269   #define fbdrmuint_t uint32_t
30270 #elif UINTPTR_MAX == 0xffFFffFFffFFffFF
30271   #define fbdrmuint_t uint64_t
30272 #endif
30273 
ctx_fbkms_new(CtxKMS * fb,int * width,int * height)30274 void *ctx_fbkms_new (CtxKMS *fb, int *width, int *height)
30275 {
30276    int got_master = 0;
30277    fb->fb_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
30278    if (!fb->fb_fd)
30279      return NULL;
30280    static fbdrmuint_t res_conn_buf[20]={0}; // this is static since its contents
30281                                          // are used by the flip callback
30282    fbdrmuint_t res_fb_buf[20]={0};
30283    fbdrmuint_t res_crtc_buf[20]={0};
30284    fbdrmuint_t res_enc_buf[20]={0};
30285    struct   drm_mode_card_res res={0};
30286 
30287    if (ioctl(fb->fb_fd, DRM_IOCTL_SET_MASTER, 0))
30288      goto cleanup;
30289    got_master = 1;
30290 
30291    if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
30292      goto cleanup;
30293    res.fb_id_ptr=(fbdrmuint_t)res_fb_buf;
30294    res.crtc_id_ptr=(fbdrmuint_t)res_crtc_buf;
30295    res.connector_id_ptr=(fbdrmuint_t)res_conn_buf;
30296    res.encoder_id_ptr=(fbdrmuint_t)res_enc_buf;
30297    if(ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
30298       goto cleanup;
30299 
30300 
30301    unsigned int i;
30302    for (i=0;i<res.count_connectors;i++)
30303    {
30304      struct drm_mode_modeinfo conn_mode_buf[20]={0};
30305      fbdrmuint_t conn_prop_buf[20]={0},
30306                      conn_propval_buf[20]={0},
30307                      conn_enc_buf[20]={0};
30308 
30309      struct drm_mode_get_connector conn={0};
30310 
30311      conn.connector_id=res_conn_buf[i];
30312 
30313      if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
30314        goto cleanup;
30315 
30316      conn.modes_ptr=(fbdrmuint_t)conn_mode_buf;
30317      conn.props_ptr=(fbdrmuint_t)conn_prop_buf;
30318      conn.prop_values_ptr=(fbdrmuint_t)conn_propval_buf;
30319      conn.encoders_ptr=(fbdrmuint_t)conn_enc_buf;
30320 
30321      if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
30322        goto cleanup;
30323 
30324      //Check if the connector is OK to use (connected to something)
30325      if (conn.count_encoders<1 || conn.count_modes<1 || !conn.encoder_id || !conn.connection)
30326        continue;
30327 
30328 //------------------------------------------------------------------------------
30329 //Creating a dumb buffer
30330 //------------------------------------------------------------------------------
30331      struct drm_mode_create_dumb create_dumb={0};
30332      struct drm_mode_map_dumb    map_dumb={0};
30333      struct drm_mode_fb_cmd      cmd_dumb={0};
30334      create_dumb.width  = conn_mode_buf[0].hdisplay;
30335      create_dumb.height = conn_mode_buf[0].vdisplay;
30336      create_dumb.bpp   = 32;
30337      create_dumb.flags = 0;
30338      create_dumb.pitch = 0;
30339      create_dumb.size  = 0;
30340      create_dumb.handle = 0;
30341      if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) ||
30342          !create_dumb.handle)
30343        goto cleanup;
30344 
30345      cmd_dumb.width =create_dumb.width;
30346      cmd_dumb.height=create_dumb.height;
30347      cmd_dumb.bpp   =create_dumb.bpp;
30348      cmd_dumb.pitch =create_dumb.pitch;
30349      cmd_dumb.depth =24;
30350      cmd_dumb.handle=create_dumb.handle;
30351      if (ioctl(fb->fb_fd,DRM_IOCTL_MODE_ADDFB,&cmd_dumb))
30352        goto cleanup;
30353 
30354      map_dumb.handle=create_dumb.handle;
30355      if (ioctl(fb->fb_fd,DRM_IOCTL_MODE_MAP_DUMB,&map_dumb))
30356        goto cleanup;
30357 
30358      void *base = mmap(0, create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED,
30359                        fb->fb_fd, map_dumb.offset);
30360      if (!base)
30361      {
30362        goto cleanup;
30363      }
30364      *width  = create_dumb.width;
30365      *height = create_dumb.height;
30366 
30367      struct drm_mode_get_encoder enc={0};
30368      enc.encoder_id=conn.encoder_id;
30369      if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETENCODER, &enc))
30370         goto cleanup;
30371 
30372      fb->crtc.crtc_id=enc.crtc_id;
30373      if (ioctl(fb->fb_fd, DRM_IOCTL_MODE_GETCRTC, &fb->crtc))
30374         goto cleanup;
30375 
30376      fb->crtc.fb_id=cmd_dumb.fb_id;
30377      fb->crtc.set_connectors_ptr=(fbdrmuint_t)&res_conn_buf[i];
30378      fb->crtc.count_connectors=1;
30379      fb->crtc.mode=conn_mode_buf[0];
30380      fb->crtc.mode_valid=1;
30381      return base;
30382    }
30383 cleanup:
30384    if (got_master)
30385      ioctl(fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
30386    fb->fb_fd = 0;
30387    return NULL;
30388 }
30389 
ctx_fbkms_flip(CtxKMS * fb)30390 void ctx_fbkms_flip (CtxKMS *fb)
30391 {
30392   if (!fb->fb_fd)
30393     return;
30394   ioctl(fb->fb_fd, DRM_IOCTL_MODE_SETCRTC, &fb->crtc);
30395 }
30396 
ctx_fbkms_close(CtxKMS * fb)30397 void ctx_fbkms_close (CtxKMS *fb)
30398 {
30399   if (!fb->fb_fd)
30400     return;
30401   ioctl(fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
30402   close (fb->fb_fd);
30403   fb->fb_fd = 0;
30404 }
30405 
ctx_kms_flip(CtxKMS * fb)30406 static void ctx_kms_flip (CtxKMS *fb)
30407 {
30408   if (fb->is_kms)
30409     ctx_fbkms_flip (fb);
30410 #if 0
30411   else
30412     ioctl (fb->fb_fd, FBIOPAN_DISPLAY, &fb->vinfo);
30413 #endif
30414 }
30415 
30416 inline static uint32_t
ctx_swap_red_green2(uint32_t orig)30417 ctx_swap_red_green2 (uint32_t orig)
30418 {
30419   uint32_t  green_alpha = (orig & 0xff00ff00);
30420   uint32_t  red_blue    = (orig & 0x00ff00ff);
30421   uint32_t  red         = red_blue << 16;
30422   uint32_t  blue        = red_blue >> 16;
30423   return green_alpha | red | blue;
30424 }
30425 
ctx_kms_show_frame(CtxKMS * fb,int block)30426 static void ctx_kms_show_frame (CtxKMS *fb, int block)
30427 {
30428   CtxTiled *tiled = (void*)fb;
30429   if (tiled->shown_frame == tiled->render_frame)
30430   {
30431     if (block == 0) // consume event call
30432     {
30433       ctx_tiled_draw_cursor ((CtxTiled*)fb);
30434       ctx_kms_flip (fb);
30435     }
30436     return;
30437   }
30438 
30439   if (block)
30440   {
30441     int count = 0;
30442     while (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
30443     {
30444       usleep (500);
30445       count ++;
30446       if (count > 500)
30447       {
30448         tiled->shown_frame = tiled->render_frame;
30449         return;
30450       }
30451     }
30452   }
30453   else
30454   {
30455     if (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
30456       return;
30457   }
30458 
30459     if (tiled->vt_active)
30460     {
30461        int pre_skip = tiled->min_row * tiled->height/CTX_HASH_ROWS * tiled->width;
30462        int post_skip = (CTX_HASH_ROWS-tiled->max_row-1) * tiled->height/CTX_HASH_ROWS * tiled->width;
30463 
30464        int rows = ((tiled->width * tiled->height) - pre_skip - post_skip)/tiled->width;
30465 
30466        int col_pre_skip = tiled->min_col * tiled->width/CTX_HASH_COLS;
30467        int col_post_skip = (CTX_HASH_COLS-tiled->max_col-1) * tiled->width/CTX_HASH_COLS;
30468        if (_ctx_damage_control)
30469        {
30470          pre_skip = post_skip = col_pre_skip = col_post_skip = 0;
30471        }
30472 
30473        if (pre_skip < 0) pre_skip = 0;
30474        if (post_skip < 0) post_skip = 0;
30475 
30476 
30477        if (tiled->min_row == 100){
30478           pre_skip = 0;
30479           post_skip = 0;
30480           // not when kms ?
30481 #if 0
30482      __u32 dummy = 0;
30483           ioctl (fb->fb_fd, FBIO_WAITFORVSYNC, &dummy);
30484 #endif
30485           ctx_tiled_undraw_cursor ((CtxTiled*)fb);
30486        }
30487        else
30488        {
30489 
30490       tiled->min_row = 100;
30491       tiled->max_row = 0;
30492       tiled->min_col = 100;
30493       tiled->max_col = 0;
30494 
30495      // not when kms ?
30496  #if 0
30497      __u32 dummy = 0;
30498      ioctl (fb->fb_fd, FBIO_WAITFORVSYNC, &dummy);
30499 #endif
30500      ctx_tiled_undraw_cursor ((CtxTiled*)fb);
30501      switch (fb->fb_bits)
30502      {
30503        case 32:
30504 #if 1
30505          {
30506            uint8_t *dst = tiled->fb + pre_skip * 4;
30507            uint8_t *src = tiled->pixels + pre_skip * 4;
30508            int pre = col_pre_skip * 4;
30509            int post = col_post_skip * 4;
30510            int core = tiled->width * 4 - pre - post;
30511            for (int i = 0; i < rows; i++)
30512            {
30513              dst  += pre;
30514              src  += pre;
30515              memcpy (dst, src, core);
30516              src  += core;
30517              dst  += core;
30518              dst  += post;
30519              src  += post;
30520            }
30521          }
30522 #else
30523          { int count = tiled->width * tiled->height;
30524            const uint32_t *src = (void*)tiled->pixels;
30525            uint32_t *dst = (void*)tiled->fb;
30526            count-= pre_skip;
30527            src+= pre_skip;
30528            dst+= pre_skip;
30529            count-= post_skip;
30530            while (count -- > 0)
30531            {
30532              dst[0] = ctx_swap_red_green2 (src[0]);
30533              src++;
30534              dst++;
30535            }
30536          }
30537 #endif
30538          break;
30539          /* XXX  :  note: converting a scanline (or all) to target and
30540           * then doing a bulk memcpy be faster (at least with som /dev/fbs)  */
30541        case 24:
30542          { int count = tiled->width * tiled->height;
30543            const uint8_t *src = tiled->pixels;
30544            uint8_t *dst = tiled->fb;
30545            count-= pre_skip;
30546            src+= pre_skip * 4;
30547            dst+= pre_skip * 3;
30548            count-= post_skip;
30549            while (count -- > 0)
30550            {
30551              dst[0] = src[0];
30552              dst[1] = src[1];
30553              dst[2] = src[2];
30554              dst+=3;
30555              src+=4;
30556            }
30557          }
30558          break;
30559        case 16:
30560          { int count = tiled->width * tiled->height;
30561            const uint8_t *src = tiled->pixels;
30562            uint8_t *dst = tiled->fb;
30563            count-= post_skip;
30564            count-= pre_skip;
30565            src+= pre_skip * 4;
30566            dst+= pre_skip * 2;
30567            while (count -- > 0)
30568            {
30569              int big = ((src[0] >> 3)) +
30570                 ((src[1] >> 2)<<5) +
30571                 ((src[2] >> 3)<<11);
30572              dst[0] = big & 255;
30573              dst[1] = big >>  8;
30574              dst+=2;
30575              src+=4;
30576            }
30577          }
30578          break;
30579        case 15:
30580          { int count = tiled->width * tiled->height;
30581            const uint8_t *src = tiled->pixels;
30582            uint8_t *dst = tiled->fb;
30583            count-= post_skip;
30584            count-= pre_skip;
30585            src+= pre_skip * 4;
30586            dst+= pre_skip * 2;
30587            while (count -- > 0)
30588            {
30589              int big = ((src[2] >> 3)) +
30590                        ((src[1] >> 2)<<5) +
30591                        ((src[0] >> 3)<<10);
30592              dst[0] = big & 255;
30593              dst[1] = big >>  8;
30594              dst+=2;
30595              src+=4;
30596            }
30597          }
30598          break;
30599        case 8:
30600          { int count = tiled->width * tiled->height;
30601            const uint8_t *src = tiled->pixels;
30602            uint8_t *dst = tiled->fb;
30603            count-= post_skip;
30604            count-= pre_skip;
30605            src+= pre_skip * 4;
30606            dst+= pre_skip;
30607            while (count -- > 0)
30608            {
30609              dst[0] = ((src[0] >> 5)) +
30610                       ((src[1] >> 5)<<3) +
30611                       ((src[2] >> 6)<<6);
30612              dst+=1;
30613              src+=4;
30614            }
30615          }
30616          break;
30617      }
30618     }
30619     ctx_tiled_cursor_drawn = 0;
30620     ctx_tiled_draw_cursor (&fb->tiled);
30621     ctx_kms_flip (fb);
30622     tiled->shown_frame = tiled->render_frame;
30623   }
30624 }
30625 
ctx_kms_consume_events(Ctx * ctx)30626 int ctx_kms_consume_events (Ctx *ctx)
30627 {
30628   CtxKMS *fb = (void*)ctx->renderer;
30629   ctx_kms_show_frame (fb, 0);
30630   event_check_pending (&fb->tiled);
30631   return 0;
30632 }
30633 
ctx_kms_reset(CtxKMS * fb)30634 inline static void ctx_kms_reset (CtxKMS *fb)
30635 {
30636   ctx_kms_show_frame (fb, 1);
30637 }
30638 
ctx_kms_flush(CtxKMS * fb)30639 inline static void ctx_kms_flush (CtxKMS *fb)
30640 {
30641   ctx_tiled_flush ((CtxTiled*)fb);
30642 }
30643 
ctx_kms_free(CtxKMS * fb)30644 void ctx_kms_free (CtxKMS *fb)
30645 {
30646   if (fb->is_kms)
30647   {
30648     ctx_fbkms_close (fb);
30649   }
30650 #ifdef __linux__
30651   ioctl (0, KDSETMODE, KD_TEXT);
30652 #endif
30653   if (system("stty sane")){};
30654   ctx_tiled_free ((CtxTiled*)fb);
30655   //free (fb);
30656 #if CTX_BABL
30657   babl_exit ();
30658 #endif
30659 }
30660 
30661 //static unsigned char *fb_icc = NULL;
30662 //static long fb_icc_length = 0;
30663 
ctx_renderer_is_kms(Ctx * ctx)30664 int ctx_renderer_is_kms (Ctx *ctx)
30665 {
30666   if (ctx->renderer &&
30667       ctx->renderer->free == (void*)ctx_kms_free)
30668           return 1;
30669   return 0;
30670 }
30671 
30672 #if 0
30673 static CtxKMS *ctx_fb = NULL;
30674 static void vt_switch_cb (int sig)
30675 {
30676   CtxTiled *tiled = (void*)ctx_fb;
30677   if (sig == SIGUSR1)
30678   {
30679     if (ctx_fb->is_kms)
30680       ioctl(ctx_fb->fb_fd, DRM_IOCTL_DROP_MASTER, 0);
30681     ioctl (0, VT_RELDISP, 1);
30682     ctx_fb->vt_active = 0;
30683 #if 0
30684     ioctl (0, KDSETMODE, KD_TEXT);
30685 #endif
30686   }
30687   else
30688   {
30689     ioctl (0, VT_RELDISP, VT_ACKACQ);
30690     ctx_fb->vt_active = 1;
30691     // queue draw
30692     tiled->render_frame = ++tiled->frame;
30693 #if 0
30694     ioctl (0, KDSETMODE, KD_GRAPHICS);
30695 #endif
30696     if (ctx_fb->is_kms)
30697     {
30698       ioctl(ctx_fb->fb_fd, DRM_IOCTL_SET_MASTER, 0);
30699       ctx_kms_flip (ctx_fb);
30700     }
30701     else
30702     {
30703       tiled->ctx->dirty=1;
30704 
30705       for (int row = 0; row < CTX_HASH_ROWS; row++)
30706       for (int col = 0; col < CTX_HASH_COLS; col++)
30707       {
30708         tiled->hashes[(row * CTX_HASH_COLS + col) *  20] += 1;
30709       }
30710     }
30711   }
30712 }
30713 #endif
30714 
ctx_kms_get_mice_fd(Ctx * ctx)30715 static int ctx_kms_get_mice_fd (Ctx *ctx)
30716 {
30717   //CtxKMS *fb = (void*)ctx->renderer;
30718   return _ctx_mice_fd;
30719 }
30720 
ctx_new_kms(int width,int height)30721 Ctx *ctx_new_kms (int width, int height)
30722 {
30723 #if CTX_RASTERIZER
30724   CtxKMS *fb = calloc (sizeof (CtxKMS), 1);
30725 
30726   CtxTiled *tiled = (void*)fb;
30727   tiled->fb = ctx_fbkms_new (fb, &tiled->width, &tiled->height);
30728   if (tiled->fb)
30729   {
30730     fb->is_kms         = 1;
30731     width              = tiled->width;
30732     height             = tiled->height;
30733     /*
30734        we're ignoring the input width and height ,
30735        maybe turn them into properties - for
30736        more generic handling.
30737      */
30738     fb->fb_mapped_size = tiled->width * tiled->height * 4;
30739     fb->fb_bits        = 32;
30740     fb->fb_bpp         = 4;
30741   }
30742   if (!tiled->fb)
30743     return NULL;
30744   tiled->pixels = calloc (fb->fb_mapped_size, 1);
30745   ctx_kms_events = 1;
30746 
30747 #if CTX_BABL
30748   babl_init ();
30749 #endif
30750 
30751   ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
30752 
30753   tiled->ctx      = ctx_new ();
30754   tiled->ctx_copy = ctx_new ();
30755   tiled->width    = width;
30756   tiled->height   = height;
30757 
30758   ctx_set_renderer (tiled->ctx, fb);
30759   ctx_set_renderer (tiled->ctx_copy, fb);
30760   ctx_set_texture_cache (tiled->ctx_copy, tiled->ctx);
30761 
30762   ctx_set_size (tiled->ctx, width, height);
30763   ctx_set_size (tiled->ctx_copy, width, height);
30764 
30765   tiled->flush = (void*)ctx_kms_flush;
30766   tiled->reset = (void*)ctx_kms_reset;
30767   tiled->free  = (void*)ctx_kms_free;
30768   tiled->set_clipboard = (void*)ctx_fb_set_clipboard;
30769   tiled->get_clipboard = (void*)ctx_fb_get_clipboard;
30770 
30771   for (int i = 0; i < _ctx_max_threads; i++)
30772   {
30773     tiled->host[i] = ctx_new_for_framebuffer (tiled->pixels,
30774                    tiled->width/CTX_HASH_COLS, tiled->height/CTX_HASH_ROWS,
30775                    tiled->width * 4, CTX_FORMAT_BGRA8); // this format
30776                                   // is overriden in  thread
30777     ((CtxRasterizer*)(tiled->host[i]->renderer))->swap_red_green = 1;
30778     ctx_set_texture_source (tiled->host[i], tiled->ctx);
30779   }
30780 
30781   mtx_init (&tiled->mtx, mtx_plain);
30782   cnd_init (&tiled->cond);
30783 
30784 #define start_thread(no)\
30785   if(_ctx_max_threads>no){ \
30786     static void *args[2]={(void*)no, };\
30787     thrd_t tid;\
30788     args[1]=fb;\
30789     thrd_create (&tid, (void*)ctx_tiled_render_fun, args);\
30790   }
30791   start_thread(0);
30792   start_thread(1);
30793   start_thread(2);
30794   start_thread(3);
30795   start_thread(4);
30796   start_thread(5);
30797   start_thread(6);
30798   start_thread(7);
30799   start_thread(8);
30800   start_thread(9);
30801   start_thread(10);
30802   start_thread(11);
30803   start_thread(12);
30804   start_thread(13);
30805   start_thread(14);
30806   start_thread(15);
30807 #undef start_thread
30808 
30809 
30810   EvSource *kb = evsource_kb_new ();
30811   if (kb)
30812   {
30813     tiled->evsource[tiled->evsource_count++] = kb;
30814     kb->priv = fb;
30815   }
30816   EvSource *mice  = evsource_mice_new ();
30817   if (mice)
30818   {
30819     tiled->evsource[tiled->evsource_count++] = mice;
30820     mice->priv = fb;
30821   }
30822 
30823   tiled->vt_active = 1;
30824 #ifdef __linux__
30825   ioctl(0, KDSETMODE, KD_GRAPHICS);
30826 #endif
30827   tiled->shown_frame = tiled->render_frame;
30828   //ctx_flush (tiled->ctx);
30829 #if 0
30830   signal (SIGUSR1, vt_switch_cb);
30831   signal (SIGUSR2, vt_switch_cb);
30832 
30833   struct vt_stat st;
30834   if (ioctl (0, VT_GETSTATE, &st) == -1)
30835   {
30836     ctx_log ("VT_GET_MODE on vt %i failed\n", fb->vt);
30837     return NULL;
30838   }
30839 
30840   fb->vt = st.v_active;
30841 
30842   struct vt_mode mode;
30843   mode.mode   = VT_PROCESS;
30844   mode.relsig = SIGUSR1;
30845   mode.acqsig = SIGUSR2;
30846   if (ioctl (0, VT_SETMODE, &mode) < 0)
30847   {
30848     ctx_log ("VT_SET_MODE on vt %i failed\n", fb->vt);
30849     return NULL;
30850   }
30851 #endif
30852 
30853   return tiled->ctx;
30854 #else
30855   return NULL;
30856 #endif
30857 }
30858 #else
30859 
ctx_renderer_is_kms(Ctx * ctx)30860 int ctx_renderer_is_kms (Ctx *ctx)
30861 {
30862   return 0;
30863 }
30864 
30865 #endif
30866 #endif
30867 
30868 #if CTX_EVENTS
30869 
30870 #if !__COSMOPOLITAN__
30871 #include <fcntl.h>
30872 #include <sys/ioctl.h>
30873 #include <signal.h>
30874 #endif
30875 
30876 #if CTX_FB
ctx_fb_get_mice_fd(Ctx * ctx)30877 static int ctx_fb_get_mice_fd (Ctx *ctx)
30878 {
30879   //CtxFb *fb = (void*)ctx->renderer;
30880   return _ctx_mice_fd;
30881 }
30882 
30883 #ifdef __linux__
30884   #include <linux/fb.h>
30885   #include <linux/vt.h>
30886   #include <linux/kd.h>
30887 #endif
30888 
30889 #ifdef __NetBSD__
30890   typedef uint8_t unchar;
30891   typedef uint8_t u_char;
30892   typedef uint16_t ushort;
30893   typedef uint32_t u_int;
30894   typedef uint64_t u_long;
30895   #include <sys/param.h>
30896   #include <dev/wscons/wsdisplay_usl_io.h>
30897   #include <dev/wscons/wsconsio.h>
30898   #include <dev/wscons/wsksymdef.h>
30899 #endif
30900 
30901   #include <sys/mman.h>
30902 
30903 typedef struct _CtxFb CtxFb;
30904 struct _CtxFb
30905 {
30906    CtxTiled tiled;
30907 #if 0
30908    void (*render) (void *fb, CtxCommand *command);
30909    void (*reset)  (void *fb);
30910    void (*flush)  (void *fb);
30911    char *(*get_clipboard) (void *ctxctx);
30912    void (*set_clipboard) (void *ctxctx, const char *text);
30913    void (*free)   (void *fb);
30914    Ctx          *ctx;
30915    int           width;
30916    int           height;
30917    int           cols; // unused
30918    int           rows; // unused
30919    int           was_down;
30920    uint8_t      *pixels;
30921    Ctx          *ctx_copy;
30922    Ctx          *host[CTX_MAX_THREADS];
30923    CtxAntialias  antialias;
30924    int           quit;
30925    _Atomic int   thread_quit;
30926    int           shown_frame;
30927    int           render_frame;
30928    int           rendered_frame[CTX_MAX_THREADS];
30929    int           frame;
30930    int           min_col; // hasher cols and rows
30931    int           min_row;
30932    int           max_col;
30933    int           max_row;
30934    uint8_t       hashes[CTX_HASH_ROWS * CTX_HASH_COLS *  20];
30935    int8_t        tile_affinity[CTX_HASH_ROWS * CTX_HASH_COLS]; // which render thread no is
30936                                                            // responsible for a tile
30937                                                            //
30938 
30939 
30940    int           pointer_down[3];
30941 #endif
30942    int           key_balance;
30943    int           key_repeat;
30944    int           lctrl;
30945    int           lalt;
30946    int           rctrl;
30947 
30948 
30949    int          fb_fd;
30950    char        *fb_path;
30951    int          fb_bits;
30952    int          fb_bpp;
30953    int          fb_mapped_size;
30954    int          vt;
30955    int          tty;
30956    cnd_t        cond;
30957    mtx_t        mtx;
30958 #if __linux__
30959    struct       fb_var_screeninfo vinfo;
30960    struct       fb_fix_screeninfo finfo;
30961 #endif
30962 };
30963 
30964 #if UINTPTR_MAX == 0xffFFffFF
30965   #define fbdrmuint_t uint32_t
30966 #elif UINTPTR_MAX == 0xffFFffFFffFFffFF
30967   #define fbdrmuint_t uint64_t
30968 #endif
30969 
30970 
ctx_fb_flip(CtxFb * fb)30971 static void ctx_fb_flip (CtxFb *fb)
30972 {
30973 #ifdef __linux__
30974   ioctl (fb->fb_fd, FBIOPAN_DISPLAY, &fb->vinfo);
30975 #endif
30976 }
30977 
ctx_fb_show_frame(CtxFb * fb,int block)30978 static void ctx_fb_show_frame (CtxFb *fb, int block)
30979 {
30980   CtxTiled *tiled = (void*)fb;
30981   if (tiled->shown_frame == tiled->render_frame)
30982   {
30983     if (block == 0) // consume event call
30984     {
30985       ctx_tiled_draw_cursor (tiled);
30986       ctx_fb_flip (fb);
30987     }
30988     return;
30989   }
30990 
30991   if (block)
30992   {
30993     int count = 0;
30994     while (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
30995     {
30996       usleep (500);
30997       count ++;
30998       if (count > 2000)
30999       {
31000         tiled->shown_frame = tiled->render_frame;
31001         return;
31002       }
31003     }
31004   }
31005   else
31006   {
31007     if (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
31008       return;
31009   }
31010 
31011     if (tiled->vt_active)
31012     {
31013        int pre_skip = tiled->min_row * tiled->height/CTX_HASH_ROWS * tiled->width;
31014        int post_skip = (CTX_HASH_ROWS-tiled->max_row-1) * tiled->height/CTX_HASH_ROWS * tiled->width;
31015 
31016        int rows = ((tiled->width * tiled->height) - pre_skip - post_skip)/tiled->width;
31017 
31018        int col_pre_skip = tiled->min_col * tiled->width/CTX_HASH_COLS;
31019        int col_post_skip = (CTX_HASH_COLS-tiled->max_col-1) * tiled->width/CTX_HASH_COLS;
31020        if (_ctx_damage_control)
31021        {
31022          pre_skip = post_skip = col_pre_skip = col_post_skip = 0;
31023        }
31024 
31025        if (pre_skip < 0) pre_skip = 0;
31026        if (post_skip < 0) post_skip = 0;
31027 
31028 
31029        if (tiled->min_row == 100){
31030           pre_skip = 0;
31031           post_skip = 0;
31032 #ifdef __linux__
31033            __u32 dummy = 0;
31034           ioctl (fb->fb_fd, FBIO_WAITFORVSYNC, &dummy);
31035 #endif
31036           ctx_tiled_undraw_cursor (tiled);
31037        }
31038        else
31039        {
31040 
31041       tiled->min_row = 100;
31042       tiled->max_row = 0;
31043       tiled->min_col = 100;
31044       tiled->max_col = 0;
31045 #ifdef __linux__
31046     {
31047      __u32 dummy = 0;
31048      ioctl (fb->fb_fd, FBIO_WAITFORVSYNC, &dummy);
31049     }
31050 #endif
31051      ctx_tiled_undraw_cursor (tiled);
31052      switch (fb->fb_bits)
31053      {
31054        case 32:
31055 #if 1
31056          {
31057            uint8_t *dst = tiled->fb + pre_skip * 4;
31058            uint8_t *src = tiled->pixels + pre_skip * 4;
31059            int pre = col_pre_skip * 4;
31060            int post = col_post_skip * 4;
31061            int core = tiled->width * 4 - pre - post;
31062            for (int i = 0; i < rows; i++)
31063            {
31064              dst  += pre;
31065              src  += pre;
31066              memcpy (dst, src, core);
31067              src  += core;
31068              dst  += core;
31069              dst  += post;
31070              src  += post;
31071            }
31072          }
31073 #else
31074          { int count = tiled->width * tiled->height;
31075            const uint32_t *src = (void*)tiled->pixels;
31076            uint32_t *dst = (void*)tiled->fb;
31077            count-= pre_skip;
31078            src+= pre_skip;
31079            dst+= pre_skip;
31080            count-= post_skip;
31081            while (count -- > 0)
31082            {
31083              dst[0] = ctx_swap_red_green2 (src[0]);
31084              src++;
31085              dst++;
31086            }
31087          }
31088 #endif
31089          break;
31090          /* XXX  :  note: converting a scanline (or all) to target and
31091           * then doing a bulk memcpy be faster (at least with som /dev/fbs)  */
31092        case 24:
31093          { int count = tiled->width * tiled->height;
31094            const uint8_t *src = tiled->pixels;
31095            uint8_t *dst = tiled->fb;
31096            count-= pre_skip;
31097            src+= pre_skip * 4;
31098            dst+= pre_skip * 3;
31099            count-= post_skip;
31100            while (count -- > 0)
31101            {
31102              dst[0] = src[0];
31103              dst[1] = src[1];
31104              dst[2] = src[2];
31105              dst+=3;
31106              src+=4;
31107            }
31108          }
31109          break;
31110        case 16:
31111          { int count = tiled->width * tiled->height;
31112            const uint8_t *src = tiled->pixels;
31113            uint8_t *dst = tiled->fb;
31114            count-= post_skip;
31115            count-= pre_skip;
31116            src+= pre_skip * 4;
31117            dst+= pre_skip * 2;
31118            while (count -- > 0)
31119            {
31120              int big = ((src[0] >> 3)) +
31121                 ((src[1] >> 2)<<5) +
31122                 ((src[2] >> 3)<<11);
31123              dst[0] = big & 255;
31124              dst[1] = big >>  8;
31125              dst+=2;
31126              src+=4;
31127            }
31128          }
31129          break;
31130        case 15:
31131          { int count = tiled->width * tiled->height;
31132            const uint8_t *src = tiled->pixels;
31133            uint8_t *dst = tiled->fb;
31134            count-= post_skip;
31135            count-= pre_skip;
31136            src+= pre_skip * 4;
31137            dst+= pre_skip * 2;
31138            while (count -- > 0)
31139            {
31140              int big = ((src[2] >> 3)) +
31141                        ((src[1] >> 2)<<5) +
31142                        ((src[0] >> 3)<<10);
31143              dst[0] = big & 255;
31144              dst[1] = big >>  8;
31145              dst+=2;
31146              src+=4;
31147            }
31148          }
31149          break;
31150        case 8:
31151          { int count = tiled->width * tiled->height;
31152            const uint8_t *src = tiled->pixels;
31153            uint8_t *dst = tiled->fb;
31154            count-= post_skip;
31155            count-= pre_skip;
31156            src+= pre_skip * 4;
31157            dst+= pre_skip;
31158            while (count -- > 0)
31159            {
31160              dst[0] = ((src[0] >> 5)) +
31161                       ((src[1] >> 5)<<3) +
31162                       ((src[2] >> 6)<<6);
31163              dst+=1;
31164              src+=4;
31165            }
31166          }
31167          break;
31168      }
31169     }
31170     ctx_tiled_cursor_drawn = 0;
31171     ctx_tiled_draw_cursor (tiled);
31172     ctx_fb_flip (fb);
31173     tiled->shown_frame = tiled->render_frame;
31174   }
31175 }
31176 
ctx_fb_consume_events(Ctx * ctx)31177 int ctx_fb_consume_events (Ctx *ctx)
31178 {
31179   CtxFb *fb = (void*)ctx->renderer;
31180   ctx_fb_show_frame (fb, 0);
31181   event_check_pending (&fb->tiled);
31182   return 0;
31183 }
31184 
ctx_fb_reset(CtxFb * fb)31185 inline static void ctx_fb_reset (CtxFb *fb)
31186 {
31187   ctx_fb_show_frame (fb, 1);
31188 }
31189 
ctx_fb_flush(CtxFb * fb)31190 inline static void ctx_fb_flush (CtxFb *fb)
31191 {
31192   ctx_tiled_flush ((CtxTiled*)fb);
31193 }
31194 
ctx_fb_free(CtxFb * fb)31195 void ctx_fb_free (CtxFb *fb)
31196 {
31197   CtxTiled*tiled=(CtxTiled*)fb;
31198 
31199 //#ifdef __linux__
31200   ioctl (0, KDSETMODE, KD_TEXT);
31201 //#endif
31202 #ifdef __NetBSD__
31203   {
31204    int mode = WSDISPLAYIO_MODE_EMUL;
31205    ioctl (fb->fb_fd, WSDISPLAYIO_SMODE, &mode);
31206   }
31207 #endif
31208   munmap (tiled->fb, fb->fb_mapped_size);
31209   close (fb->fb_fd);
31210   if (system("stty sane")){};
31211   ctx_tiled_free ((CtxTiled*)fb);
31212   //free (fb);
31213 #if CTX_BABL
31214   babl_exit ();
31215 #endif
31216 }
31217 
31218 //static unsigned char *fb_icc = NULL;
31219 //static long fb_icc_length = 0;
31220 
ctx_renderer_is_fb(Ctx * ctx)31221 int ctx_renderer_is_fb (Ctx *ctx)
31222 {
31223   if (ctx->renderer &&
31224       ctx->renderer->free == (void*)ctx_fb_free)
31225           return 1;
31226   return 0;
31227 }
31228 
31229 static CtxFb *ctx_fb = NULL;
31230 #ifdef __linux__
fb_vt_switch_cb(int sig)31231 static void fb_vt_switch_cb (int sig)
31232 {
31233   CtxTiled *tiled = (void*)ctx_fb;
31234   if (sig == SIGUSR1)
31235   {
31236     ioctl (0, VT_RELDISP, 1);
31237     tiled->vt_active = 0;
31238     ioctl (0, KDSETMODE, KD_TEXT);
31239   }
31240   else
31241   {
31242     ioctl (0, VT_RELDISP, VT_ACKACQ);
31243     tiled->vt_active = 1;
31244     // queue draw
31245     tiled->render_frame = ++tiled->frame;
31246     ioctl (0, KDSETMODE, KD_GRAPHICS);
31247     {
31248       tiled->ctx->dirty=1;
31249 
31250       for (int row = 0; row < CTX_HASH_ROWS; row++)
31251       for (int col = 0; col < CTX_HASH_COLS; col++)
31252       {
31253         tiled->hashes[(row * CTX_HASH_COLS + col) *  20] += 1;
31254       }
31255     }
31256   }
31257 }
31258 #endif
31259 
31260 
ctx_new_fb(int width,int height)31261 Ctx *ctx_new_fb (int width, int height)
31262 {
31263 #if CTX_RASTERIZER
31264   CtxFb *fb = calloc (sizeof (CtxFb), 1);
31265 
31266   CtxTiled *tiled = (void*)fb;
31267   ctx_fb = fb;
31268   {
31269 #ifdef __linux__
31270   const char *dev_path = "/dev/fb0";
31271 #endif
31272 #ifdef __NetBSD__
31273   const char *dev_path = "/dev/ttyE0";
31274 #endif
31275 #ifdef __OpenBSD__
31276   const char *dev_path = "/dev/ttyC0";
31277 #endif
31278   fb->fb_fd = open (dev_path, O_RDWR);
31279   if (fb->fb_fd > 0)
31280     fb->fb_path = strdup (dev_path);
31281   else
31282   {
31283 #ifdef __linux__
31284     fb->fb_fd = open ("/dev/graphics/fb0", O_RDWR);
31285     if (fb->fb_fd > 0)
31286     {
31287       fb->fb_path = strdup ("/dev/graphics/fb0");
31288     }
31289     else
31290 #endif
31291     {
31292       free (fb);
31293       return NULL;
31294     }
31295   }
31296 
31297 #ifdef __linux__
31298   if (ioctl(fb->fb_fd, FBIOGET_FSCREENINFO, &fb->finfo))
31299     {
31300       fprintf (stderr, "error getting fbinfo\n");
31301       close (fb->fb_fd);
31302       free (fb->fb_path);
31303       free (fb);
31304       return NULL;
31305     }
31306 
31307    if (ioctl(fb->fb_fd, FBIOGET_VSCREENINFO, &fb->vinfo))
31308      {
31309        fprintf (stderr, "error getting fbinfo\n");
31310       close (fb->fb_fd);
31311       free (fb->fb_path);
31312       free (fb);
31313       return NULL;
31314      }
31315   ioctl (0, KDSETMODE, KD_GRAPHICS);
31316 
31317 //fprintf (stderr, "%s\n", fb->fb_path);
31318   width = tiled->width = fb->vinfo.xres;
31319   height = tiled->height = fb->vinfo.yres;
31320 
31321   fb->fb_bits = fb->vinfo.bits_per_pixel;
31322 //fprintf (stderr, "fb bits: %i\n", fb->fb_bits);
31323 
31324   if (fb->fb_bits == 16)
31325     fb->fb_bits =
31326       fb->vinfo.red.length +
31327       fb->vinfo.green.length +
31328       fb->vinfo.blue.length;
31329    else if (fb->fb_bits == 8)
31330   {
31331     unsigned short red[256],  green[256],  blue[256];
31332   //  unsigned short original_red[256];
31333   //  unsigned short original_green[256];
31334   //  unsigned short original_blue[256];
31335     struct fb_cmap cmap = {0, 256, red, green, blue, NULL};
31336   //  struct fb_cmap original_cmap = {0, 256, original_red, original_green, original_blue, NULL};
31337     int i;
31338 
31339     /* do we really need to restore it ? */
31340    // if (ioctl (fb->fb_fd, FBIOPUTCMAP, &original_cmap) == -1)
31341    // {
31342    //   fprintf (stderr, "palette initialization problem %i\n", __LINE__);
31343    // }
31344 
31345     for (i = 0; i < 256; i++)
31346     {
31347       red[i]   = ((( i >> 5) & 0x7) << 5) << 8;
31348       green[i] = ((( i >> 2) & 0x7) << 5) << 8;
31349       blue[i]  = ((( i >> 0) & 0x3) << 6) << 8;
31350     }
31351 
31352     if (ioctl (fb->fb_fd, FBIOPUTCMAP, &cmap) == -1)
31353     {
31354       fprintf (stderr, "palette initialization problem %i\n", __LINE__);
31355     }
31356   }
31357 
31358   fb->fb_bpp = fb->vinfo.bits_per_pixel / 8;
31359   fb->fb_mapped_size = fb->finfo.smem_len;
31360 #endif
31361 
31362 #ifdef __NetBSD__
31363   struct wsdisplay_fbinfo finfo;
31364 
31365   int mode = WSDISPLAYIO_MODE_DUMBFB;
31366   //int mode = WSDISPLAYIO_MODE_MAPPED;
31367   if (ioctl (fb->fb_fd, WSDISPLAYIO_SMODE, &mode)) {
31368     return NULL;
31369   }
31370   if (ioctl (fb->fb_fd, WSDISPLAYIO_GINFO, &finfo)) {
31371     fprintf (stderr, "ioctl: WSIDSPLAYIO_GINFO failed\n");
31372     return NULL;
31373   }
31374 
31375   width = tiled->width = finfo.width;
31376   height = tiled->height = finfo.height;
31377   fb->fb_bits = finfo.depth;
31378   fb->fb_bpp = (fb->fb_bits + 1) / 8;
31379   fb->fb_mapped_size = width * height * fb->fb_bpp;
31380 
31381 
31382   if (fb->fb_bits == 8)
31383   {
31384     uint8_t red[256],  green[256],  blue[256];
31385     struct wsdisplay_cmap cmap;
31386     cmap.red = red;
31387     cmap.green = green;
31388     cmap.blue = blue;
31389     cmap.count = 256;
31390     cmap.index = 0;
31391     for (int i = 0; i < 256; i++)
31392     {
31393       red[i]   = ((( i >> 5) & 0x7) << 5);
31394       green[i] = ((( i >> 2) & 0x7) << 5);
31395       blue[i]  = ((( i >> 0) & 0x3) << 6);
31396     }
31397 
31398     ioctl (fb->fb_fd, WSDISPLAYIO_PUTCMAP, &cmap);
31399   }
31400 #endif
31401 
31402 
31403   tiled->fb = mmap (NULL, fb->fb_mapped_size, PROT_READ|PROT_WRITE, MAP_SHARED, fb->fb_fd, 0);
31404   }
31405   if (!tiled->fb)
31406     return NULL;
31407   tiled->pixels = calloc (fb->fb_mapped_size, 1);
31408   ctx_fb_events = 1;
31409 
31410 #if CTX_BABL
31411   babl_init ();
31412 #endif
31413 
31414   ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
31415 
31416   tiled->ctx      = ctx_new ();
31417   tiled->ctx_copy = ctx_new ();
31418   tiled->width    = width;
31419   tiled->height   = height;
31420 
31421   ctx_set_renderer (tiled->ctx, fb);
31422   ctx_set_renderer (tiled->ctx_copy, fb);
31423   ctx_set_texture_cache (tiled->ctx_copy, tiled->ctx);
31424 
31425   ctx_set_size (tiled->ctx, width, height);
31426   ctx_set_size (tiled->ctx_copy, width, height);
31427 
31428   tiled->flush = (void*)ctx_fb_flush;
31429   tiled->reset = (void*)ctx_fb_reset;
31430   tiled->free  = (void*)ctx_fb_free;
31431   tiled->set_clipboard = (void*)ctx_fb_set_clipboard;
31432   tiled->get_clipboard = (void*)ctx_fb_get_clipboard;
31433 
31434   for (int i = 0; i < _ctx_max_threads; i++)
31435   {
31436     tiled->host[i] = ctx_new_for_framebuffer (tiled->pixels,
31437                    tiled->width/CTX_HASH_COLS, tiled->height/CTX_HASH_ROWS,
31438                    tiled->width * 4, CTX_FORMAT_BGRA8); // this format
31439                                   // is overriden in  thread
31440     ((CtxRasterizer*)(tiled->host[i]->renderer))->swap_red_green = 1;
31441     ctx_set_texture_source (tiled->host[i], tiled->ctx);
31442   }
31443 
31444   mtx_init (&tiled->mtx, mtx_plain);
31445   cnd_init (&tiled->cond);
31446 
31447 #define start_thread(no)\
31448   if(_ctx_max_threads>no){ \
31449     static void *args[2]={(void*)no, };\
31450     thrd_t tid;\
31451     args[1]=fb;\
31452     thrd_create (&tid, (void*)ctx_tiled_render_fun, args);\
31453   }
31454   start_thread(0);
31455   start_thread(1);
31456   start_thread(2);
31457   start_thread(3);
31458   start_thread(4);
31459   start_thread(5);
31460   start_thread(6);
31461   start_thread(7);
31462   start_thread(8);
31463   start_thread(9);
31464   start_thread(10);
31465   start_thread(11);
31466   start_thread(12);
31467   start_thread(13);
31468   start_thread(14);
31469   start_thread(15);
31470 #undef start_thread
31471 
31472   //ctx_flush (tiled->ctx);
31473 
31474   EvSource *kb = evsource_kb_new ();
31475   if (kb)
31476   {
31477     tiled->evsource[tiled->evsource_count++] = kb;
31478     kb->priv = fb;
31479   }
31480   EvSource *mice  = evsource_mice_new ();
31481   if (mice)
31482   {
31483     tiled->evsource[tiled->evsource_count++] = mice;
31484     mice->priv = fb;
31485   }
31486 
31487   tiled->vt_active = 1;
31488 #ifdef __linux__
31489   ioctl(0, KDSETMODE, KD_GRAPHICS);
31490   signal (SIGUSR1, fb_vt_switch_cb);
31491   signal (SIGUSR2, fb_vt_switch_cb);
31492 
31493   struct vt_stat st;
31494   if (ioctl (0, VT_GETSTATE, &st) == -1)
31495   {
31496     ctx_log ("VT_GET_MODE on vt %i failed\n", fb->vt);
31497     return NULL;
31498   }
31499 
31500   fb->vt = st.v_active;
31501 
31502   struct vt_mode mode;
31503   mode.mode   = VT_PROCESS;
31504   mode.relsig = SIGUSR1;
31505   mode.acqsig = SIGUSR2;
31506   if (ioctl (0, VT_SETMODE, &mode) < 0)
31507   {
31508     ctx_log ("VT_SET_MODE on vt %i failed\n", fb->vt);
31509     return NULL;
31510   }
31511 #endif
31512 
31513   return tiled->ctx;
31514 #else
31515   return NULL;
31516 #endif
31517 }
31518 #else
31519 
ctx_renderer_is_fb(Ctx * ctx)31520 int ctx_renderer_is_fb (Ctx *ctx)
31521 {
31522   return 0;
31523 }
31524 #endif
31525 #endif
31526 
31527 #if CTX_SDL
31528 
31529 /**/
31530 
31531 typedef struct _CtxSDL CtxSDL;
31532 struct _CtxSDL
31533 {
31534    CtxTiled  tiled;
31535    /* where we diverge from fb*/
31536    int           key_balance;
31537    int           key_repeat;
31538    int           lctrl;
31539    int           lalt;
31540    int           rctrl;
31541    int           lshift;
31542    int           rshift;
31543 
31544    SDL_Window   *window;
31545    SDL_Renderer *renderer;
31546    SDL_Texture  *texture;
31547 
31548    int           fullscreen;
31549 };
31550 
31551 #include "stb_image_write.h"
31552 
ctx_screenshot(Ctx * ctx,const char * output_path)31553 void ctx_screenshot (Ctx *ctx, const char *output_path)
31554 {
31555 #if CTX_SCREENSHOT
31556   int valid = 0;
31557   CtxSDL *sdl = (void*)ctx->renderer;
31558 
31559   if (ctx_renderer_is_sdl (ctx)) valid = 1;
31560 #if CTX_FB
31561   if (ctx_renderer_is_fb  (ctx)) valid = 1;
31562 #endif
31563 #if CTX_KMS
31564   if (ctx_renderer_is_kms (ctx)) valid = 1;
31565 #endif
31566 
31567   if (!valid)
31568     return;
31569 
31570   // we rely on the same struxt layout XXX !
31571   for (int i = 0; i < sdl->width * sdl->height; i++)
31572   {
31573     int tmp = sdl->pixels[i*4];
31574     sdl->pixels[i*4] = sdl->pixels[i*4 + 2];
31575     sdl->pixels[i*4 + 2] = tmp;
31576   }
31577 
31578   stbi_write_png (output_path, sdl->width, sdl->height, 4, sdl->pixels, sdl->width*4);
31579 
31580 #if 0
31581 #if CTX_FB || CTX_KMS
31582   for (int i = 0; i < sdl->width * sdl->height; i++)
31583   {
31584     int tmp = sdl->pixels[i*4];
31585     sdl->pixels[i*4] = sdl->pixels[i*4 + 2];
31586     sdl->pixels[i*4 + 2] = tmp;
31587   }
31588 #endif
31589 #endif
31590 #endif
31591 }
31592 
31593 int ctx_show_fps = 1;
ctx_sdl_set_title(void * self,const char * new_title)31594 void ctx_sdl_set_title (void *self, const char *new_title)
31595 {
31596    CtxSDL *sdl = self;
31597    if (!ctx_show_fps)
31598    SDL_SetWindowTitle (sdl->window, new_title);
31599 }
31600 
ctx_sdl_show_frame(CtxSDL * sdl,int block)31601 static void ctx_sdl_show_frame (CtxSDL *sdl, int block)
31602 {
31603   CtxTiled *tiled = &sdl->tiled;
31604   if (tiled->shown_cursor != tiled->ctx->cursor)
31605   {
31606     tiled->shown_cursor = tiled->ctx->cursor;
31607     SDL_Cursor *new_cursor =  NULL;
31608     switch (tiled->shown_cursor)
31609     {
31610       case CTX_CURSOR_UNSET: // XXX: document how this differs from none
31611                              //      perhaps falling back to arrow?
31612         break;
31613       case CTX_CURSOR_NONE:
31614         new_cursor = NULL;
31615         break;
31616       case CTX_CURSOR_ARROW:
31617         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
31618         break;
31619       case CTX_CURSOR_CROSSHAIR:
31620         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
31621         break;
31622       case CTX_CURSOR_WAIT:
31623         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
31624         break;
31625       case CTX_CURSOR_HAND:
31626         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
31627         break;
31628       case CTX_CURSOR_IBEAM:
31629         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
31630         break;
31631       case CTX_CURSOR_MOVE:
31632       case CTX_CURSOR_RESIZE_ALL:
31633         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
31634         break;
31635       case CTX_CURSOR_RESIZE_N:
31636       case CTX_CURSOR_RESIZE_S:
31637         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
31638         break;
31639       case CTX_CURSOR_RESIZE_E:
31640       case CTX_CURSOR_RESIZE_W:
31641         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
31642         break;
31643       case CTX_CURSOR_RESIZE_NE:
31644       case CTX_CURSOR_RESIZE_SW:
31645         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
31646         break;
31647       case CTX_CURSOR_RESIZE_NW:
31648       case CTX_CURSOR_RESIZE_SE:
31649         new_cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
31650         break;
31651     }
31652     if (new_cursor)
31653     {
31654       SDL_Cursor *old_cursor = SDL_GetCursor();
31655       SDL_SetCursor (new_cursor);
31656       SDL_ShowCursor (1);
31657       if (old_cursor)
31658         SDL_FreeCursor (old_cursor);
31659     }
31660     else
31661     {
31662       SDL_ShowCursor (0);
31663     }
31664   }
31665 
31666   if (tiled->shown_frame == tiled->render_frame)
31667   {
31668     return;
31669   }
31670 
31671   if (block)
31672   {
31673     int count = 0;
31674     while (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
31675     {
31676       usleep (500);
31677       count ++;
31678       if (count > 100)
31679       {
31680         tiled->shown_frame = tiled->render_frame;
31681         return;
31682       }
31683     }
31684   }
31685   else
31686   {
31687     if (ctx_tiled_threads_done (tiled) != _ctx_max_threads)
31688       return;
31689   }
31690 
31691 
31692   if (tiled->min_row == 100)
31693   {
31694   }
31695   else
31696   {
31697 #if 1
31698     int x = tiled->min_col * tiled->width/CTX_HASH_COLS;
31699     int y = tiled->min_row * tiled->height/CTX_HASH_ROWS;
31700     int x1 = (tiled->max_col+1) * tiled->width/CTX_HASH_COLS;
31701     int y1 = (tiled->max_row+1) * tiled->height/CTX_HASH_ROWS;
31702     int width = x1 - x;
31703     int height = y1 - y;
31704 #endif
31705     tiled->min_row = 100;
31706     tiled->max_row = 0;
31707     tiled->min_col = 100;
31708     tiled->max_col = 0;
31709 
31710     SDL_Rect r = {x, y, width, height};
31711     SDL_UpdateTexture (sdl->texture, &r,
31712                       //(void*)sdl->pixels,
31713                       (void*)(tiled->pixels + y * tiled->width * 4 + x * 4),
31714 
31715                       tiled->width * 4);
31716     SDL_RenderClear (sdl->renderer);
31717     SDL_RenderCopy (sdl->renderer, sdl->texture, NULL, NULL);
31718     SDL_RenderPresent (sdl->renderer);
31719 
31720 
31721   if (ctx_show_fps)
31722   {
31723     static uint64_t prev_time = 0;
31724     static char tmp_title[1024];
31725     uint64_t time = ctx_ticks ();
31726     sprintf (tmp_title, "FPS: %.1f", 1000000.0/  (time - prev_time));
31727     prev_time = time;
31728     SDL_SetWindowTitle (sdl->window, tmp_title);
31729   }
31730   }
31731   tiled->shown_frame = tiled->render_frame;
31732 }
31733 
ctx_sdl_keysym_to_name(unsigned int sym,int * r_keycode)31734 static const char *ctx_sdl_keysym_to_name (unsigned int sym, int *r_keycode)
31735 {
31736   static char buf[16]="";
31737   buf[ctx_unichar_to_utf8 (sym, (void*)buf)]=0;
31738   int code = sym;
31739   const char *name = &buf[0];
31740    switch (sym)
31741    {
31742      case SDLK_RSHIFT: code = 16 ; break;
31743      case SDLK_LSHIFT: code = 16 ; break;
31744      case SDLK_LCTRL: code = 17 ; break;
31745      case SDLK_RCTRL: code = 17 ; break;
31746      case SDLK_LALT:  code = 18 ; break;
31747      case SDLK_RALT:  code = 18 ; break;
31748      case SDLK_CAPSLOCK: name = "capslock"; code = 20 ; break;
31749      //case SDLK_NUMLOCK: name = "numlock"; code = 144 ; break;
31750      //case SDLK_SCROLLLOCK: name = "scrollock"; code = 145 ; break;
31751 
31752      case SDLK_F1:     name = "F1"; code = 112; break;
31753      case SDLK_F2:     name = "F2"; code = 113; break;
31754      case SDLK_F3:     name = "F3"; code = 114; break;
31755      case SDLK_F4:     name = "F4"; code = 115; break;
31756      case SDLK_F5:     name = "F5"; code = 116; break;
31757      case SDLK_F6:     name = "F6"; code = 117; break;
31758      case SDLK_F7:     name = "F7"; code = 118; break;
31759      case SDLK_F8:     name = "F8"; code = 119; break;
31760      case SDLK_F9:     name = "F9"; code = 120; break;
31761      case SDLK_F10:    name = "F10"; code = 121; break;
31762      case SDLK_F11:    name = "F11"; code = 122; break;
31763      case SDLK_F12:    name = "F12"; code = 123; break;
31764      case SDLK_ESCAPE: name = "escape"; break;
31765      case SDLK_DOWN:   name = "down"; code = 40; break;
31766      case SDLK_LEFT:   name = "left"; code = 37; break;
31767      case SDLK_UP:     name = "up"; code = 38;  break;
31768      case SDLK_RIGHT:  name = "right"; code = 39; break;
31769      case SDLK_BACKSPACE: name = "backspace"; break;
31770      case SDLK_SPACE:  name = "space"; break;
31771      case SDLK_TAB:    name = "tab"; break;
31772      case SDLK_DELETE: name = "delete"; code = 46; break;
31773      case SDLK_INSERT: name = "insert"; code = 45; break;
31774      case SDLK_RETURN:
31775        //if (key_repeat == 0) // return never should repeat
31776        name = "return";   // on a DEC like terminal
31777        break;
31778      case SDLK_HOME:     name = "home"; code = 36; break;
31779      case SDLK_END:      name = "end"; code = 35; break;
31780      case SDLK_PAGEDOWN: name = "page-down"; code = 34; break;
31781      case SDLK_PAGEUP:   name = "page-up"; code = 33; break;
31782      case ',': code = 188; break;
31783      case '.': code = 190; break;
31784      case '/': code = 191; break;
31785      case '`': code = 192; break;
31786      case '[': code = 219; break;
31787      case '\\': code = 220; break;
31788      case ']':  code = 221; break;
31789      case '\'': code = 222; break;
31790      default:
31791        ;
31792    }
31793    if (sym >= 'a' && sym <='z') code -= 32;
31794    if (r_keycode)
31795    {
31796      *r_keycode = code;
31797    }
31798    return name;
31799 }
31800 
ctx_sdl_consume_events(Ctx * ctx)31801 int ctx_sdl_consume_events (Ctx *ctx)
31802 {
31803   CtxTiled *tiled = (void*)ctx->renderer;
31804   CtxSDL *sdl = (void*)ctx->renderer;
31805   SDL_Event event;
31806   int got_events = 0;
31807 
31808   ctx_sdl_show_frame (sdl, 0);
31809 
31810   while (SDL_PollEvent (&event))
31811   {
31812     got_events ++;
31813     switch (event.type)
31814     {
31815       case SDL_MOUSEBUTTONDOWN:
31816         SDL_CaptureMouse (1);
31817         ctx_pointer_press (ctx, event.button.x, event.button.y, event.button.button, 0);
31818         break;
31819       case SDL_MOUSEBUTTONUP:
31820         SDL_CaptureMouse (0);
31821         ctx_pointer_release (ctx, event.button.x, event.button.y, event.button.button, 0);
31822         break;
31823       case SDL_MOUSEMOTION:
31824         //  XXX : look at mask and generate motion for each pressed
31825         //        button
31826         ctx_pointer_motion (ctx, event.motion.x, event.motion.y, 1, 0);
31827         break;
31828       case SDL_FINGERMOTION:
31829         ctx_pointer_motion (ctx, event.tfinger.x * tiled->width, event.tfinger.y * tiled->height,
31830             (event.tfinger.fingerId%10) + 4, 0);
31831         break;
31832       case SDL_FINGERDOWN:
31833         {
31834         static int fdowns = 0;
31835         fdowns ++;
31836         if (fdowns > 1) // the very first finger down from SDL seems to be
31837                         // mirrored as mouse events, later ones not - at
31838                         // least under wayland
31839         {
31840           ctx_pointer_press (ctx, event.tfinger.x * tiled->width, event.tfinger.y * tiled->height,
31841           (event.tfinger.fingerId%10) + 4, 0);
31842         }
31843         }
31844         break;
31845       case SDL_FINGERUP:
31846         ctx_pointer_release (ctx, event.tfinger.x * tiled->width, event.tfinger.y * tiled->height,
31847           (event.tfinger.fingerId%10) + 4, 0);
31848         break;
31849 #if 1
31850       case SDL_TEXTINPUT:
31851     //  if (!active)
31852     //    break;
31853         if (!sdl->lctrl && !sdl->rctrl && !sdl->lalt
31854            //&& ( (vt && vt_keyrepeat (vt) ) || (key_repeat==0) )
31855            )
31856           {
31857             const char *name = event.text.text;
31858             int keycode = 0;
31859             if (!strcmp (name, " ") ) { name = "space"; }
31860             if (name[0] && name[1] == 0)
31861             {
31862               keycode = name[0];
31863               keycode = toupper (keycode);
31864               switch (keycode)
31865               {
31866                 case '.':  keycode = 190; break;
31867                 case ';':  keycode = 59; break;
31868                 case ',':  keycode = 188; break;
31869                 case '/':  keycode = 191; break;
31870                 case '\'': keycode = 222; break;
31871                 case '`':  keycode = 192; break;
31872                 case '[':  keycode = 219; break;
31873                 case ']':  keycode = 221; break;
31874                 case '\\': keycode = 220; break;
31875               }
31876             }
31877             ctx_key_press (ctx, keycode, name, 0);
31878             //got_event = 1;
31879           }
31880         break;
31881 #endif
31882       case SDL_KEYDOWN:
31883         {
31884           char buf[32] = "";
31885           const char *name = buf;
31886           if (!event.key.repeat)
31887           {
31888             sdl->key_balance ++;
31889             sdl->key_repeat = 0;
31890           }
31891           else
31892           {
31893             sdl->key_repeat ++;
31894           }
31895           switch (event.key.keysym.sym)
31896           {
31897             case SDLK_LSHIFT: sdl->lshift = 1; break;
31898             case SDLK_RSHIFT: sdl->rshift = 1; break;
31899             case SDLK_LCTRL:  sdl->lctrl = 1; break;
31900             case SDLK_LALT:   sdl->lalt = 1; break;
31901             case SDLK_RCTRL:  sdl->rctrl = 1; break;
31902           }
31903           if (sdl->lshift | sdl->rshift | sdl->lctrl | sdl->lalt | sdl->rctrl)
31904           {
31905             ctx->events.modifier_state ^= ~(CTX_MODIFIER_STATE_CONTROL|
31906                                             CTX_MODIFIER_STATE_ALT|
31907                                             CTX_MODIFIER_STATE_SHIFT);
31908             if (sdl->lshift | sdl->rshift)
31909               ctx->events.modifier_state |= CTX_MODIFIER_STATE_SHIFT;
31910             if (sdl->lctrl | sdl->rctrl)
31911               ctx->events.modifier_state |= CTX_MODIFIER_STATE_CONTROL;
31912             if (sdl->lalt)
31913               ctx->events.modifier_state |= CTX_MODIFIER_STATE_ALT;
31914           }
31915           int keycode;
31916           name = ctx_sdl_keysym_to_name (event.key.keysym.sym, &keycode);
31917           ctx_key_down (ctx, keycode, name, 0);
31918 
31919           if (strlen (name)
31920               &&(event.key.keysym.mod & (KMOD_CTRL) ||
31921                  event.key.keysym.mod & (KMOD_ALT) ||
31922                  ctx_utf8_strlen (name) >= 2))
31923           {
31924             if (event.key.keysym.mod & (KMOD_CTRL) )
31925               {
31926                 static char buf[64] = "";
31927                 sprintf (buf, "control-%s", name);
31928                 name = buf;
31929               }
31930             if (event.key.keysym.mod & (KMOD_ALT) )
31931               {
31932                 static char buf[128] = "";
31933                 sprintf (buf, "alt-%s", name);
31934                 name = buf;
31935               }
31936             if (event.key.keysym.mod & (KMOD_SHIFT) )
31937               {
31938                 static char buf[196] = "";
31939                 sprintf (buf, "shift-%s", name);
31940                 name = buf;
31941               }
31942             if (strcmp (name, "space"))
31943               {
31944                ctx_key_press (ctx, keycode, name, 0);
31945               }
31946           }
31947           else
31948           {
31949 #if 0
31950              ctx_key_press (ctx, 0, buf, 0);
31951 #endif
31952           }
31953         }
31954         break;
31955       case SDL_KEYUP:
31956         {
31957            sdl->key_balance --;
31958            switch (event.key.keysym.sym)
31959            {
31960              case SDLK_LSHIFT: sdl->lshift = 0; break;
31961              case SDLK_RSHIFT: sdl->rshift = 0; break;
31962              case SDLK_LCTRL: sdl->lctrl = 0; break;
31963              case SDLK_RCTRL: sdl->rctrl = 0; break;
31964              case SDLK_LALT:  sdl->lalt  = 0; break;
31965            }
31966 
31967           {
31968             ctx->events.modifier_state ^= ~(CTX_MODIFIER_STATE_CONTROL|
31969                                             CTX_MODIFIER_STATE_ALT|
31970                                             CTX_MODIFIER_STATE_SHIFT);
31971             if (sdl->lshift | sdl->rshift)
31972               ctx->events.modifier_state |= CTX_MODIFIER_STATE_SHIFT;
31973             if (sdl->lctrl | sdl->rctrl)
31974               ctx->events.modifier_state |= CTX_MODIFIER_STATE_CONTROL;
31975             if (sdl->lalt)
31976               ctx->events.modifier_state |= CTX_MODIFIER_STATE_ALT;
31977           }
31978 
31979            int keycode;
31980            const char *name = ctx_sdl_keysym_to_name (event.key.keysym.sym, &keycode);
31981            ctx_key_up (ctx, keycode, name, 0);
31982         }
31983         break;
31984       case SDL_QUIT:
31985         ctx_quit (ctx);
31986         break;
31987       case SDL_WINDOWEVENT:
31988         if (event.window.event == SDL_WINDOWEVENT_RESIZED)
31989         {
31990           ctx_sdl_show_frame (sdl, 1);
31991           int width = event.window.data1;
31992           int height = event.window.data2;
31993           SDL_DestroyTexture (sdl->texture);
31994           sdl->texture = SDL_CreateTexture (sdl->renderer, SDL_PIXELFORMAT_ABGR8888,
31995                           SDL_TEXTUREACCESS_STREAMING, width, height);
31996           free (tiled->pixels);
31997           tiled->pixels = calloc (4, width * height);
31998 
31999           tiled->width  = width;
32000           tiled->height = height;
32001           ctx_set_size (tiled->ctx, width, height);
32002           ctx_set_size (tiled->ctx_copy, width, height);
32003         }
32004         break;
32005     }
32006   }
32007   return 1;
32008 }
32009 #else
ctx_screenshot(Ctx * ctx,const char * path)32010 void ctx_screenshot (Ctx *ctx, const char *path)
32011 {
32012 }
32013 #endif
32014 
32015 #if CTX_SDL
32016 
ctx_sdl_set_clipboard(CtxSDL * sdl,const char * text)32017 static void ctx_sdl_set_clipboard (CtxSDL *sdl, const char *text)
32018 {
32019   if (text)
32020     SDL_SetClipboardText (text);
32021 }
32022 
ctx_sdl_get_clipboard(CtxSDL * sdl)32023 static char *ctx_sdl_get_clipboard (CtxSDL *sdl)
32024 {
32025   return SDL_GetClipboardText ();
32026 }
32027 
ctx_sdl_reset(CtxSDL * sdl)32028 inline static void ctx_sdl_reset (CtxSDL *sdl)
32029 {
32030   ctx_sdl_show_frame (sdl, 1);
32031 }
32032 
ctx_sdl_flush(CtxSDL * sdl)32033 inline static void ctx_sdl_flush (CtxSDL *sdl)
32034 {
32035   ctx_tiled_flush ((void*)sdl);
32036   //CtxTiled *tiled = (void*)sdl;
32037 }
32038 
ctx_sdl_free(CtxSDL * sdl)32039 void ctx_sdl_free (CtxSDL *sdl)
32040 {
32041 
32042   if (sdl->texture)
32043   SDL_DestroyTexture (sdl->texture);
32044   if (sdl->renderer)
32045   SDL_DestroyRenderer (sdl->renderer);
32046   if (sdl->window)
32047   SDL_DestroyWindow (sdl->window);
32048 
32049   ctx_tiled_free ((CtxTiled*)sdl);
32050 #if CTX_BABL
32051   babl_exit ();
32052 #endif
32053 }
32054 
32055 
ctx_renderer_is_sdl(Ctx * ctx)32056 int ctx_renderer_is_sdl (Ctx *ctx)
32057 {
32058   if (ctx->renderer &&
32059       ctx->renderer->free == (void*)ctx_sdl_free)
32060           return 1;
32061   return 0;
32062 }
32063 
ctx_sdl_set_fullscreen(Ctx * ctx,int val)32064 void ctx_sdl_set_fullscreen (Ctx *ctx, int val)
32065 {
32066   CtxSDL *sdl = (void*)ctx->renderer;
32067 
32068   if (val)
32069   {
32070     SDL_SetWindowFullscreen (sdl->window, SDL_WINDOW_FULLSCREEN_DESKTOP);
32071   }
32072   else
32073   {
32074     SDL_SetWindowFullscreen (sdl->window, 0);
32075   }
32076   // XXX we're presuming success
32077   sdl->fullscreen = val;
32078 }
ctx_sdl_get_fullscreen(Ctx * ctx)32079 int ctx_sdl_get_fullscreen (Ctx *ctx)
32080 {
32081   CtxSDL *sdl = (void*)ctx->renderer;
32082   return sdl->fullscreen;
32083 }
32084 
32085 
ctx_new_sdl(int width,int height)32086 Ctx *ctx_new_sdl (int width, int height)
32087 {
32088 #if CTX_RASTERIZER
32089 
32090   CtxSDL *sdl = (CtxSDL*)calloc (sizeof (CtxSDL), 1);
32091   CtxTiled *tiled = (void*)sdl;
32092 
32093   ctx_get_contents ("file:///tmp/ctx.icc", &sdl_icc, &sdl_icc_length);
32094   if (width <= 0 || height <= 0)
32095   {
32096     width  = 1920;
32097     height = 1080;
32098   }
32099   sdl->window = SDL_CreateWindow("ctx", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE);
32100   //sdl->renderer = SDL_CreateRenderer (sdl->window, -1, SDL_RENDERER_SOFTWARE);
32101   sdl->renderer = SDL_CreateRenderer (sdl->window, -1, 0);
32102   if (!sdl->renderer)
32103   {
32104      ctx_free (tiled->ctx);
32105      free (sdl);
32106      return NULL;
32107   }
32108 #if CTX_BABL
32109   babl_init ();
32110 #endif
32111   sdl->fullscreen = 0;
32112 
32113 
32114   ctx_show_fps = getenv ("CTX_SHOW_FPS")!=NULL;
32115 
32116   ctx_sdl_events = 1;
32117   sdl->texture = SDL_CreateTexture (sdl->renderer,
32118         SDL_PIXELFORMAT_ABGR8888,
32119         SDL_TEXTUREACCESS_STREAMING,
32120         width, height);
32121 
32122   SDL_StartTextInput ();
32123   SDL_EnableScreenSaver ();
32124 
32125   tiled->ctx      = ctx_new ();
32126   tiled->ctx_copy = ctx_new ();
32127   tiled->width    = width;
32128   tiled->height   = height;
32129   tiled->cols     = 80;
32130   tiled->rows     = 20;
32131   ctx_set_renderer (tiled->ctx, sdl);
32132   ctx_set_renderer (tiled->ctx_copy, sdl);
32133   ctx_set_texture_cache (tiled->ctx_copy, tiled->ctx);
32134 
32135   tiled->pixels = (uint8_t*)malloc (width * height * 4);
32136 
32137   ctx_set_size (tiled->ctx,      width, height);
32138   ctx_set_size (tiled->ctx_copy, width, height);
32139 
32140   tiled->flush = (void*)ctx_sdl_flush;
32141   tiled->reset = (void*)ctx_sdl_reset;
32142   tiled->free  = (void*)ctx_sdl_free;
32143   tiled->set_clipboard = (void*)ctx_sdl_set_clipboard;
32144   tiled->get_clipboard = (void*)ctx_sdl_get_clipboard;
32145 
32146   for (int i = 0; i < _ctx_max_threads; i++)
32147   {
32148     tiled->host[i] = ctx_new_for_framebuffer (tiled->pixels,
32149                      tiled->width/CTX_HASH_COLS, tiled->height/CTX_HASH_ROWS,
32150                      tiled->width * 4, CTX_FORMAT_RGBA8);
32151     ctx_set_texture_source (tiled->host[i], tiled->ctx);
32152   }
32153 
32154   mtx_init (&tiled->mtx, mtx_plain);
32155   cnd_init (&tiled->cond);
32156 
32157 #define start_thread(no)\
32158   if(_ctx_max_threads>no){ \
32159     static void *args[2]={(void*)no, };\
32160     thrd_t tid;\
32161     args[1]=sdl;\
32162     thrd_create (&tid, (void*)ctx_tiled_render_fun, args);\
32163   }
32164   start_thread(0);
32165   start_thread(1);
32166   start_thread(2);
32167   start_thread(3);
32168   start_thread(4);
32169   start_thread(5);
32170   start_thread(6);
32171   start_thread(7);
32172   start_thread(8);
32173   start_thread(9);
32174   start_thread(10);
32175   start_thread(11);
32176   start_thread(12);
32177   start_thread(13);
32178   start_thread(14);
32179   start_thread(15);
32180 #undef start_thread
32181 
32182   //ctx_flush (tiled->ctx);
32183   return tiled->ctx;
32184 #else
32185   return NULL;
32186 #endif
32187 }
32188 #else
32189 
ctx_renderer_is_sdl(Ctx * ctx)32190 int ctx_renderer_is_sdl (Ctx *ctx)
32191 {
32192   return 0;
32193 }
32194 #endif
32195 
32196 #if CTX_EVENTS
32197 
32198 #if !__COSMOPOLITAN__
32199 #include <fcntl.h>
32200 #include <sys/ioctl.h>
32201 #endif
32202 
32203 typedef struct CtxTermCell
32204 {
32205   char    utf8[5];
32206   uint8_t fg[4];
32207   uint8_t bg[4];
32208 
32209   char    prev_utf8[5];
32210   uint8_t prev_fg[4];
32211   uint8_t prev_bg[4];
32212 } CtxTermCell;
32213 
32214 typedef struct CtxTermLine
32215 {
32216   CtxTermCell *cells;
32217   int maxcol;
32218   int size;
32219 } CtxTermLine;
32220 
32221 typedef enum
32222 {
32223   CTX_TERM_ASCII,
32224   CTX_TERM_ASCII_MONO,
32225   CTX_TERM_SEXTANT,
32226   CTX_TERM_BRAILLE_MONO,
32227   CTX_TERM_BRAILLE,
32228   CTX_TERM_QUARTER,
32229 } CtxTermMode;
32230 
32231 typedef struct _CtxTerm CtxTerm;
32232 struct _CtxTerm
32233 {
32234    void (*render) (void *term, CtxCommand *command);
32235    void (*reset)  (void *term);
32236    void (*flush)  (void *term);
32237    char *(*get_clipboard) (void *ctxctx);
32238    void (*set_clipboard) (void *ctxctx, const char *text);
32239    void (*free)   (void *term);
32240    Ctx      *ctx;
32241    int       width;
32242    int       height;
32243    int       cols;
32244    int       rows;
32245    int       was_down;
32246 
32247    uint8_t  *pixels;
32248 
32249    Ctx      *host;
32250    CtxList  *lines;
32251    CtxTermMode mode;
32252 };
32253 
32254 static int ctx_term_ch = 8;
32255 static int ctx_term_cw = 8;
32256 
ctx_term_set(CtxTerm * term,int col,int row,const char * utf8,uint8_t * fg,uint8_t * bg)32257 void ctx_term_set (CtxTerm *term,
32258                       int col, int row, const char *utf8,
32259                       uint8_t *fg, uint8_t *bg)
32260 {
32261   if (col < 1 || row < 1 || col > term->cols  || row > term->rows) return;
32262   while (ctx_list_length (term->lines) < row)
32263   {
32264     ctx_list_append (&term->lines, calloc (sizeof (CtxTermLine), 1));
32265   }
32266   CtxTermLine *line = ctx_list_nth_data (term->lines, row-1);
32267   assert (line);
32268   if (line->size < col)
32269   {
32270      int new_size = ((col + 128)/128)*128;
32271      line->cells = realloc (line->cells, sizeof (CtxTermCell) * new_size);
32272      memset (&line->cells[line->size], 0, sizeof (CtxTermCell) * (new_size - line->size) );
32273      line->size = new_size;
32274   }
32275   if (col > line->maxcol) line->maxcol = col;
32276   strncpy (line->cells[col-1].utf8, (char*)utf8, 4);
32277   memcpy  (line->cells[col-1].fg, fg, 4);
32278   memcpy  (line->cells[col-1].bg, bg, 4);
32279 }
32280 
32281 static int _ctx_term256 = 0; // XXX TODO implement autodetect for this
32282 static long _ctx_curfg = -1;
32283 static long _ctx_curbg = -1;
32284 
ctx_rgb_to_long(int r,int g,int b)32285 static long ctx_rgb_to_long (int r,int g, int b)
32286 {
32287   return r * 256 * 256 + g * 256 + b;
32288 }
32289 
32290 
ctx_term_set_fg(int red,int green,int blue)32291 static void ctx_term_set_fg (int red, int green, int blue)
32292 {
32293   long lc = ctx_rgb_to_long (red, green, blue);
32294   if (lc == _ctx_curfg)
32295     return;
32296   _ctx_curfg=lc;
32297   if (_ctx_term256 == 0)
32298   {
32299     printf("\e[38;2;%i;%i;%im", red,green,blue);
32300   }
32301   else
32302   {
32303     int gray = (green /255.0) * 24 + 0.5;
32304     int r    = (red/255.0)    * 6 + 0.5;
32305     int g    = (green/255.0)  * 6 + 0.5;
32306     int b    = (blue/255.0)   * 6 + 0.5;
32307     if (gray > 23) gray = 23;
32308 
32309     if (r > 5) r = 5;
32310     if (g > 5) g = 5;
32311     if (b > 5) b = 5;
32312 
32313     if (((int)(r/1.66)== (int)(g/1.66)) && ((int)(g/1.66) == ((int)(b/1.66))))
32314     {
32315       printf("\e[38;5;%im", 16 + 216 + gray);
32316     }
32317     else
32318       printf("\e[38;5;%im", 16 + r * 6 * 6 + g * 6  + b);
32319   }
32320 }
32321 
ctx_term_set_bg(int red,int green,int blue)32322 static void ctx_term_set_bg(int red, int green, int blue)
32323 {
32324   long lc = ctx_rgb_to_long (red, green, blue);
32325 //if (lc == _ctx_curbg)
32326 //  return;
32327   _ctx_curbg=lc;
32328   if (_ctx_term256 == 0)
32329   {
32330     printf("\e[48;2;%i;%i;%im", red,green,blue);
32331   }
32332   else
32333   {
32334     int gray = (green /255.0) * 24 + 0.5;
32335     int r    = (red/255.0)    * 6 + 0.5;
32336     int g    = (green/255.0)  * 6 + 0.5;
32337     int b    = (blue/255.0)   * 6 + 0.5;
32338     if (gray > 23) gray = 23;
32339 
32340     if (r > 5) r = 5;
32341     if (g > 5) g = 5;
32342     if (b > 5) b = 5;
32343 
32344     if (((int)(r/1.66)== (int)(g/1.66)) && ((int)(g/1.66) == ((int)(b/1.66))))
32345     {
32346       printf("\e[48;5;%im", 16 + 216 + gray);
32347     }
32348     else
32349       printf("\e[48;5;%im", 16 + r * 6 * 6 + g * 6  + b);
32350   }
32351 }
32352 
32353 static int _ctx_term_force_full = 0;
32354 
ctx_term_scanout(CtxTerm * term)32355 void ctx_term_scanout (CtxTerm *term)
32356 {
32357   int row = 1;
32358   printf ("\e[H");
32359 //  printf ("\e[?25l");
32360   printf ("\e[0m");
32361 
32362   int cur_fg[3]={-1,-1,-1};
32363   int cur_bg[3]={-1,-1,-1};
32364 
32365   for (CtxList *l = term->lines; l; l = l->next)
32366   {
32367     CtxTermLine *line = l->data;
32368     for (int col = 1; col <= line->maxcol; col++)
32369     {
32370       CtxTermCell *cell = &line->cells[col-1];
32371 
32372       if (strcmp(cell->utf8, cell->prev_utf8) ||
32373           memcmp(cell->fg, cell->prev_fg, 3) ||
32374           memcmp(cell->bg, cell->prev_bg, 3) || _ctx_term_force_full)
32375       {
32376         if (cell->fg[0] != cur_fg[0] ||
32377             cell->fg[1] != cur_fg[1] ||
32378             cell->fg[2] != cur_fg[2])
32379         {
32380           ctx_term_set_fg (cell->fg[0], cell->fg[1], cell->fg[2]);
32381           cur_fg[0]=cell->fg[0];
32382           cur_fg[1]=cell->fg[1];
32383           cur_fg[2]=cell->fg[2];
32384         }
32385         if (cell->bg[0] != cur_bg[0] ||
32386             cell->bg[1] != cur_bg[1] ||
32387             cell->bg[2] != cur_bg[2])
32388         {
32389           ctx_term_set_bg (cell->bg[0], cell->bg[1], cell->bg[2]);
32390           cur_bg[0]=cell->bg[0];
32391           cur_bg[1]=cell->bg[1];
32392           cur_bg[2]=cell->bg[2];
32393         }
32394         printf ("%s", cell->utf8);
32395       }
32396       else
32397       {
32398         // TODO: accumulate succesive such to be ignored items,
32399         // and compress them into one, making us compress largely
32400         // reused screens well
32401         printf ("\e[C");
32402       }
32403       strcpy (cell->prev_utf8, cell->utf8);
32404       memcpy (cell->prev_fg, cell->fg, 3);
32405       memcpy (cell->prev_bg, cell->bg, 3);
32406     }
32407     if (row != term->rows)
32408       printf ("\n\r");
32409     row ++;
32410   }
32411   printf ("\e[0m");
32412   //printf ("\e[?25h");
32413   //
32414 }
32415 
32416 // xx
32417 // xx
32418 // xx
32419 //
32420 
_ctx_rgba8_manhattan_diff(const uint8_t * a,const uint8_t * b)32421 static inline int _ctx_rgba8_manhattan_diff (const uint8_t *a, const uint8_t *b)
32422 {
32423   int c;
32424   int diff = 0;
32425   for (c = 0; c<3;c++)
32426     diff += ctx_pow2(a[c]-b[c]);
32427   return ctx_sqrtf(diff);
32428   return diff;
32429 }
32430 
ctx_term_output_buf_half(uint8_t * pixels,int width,int height,CtxTerm * term)32431 static void ctx_term_output_buf_half (uint8_t *pixels,
32432                           int width,
32433                           int height,
32434                           CtxTerm *term)
32435 {
32436   int stride = width * 4;
32437   const char *sextants[]={
32438    " ","▘","▝","▀","▖","▌", "▞", "▛", "▗", "▚", "▐", "▜","▄","▙","▟","█",
32439 
32440   };
32441   for (int row = 0; row < height/2; row++)
32442     {
32443       for (int col = 0; col < width-3; col++)
32444         {
32445           int     unicode = 0;
32446           int     bitno = 0;
32447           uint8_t rgba[2][4] = {
32448                              {255,255,255,0},
32449                              {0,0,0,0}};
32450           int i = 0;
32451 
32452           int  rgbasum[2][4] = {0,};
32453           int  sumcount[2];
32454 
32455           int curdiff = 0;
32456           /* first find starting point colors */
32457           for (int yi = 0; yi < ctx_term_ch; yi++)
32458             for (int xi = 0; xi < ctx_term_cw; xi++, i++)
32459                 {
32460                   int noi = (row * ctx_term_ch + yi) * stride + (col*ctx_term_cw+xi) * 4;
32461 
32462                   if (rgba[0][3] == 0)
32463                   {
32464                     for (int c = 0; c < 3; c++)
32465                       rgba[0][c] = pixels[noi + c];
32466                     rgba[0][3] = 255; // used only as mark of in-use
32467                   }
32468                   else
32469                   {
32470                     int diff = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[0]);
32471                     if (diff > curdiff)
32472                     {
32473                       curdiff = diff;
32474                       for (int c = 0; c < 3; c++)
32475                         rgba[1][c] = pixels[noi + c];
32476                     }
32477                   }
32478 
32479                 }
32480 
32481           for (int iters = 0; iters < 1; iters++)
32482           {
32483                   i= 0;
32484           for (int i = 0; i < 4; i ++)
32485              rgbasum[0][i] = rgbasum[1][i]=0;
32486           sumcount[0] = sumcount[1] = 0;
32487 
32488           for (int yi = 0; yi < ctx_term_ch; yi++)
32489             for (int xi = 0; xi < ctx_term_cw; xi++, i++)
32490                 {
32491                   int noi = (row * ctx_term_ch + yi) * stride + (col*ctx_term_cw+xi) * 4;
32492 
32493                   int diff1 = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[0]);
32494                   int diff2 = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[1]);
32495                   int cluster = 0;
32496                   if (diff1 <= diff2)
32497                     cluster = 0;
32498                   else
32499                     cluster = 1;
32500                   sumcount[cluster]++;
32501                   for (int c = 0; c < 3; c++)
32502                     rgbasum[cluster][c] += pixels[noi+c];
32503                 }
32504 
32505 
32506           if (sumcount[0])
32507           for (int c = 0; c < 3; c++)
32508           {
32509             rgba[0][c] = rgbasum[0][c] / sumcount[0];
32510           }
32511           if (sumcount[1])
32512           for (int c = 0; c < 3; c++)
32513           {
32514             rgba[1][c] = rgbasum[1][c] / sumcount[1];
32515           }
32516           }
32517 
32518           int pixels_set = 0;
32519           for (int y = 0; y < ctx_term_ch; y++)
32520             for (int x = 0; x < ctx_term_cw; x++)
32521               {
32522                 int no = (row * ctx_term_ch + y) * stride + (col*ctx_term_cw+x) * 4;
32523 #define CHECK_IS_SET \
32524       (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
32525        _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
32526 
32527                 int set = CHECK_IS_SET;
32528 #undef CHECK_IS_SET
32529                 if (set)
32530                   { unicode |=  (1<< (bitno) );
32531                     pixels_set ++;
32532                   }
32533                 bitno++;
32534               }
32535            if (pixels_set == 4)
32536              ctx_term_set (term, col +1, row + 1, " ",
32537                            rgba[1], rgba[0]);
32538            else
32539              ctx_term_set (term, col +1, row + 1, sextants[unicode],
32540                            rgba[0], rgba[1]);
32541         }
32542     }
32543 }
32544 
ctx_term_find_color_pair(CtxTerm * term,int x0,int y0,int w,int h,uint8_t rgba[2][4])32545 void ctx_term_find_color_pair (CtxTerm *term, int x0, int y0, int w, int h,
32546                 uint8_t rgba[2][4])
32547         //uint8_t *rgba0, uint8_t *rgba1)
32548 {
32549 int curdiff = 0;
32550 int stride = term->width * 4;
32551 uint8_t *pixels = term->pixels;
32552 /* first find starting point colors */
32553 for (int y = y0; y < y0 + h; y++)
32554   for (int x = x0; x < x0 + w; x++)
32555       {
32556         int noi = (y) * stride + (x) * 4;
32557 
32558         if (rgba[0][3] == 0)
32559         {
32560           for (int c = 0; c < 3; c++)
32561             rgba[0][c] = pixels[noi + c];
32562           rgba[0][3] = 255; // used only as mark of in-use
32563         }
32564         else
32565         {
32566           int diff = _ctx_rgba8_manhattan_diff (&pixels[noi], &rgba[0][0]);
32567           if (diff > curdiff)
32568           {
32569             curdiff = diff;
32570             for (int c = 0; c < 3; c++)
32571               rgba[1][c] = pixels[noi + c];
32572           }
32573         }
32574       }
32575           int  rgbasum[2][4] = {0,};
32576           int  sumcount[2];
32577 
32578           for (int iters = 0; iters < 1; iters++)
32579           {
32580           for (int i = 0; i < 4; i ++)
32581              rgbasum[0][i] = rgbasum[1][i]=0;
32582           sumcount[0] = sumcount[1] = 0;
32583 
32584           for (int y = y0; y < y0 + h; y++)
32585             for (int x = x0; x < x0 + w; x++)
32586                 {
32587                   int noi = (y) * stride + (x) * 4;
32588 
32589                   int diff1 = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[0]);
32590                   int diff2 = _ctx_rgba8_manhattan_diff (&pixels[noi], rgba[1]);
32591                   int cluster = 0;
32592                   if (diff1 <= diff2)
32593                     cluster = 0;
32594                   else
32595                     cluster = 1;
32596                   sumcount[cluster]++;
32597                   for (int c = 0; c < 3; c++)
32598                     rgbasum[cluster][c] += pixels[noi+c];
32599                 }
32600 
32601 
32602           if (sumcount[0])
32603           for (int c = 0; c < 3; c++)
32604           {
32605             rgba[0][c] = rgbasum[0][c] / sumcount[0];
32606           }
32607           if (sumcount[1])
32608           for (int c = 0; c < 3; c++)
32609           {
32610             rgba[1][c] = rgbasum[1][c] / sumcount[1];
32611           }
32612           }
32613 
32614 }
32615 
32616 
32617 
ctx_term_output_buf_quarter(uint8_t * pixels,int width,int height,CtxTerm * term)32618 static void ctx_term_output_buf_quarter (uint8_t *pixels,
32619                           int width,
32620                           int height,
32621                           CtxTerm *term)
32622 {
32623   int stride = width * 4;
32624   const char *sextants[]={
32625    " ","▘","▝","▀","▖","▌", "▞", "▛", "▗", "▚", "▐", "▜","▄","▙","▟","█"
32626 
32627   };
32628   for (int row = 0; row < height/ctx_term_ch; row++)
32629     {
32630       for (int col = 0; col < width /ctx_term_cw; col++)
32631         {
32632           int     unicode = 0;
32633           int     bitno = 0;
32634           uint8_t rgba[2][4] = {
32635                              {255,255,255,0},
32636                              {0,0,0,0}};
32637           ctx_term_find_color_pair (term, col * ctx_term_cw,
32638                                     row * ctx_term_ch,
32639                                     ctx_term_cw,
32640                                     ctx_term_ch, rgba);
32641 
32642           int pixels_set = 0;
32643           for (int y = 0; y < 2; y++)
32644             for (int x = 0; x < ctx_term_cw; x++)
32645               {
32646                 int no = (row * ctx_term_ch + y) * stride + (col*ctx_term_cw+x) * 4;
32647 #define CHECK_IS_SET \
32648       (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
32649        _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
32650 
32651                 int set = CHECK_IS_SET;
32652 #undef CHECK_IS_SET
32653                 if (set)
32654                   { unicode |=  (1<< (bitno) );
32655                     pixels_set ++;
32656                   }
32657                 bitno++;
32658               }
32659            if (pixels_set == 4)
32660              ctx_term_set (term, col +1, row + 1, " ",
32661                            rgba[1], rgba[0]);
32662            else
32663              ctx_term_set (term, col +1, row + 1, sextants[unicode],
32664                            rgba[0], rgba[1]);
32665         }
32666     }
32667 }
32668 
32669 
ctx_term_output_buf_sextant(uint8_t * pixels,int width,int height,CtxTerm * term)32670 static void ctx_term_output_buf_sextant (uint8_t *pixels,
32671                           int width,
32672                           int height,
32673                           CtxTerm *term)
32674 {
32675   int stride = width * 4;
32676 
32677   const char *sextants[]={
32678    " ","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","▌","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","▐","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","��","█"
32679   };
32680 
32681   for (int row = 0; row < height/ctx_term_ch; row++)
32682     {
32683       for (int col = 0; col < width /ctx_term_cw; col++)
32684         {
32685           int     unicode = 0;
32686           int     bitno = 0;
32687           uint8_t rgba[2][4] = {
32688                              {255,255,255,0},
32689                              {0,0,0,0}};
32690 
32691           ctx_term_find_color_pair (term, col * ctx_term_cw,
32692                                     row * ctx_term_ch,
32693                                     ctx_term_cw,
32694                                     ctx_term_ch, rgba);
32695 
32696           int pixels_set = 0;
32697           for (int y = 0; y < ctx_term_ch; y++)
32698             for (int x = 0; x < ctx_term_cw; x++)
32699               {
32700                 int no = (row * ctx_term_ch + y) * stride + (col*ctx_term_cw+x) * 4;
32701 #define CHECK_IS_SET \
32702       (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
32703        _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
32704 
32705                 int set = CHECK_IS_SET;
32706 #undef CHECK_IS_SET
32707                 if (set)
32708                   { unicode |=  (1<< (bitno) );
32709                     pixels_set ++;
32710                   }
32711                 bitno++;
32712               }
32713 
32714           if (pixels_set == 6)
32715             ctx_term_set (term, col +1, row + 1, " ",
32716                           rgba[1], rgba[0]);
32717           else
32718             ctx_term_set (term, col +1, row + 1, sextants[unicode], rgba[0], rgba[1]);
32719         }
32720     }
32721 }
32722 
ctx_term_output_buf_ascii(uint8_t * pixels,int width,int height,CtxTerm * term,int mono)32723 static void ctx_term_output_buf_ascii (uint8_t *pixels,
32724                           int width,
32725                           int height,
32726                           CtxTerm *term,
32727                           int mono)
32728 {
32729   /* this is a crude ascii-mode built on a quick mapping of sexels to ascii */
32730   int stride = width * 4;
32731   const char *sextants[]={
32732    " ","`","'","^","��","`","~","\"","-","\"","'","\"","-","\"","~","^",",",";",
32733    "=","/","i","[","p","P","z",")","/","7","f",">","/","F",",","\\",":",":",
32734    "\\","\\","(","T","j","T","]","?","s","\\","<","q","_","=","=","=","c","L",
32735    "Q","C","a","b","J","]","m","b","d","@"
32736   };
32737   uint8_t black[4] = {0,0,0,255};
32738   for (int row = 0; row < height/ctx_term_ch; row++)
32739     {
32740       for (int col = 0; col < width /ctx_term_cw; col++)
32741         {
32742           int     unicode = 0;
32743           int     bitno = 0;
32744           uint8_t rgba[2][4] = {
32745                              {255,255,255,0},
32746                              {0,0,0,0}};
32747 
32748           ctx_term_find_color_pair (term, col * ctx_term_cw,
32749                                     row * ctx_term_ch,
32750                                     ctx_term_cw,
32751                                     ctx_term_ch, rgba);
32752 
32753 
32754           if (_ctx_rgba8_manhattan_diff (black, rgba[1]) >
32755               _ctx_rgba8_manhattan_diff (black, rgba[0]))
32756           {
32757             for (int c = 0; c < 4; c ++)
32758             {
32759               int tmp = rgba[0][c];
32760               rgba[0][c] = rgba[1][c];
32761               rgba[1][c] = tmp;
32762             }
32763           }
32764           if (mono)
32765           {
32766             rgba[1][0] = 0;
32767             rgba[1][1] = 0;
32768             rgba[1][2] = 0;
32769           }
32770 
32771 
32772           int brightest_dark_diff = _ctx_rgba8_manhattan_diff (black, rgba[0]);
32773 
32774           int pixels_set = 0;
32775           for (int y = 0; y < ctx_term_ch; y++)
32776             for (int x = 0; x < ctx_term_cw; x++)
32777               {
32778                 int no = (row * ctx_term_ch + y) * stride + (col*ctx_term_cw+x) * 4;
32779 #define CHECK_IS_SET \
32780       (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
32781        _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
32782 
32783                 int set = CHECK_IS_SET;
32784 #undef CHECK_IS_SET
32785                 if (set)
32786                   { unicode |=  (1<< (bitno) );
32787                     pixels_set ++;
32788                   }
32789                 bitno++;
32790               }
32791 
32792 
32793            if (pixels_set == 6 && brightest_dark_diff < 40)
32794              ctx_term_set (term, col +1, row + 1, " ",
32795                            rgba[1], rgba[0]);
32796            else
32797              ctx_term_set (term, col +1, row + 1, sextants[unicode],
32798                            rgba[0], rgba[1]);
32799         }
32800     }
32801 }
32802 
ctx_term_output_buf_braille(uint8_t * pixels,int width,int height,CtxTerm * term,int mono)32803 static void ctx_term_output_buf_braille (uint8_t *pixels,
32804                           int width,
32805                           int height,
32806                           CtxTerm *term,
32807                           int mono)
32808 {
32809   int reverse = 0;
32810   int stride = width * 4;
32811   uint8_t black[4] = {0,0,0,255};
32812   for (int row = 0; row < height/ctx_term_ch; row++)
32813     {
32814       for (int col = 0; col < width /ctx_term_cw; col++)
32815         {
32816           int     unicode = 0;
32817           int     bitno = 0;
32818           uint8_t rgba[2][4] = {
32819                              {255,255,255,0},
32820                              {0,0,0,0}};
32821 
32822           ctx_term_find_color_pair (term, col * ctx_term_cw,
32823                                     row * ctx_term_ch,
32824                                     ctx_term_cw,
32825                                     ctx_term_ch, rgba);
32826 
32827 
32828           /* make darkest consistently be background  */
32829           if (_ctx_rgba8_manhattan_diff (black, rgba[1]) >
32830               _ctx_rgba8_manhattan_diff (black, rgba[0]))
32831           {
32832             for (int c = 0; c < 4; c ++)
32833             {
32834               int tmp = rgba[0][c];
32835               rgba[0][c] = rgba[1][c];
32836               rgba[1][c] = tmp;
32837             }
32838           }
32839           if (mono)
32840           {
32841             rgba[1][0] = 0;
32842             rgba[1][1] = 0;
32843             rgba[1][2] = 0;
32844           }
32845 
32846           int pixels_set = 0;
32847           for (int x = 0; x < 2; x++)
32848             for (int y = 0; y < 3; y++)
32849               {
32850                 int no = (row * 4 + y) * stride + (col*2+x) * 4;
32851 #define CHECK_IS_SET \
32852       (_ctx_rgba8_manhattan_diff (&pixels[no], rgba[0])< \
32853        _ctx_rgba8_manhattan_diff (&pixels[no], rgba[1]))
32854 
32855                 int set = CHECK_IS_SET;
32856                 if (reverse) { set = !set; }
32857                 if (set)
32858                   { unicode |=  (1<< (bitno) );
32859                     pixels_set ++;
32860                   }
32861                 bitno++;
32862               }
32863           {
32864             int x = 0;
32865             int y = 3;
32866             int no = (row * 4 + y) * stride + (col*2+x) * 4;
32867             int setA = CHECK_IS_SET;
32868             no = (row * 4 + y) * stride + (col*2+x+1) * 4;
32869             int setB = CHECK_IS_SET;
32870 
32871             pixels_set += setA;
32872             pixels_set += setB;
32873 #undef CHECK_IS_SET
32874             if (reverse) { setA = !setA; }
32875             if (reverse) { setB = !setB; }
32876             if (setA != 0 && setB==0)
32877               { unicode += 0x2840; }
32878             else if (setA == 0 && setB)
32879               { unicode += 0x2880; }
32880             else if ( (setA != 0) && (setB != 0) )
32881               { unicode += 0x28C0; }
32882             else
32883               { unicode += 0x2800; }
32884             char utf8[5];
32885             utf8[ctx_unichar_to_utf8 (unicode, (uint8_t*)utf8)]=0;
32886 
32887 #if 0
32888             if (pixels_set == 8)
32889             {
32890               if (rgba[0][0] < 32 && rgba[0][1] < 32 && rgba[0][2] < 32)
32891               {
32892                 ctx_term_set (term, col +1, row + 1, " ",
32893                                  rgba[1], rgba[0]);
32894                 continue;
32895               }
32896             }
32897 #endif
32898             {
32899               ctx_term_set (term, col +1, row + 1, utf8,
32900                                rgba[0], rgba[1]);
32901             }
32902           }
32903         }
32904     }
32905 }
32906 
32907 
ctx_term_render(void * ctx,CtxCommand * command)32908 inline static void ctx_term_render (void *ctx,
32909                                        CtxCommand *command)
32910 {
32911   CtxTerm *term = (void*)ctx;
32912   /* directly forward */
32913   ctx_process (term->host, &command->entry);
32914 }
32915 
ctx_term_flush(CtxTerm * term)32916 inline static void ctx_term_flush (CtxTerm *term)
32917 {
32918   int width =  term->width;
32919   int height = term->height;
32920   switch (term->mode)
32921   {
32922     case CTX_TERM_QUARTER:
32923        ctx_term_output_buf_quarter (term->pixels,
32924                                 width, height, term);
32925        break;
32926     case CTX_TERM_ASCII:
32927        ctx_term_output_buf_ascii (term->pixels,
32928                                 width, height, term, 0);
32929        break;
32930     case CTX_TERM_ASCII_MONO:
32931        ctx_term_output_buf_ascii (term->pixels,
32932                                 width, height, term, 1);
32933        break;
32934     case CTX_TERM_SEXTANT:
32935        ctx_term_output_buf_sextant (term->pixels,
32936                                 width, height, term);
32937        break;
32938     case CTX_TERM_BRAILLE:
32939        ctx_term_output_buf_braille (term->pixels,
32940                                 width, height, term, 0);
32941        break;
32942     case CTX_TERM_BRAILLE_MONO:
32943        ctx_term_output_buf_braille (term->pixels,
32944                                 width, height, term, 1);
32945        break;
32946   }
32947 #if CTX_BRAILLE_TEXT
32948   CtxRasterizer *rasterizer = (CtxRasterizer*)(term->host->renderer);
32949   // XXX instead sort and inject along with braille
32950   //
32951 
32952   //uint8_t rgba_bg[4]={0,0,0,0};
32953   //uint8_t rgba_fg[4]={255,0,255,255};
32954 
32955   for (CtxList *l = rasterizer->glyphs; l; l = l->next)
32956   {
32957     CtxTermGlyph *glyph = l->data;
32958 
32959     uint8_t *pixels = term->pixels;
32960     long rgb_sum[4]={0,0,0};
32961     for (int v = 0; v <  ctx_term_ch; v ++)
32962     for (int u = 0; u <  ctx_term_cw; u ++)
32963     {
32964       int i = ((glyph->row-1) * ctx_term_ch + v) * rasterizer->blit_width +
32965               ((glyph->col-1) * ctx_term_cw + u);
32966       for (int c = 0; c < 3; c ++)
32967         rgb_sum[c] += pixels[i*4+c];
32968     }
32969     for (int c = 0; c < 3; c ++)
32970       glyph->rgba_bg[c] = rgb_sum[c] / (ctx_term_ch * ctx_term_cw);
32971     char utf8[8];
32972     utf8[ctx_unichar_to_utf8(glyph->unichar, (uint8_t*)utf8)]=0;
32973     ctx_term_set (term, glyph->col, glyph->row,
32974                      utf8, glyph->rgba_fg, glyph->rgba_bg);
32975     free (glyph);
32976   }
32977 
32978   printf ("\e[H");
32979   printf ("\e[0m");
32980   ctx_term_scanout (term);
32981   printf ("\e[0m");
32982   fflush(NULL);
32983   while (rasterizer->glyphs)
32984     ctx_list_remove (&rasterizer->glyphs, rasterizer->glyphs->data);
32985 #endif
32986 }
32987 
ctx_term_free(CtxTerm * term)32988 void ctx_term_free (CtxTerm *term)
32989 {
32990   while (term->lines)
32991   {
32992     free (term->lines->data);
32993     ctx_list_remove (&term->lines, term->lines->data);
32994   }
32995   printf ("\e[?25h"); // cursor on
32996   nc_at_exit ();
32997   free (term->pixels);
32998   ctx_free (term->host);
32999   free (term);
33000   /* we're not destoring the ctx member, this is function is called in ctx' teardown */
33001 }
33002 
ctx_renderer_is_term(Ctx * ctx)33003 int ctx_renderer_is_term (Ctx *ctx)
33004 {
33005   if (ctx->renderer &&
33006       ctx->renderer->free == (void*)ctx_term_free)
33007           return 1;
33008   return 0;
33009 }
33010 
ctx_term_get_cell_width(Ctx * ctx)33011 float ctx_term_get_cell_width (Ctx *ctx)
33012 {
33013   return ctx_term_cw;
33014 }
33015 
ctx_term_get_cell_height(Ctx * ctx)33016 float ctx_term_get_cell_height (Ctx *ctx)
33017 {
33018   return ctx_term_ch;
33019 }
33020 
ctx_new_term(int width,int height)33021 Ctx *ctx_new_term (int width, int height)
33022 {
33023   Ctx *ctx = ctx_new ();
33024 #if CTX_RASTERIZER
33025   CtxTerm *term = (CtxTerm*)calloc (sizeof (CtxTerm), 1);
33026 
33027   const char *mode = getenv ("CTX_TERM_MODE");
33028   ctx_term_cw = 2;
33029   ctx_term_ch = 3;
33030 
33031   if (!mode) term->mode = CTX_TERM_SEXTANT;
33032   else if (!strcmp (mode, "sextant")) term->mode = CTX_TERM_SEXTANT;
33033   else if (!strcmp (mode, "ascii")) term->mode = CTX_TERM_ASCII_MONO;
33034   //else if (!strcmp (mode, "ascii-mono")) term->mode = CTX_TERM_ASCII_MONO;
33035   else if (!strcmp (mode, "quarter")) term->mode = CTX_TERM_QUARTER;
33036   //else if (!strcmp (mode, "braille")){
33037   //  term->mode = CTX_TERM_BRAILLE;
33038   //  ctx_term_ch = 4;
33039   //}
33040   else if (!strcmp (mode, "braille")){
33041     term->mode = CTX_TERM_BRAILLE_MONO;
33042     ctx_term_ch = 4;
33043   }
33044   else {
33045     fprintf (stderr, "recognized values for CTX_TERM_MODE:\n"
33046                     " sextant ascii quarter braille\n");
33047     exit (1);
33048   }
33049 
33050   mode = getenv ("CTX_TERM_FORCE_FULL");
33051   if (mode && strcmp (mode, "0") && strcmp (mode, "no"))
33052     _ctx_term_force_full = 1;
33053 
33054   fprintf (stdout, "\e[?1049h");
33055   fprintf (stdout, "\e[?25l"); // cursor off
33056 
33057   int maxwidth = ctx_terminal_cols  () * ctx_term_cw;
33058   int maxheight = (ctx_terminal_rows ()) * ctx_term_ch;
33059   if (width <= 0 || height <= 0)
33060   {
33061     width = maxwidth;
33062     height = maxheight;
33063   }
33064   if (width > maxwidth) width = maxwidth;
33065   if (height > maxheight) height = maxheight;
33066   term->ctx = ctx;
33067   term->width  = width;
33068   term->height = height;
33069 
33070   term->cols = (width + 1) / ctx_term_cw;
33071   term->rows = (height + 2) / ctx_term_ch;
33072   term->lines = 0;
33073   term->pixels = (uint8_t*)malloc (width * height * 4);
33074   term->host = ctx_new_for_framebuffer (term->pixels,
33075                                            width, height,
33076                                            width * 4, CTX_FORMAT_RGBA8);
33077 #if CTX_BRAILLE_TEXT
33078   ((CtxRasterizer*)term->host->renderer)->term_glyphs=1;
33079 #endif
33080   _ctx_mouse (ctx, NC_MOUSE_DRAG);
33081   ctx_set_renderer (ctx, term);
33082   ctx_set_size (ctx, width, height);
33083   ctx_font_size (ctx, ctx_term_ch);
33084   term->render = ctx_term_render;
33085   term->flush = (void(*)(void*))ctx_term_flush;
33086   term->free  = (void(*)(void*))ctx_term_free;
33087 #endif
33088 
33089 
33090   return ctx;
33091 }
33092 
33093 #endif
33094 
33095 #if CTX_EVENTS
33096 
33097 #if !__COSMOPOLITAN__
33098 #include <fcntl.h>
33099 #include <sys/ioctl.h>
33100 #endif
33101 
33102 typedef struct _CtxTermImg CtxTermImg;
33103 struct _CtxTermImg
33104 {
33105    void (*render)         (void *termimg, CtxCommand *command);
33106    void (*reset)          (void *termimg);
33107    void (*flush)          (void *termimg);
33108    char *(*get_clipboard) (void *ctxctx);
33109    void (*set_clipboard)  (void *ctxctx, const char *text);
33110    void (*free)           (void *termimg);
33111    Ctx      *ctx;
33112    int       width;
33113    int       height;
33114    int       cols;
33115    int       rows;
33116    int       was_down;
33117    // we need to have the above members in that order up to here
33118    uint8_t  *pixels;
33119    Ctx      *host;
33120    CtxList  *lines;
33121 };
33122 
ctx_termimg_render(void * ctx,CtxCommand * command)33123 inline static void ctx_termimg_render (void       *ctx,
33124                                        CtxCommand *command)
33125 {
33126   CtxTermImg *termimg = (void*)ctx;
33127   /* directly forward */
33128   ctx_process (termimg->host, &command->entry);
33129 }
33130 
ctx_termimg_flush(CtxTermImg * termimg)33131 inline static void ctx_termimg_flush (CtxTermImg *termimg)
33132 {
33133   int width =  termimg->width;
33134   int height = termimg->height;
33135   if (!termimg->pixels) return;
33136   char *encoded = malloc (width * height * 3 * 3);
33137   ctx_bin2base64 (termimg->pixels, width * height * 3,
33138                   encoded);
33139   int encoded_len = strlen (encoded);
33140 
33141   int i = 0;
33142 
33143   printf ("\e[H");
33144   printf ("\e_Gf=24,s=%i,v=%i,t=d,a=T,m=1;\e\\", width, height);
33145   while (i <  encoded_len)
33146   {
33147      if (i + 4096 <  encoded_len)
33148      {
33149        printf  ("\e_Gm=1;");
33150      }
33151      else
33152      {
33153        printf  ("\e_Gm=0;");
33154      }
33155      for (int n = 0; n < 4000 && i < encoded_len; n++)
33156      {
33157        printf ("%c", encoded[i]);
33158        i++;
33159      }
33160      printf ("\e\\");
33161   }
33162   free (encoded);
33163 
33164   fflush (NULL);
33165 }
33166 
ctx_termimg_free(CtxTermImg * termimg)33167 void ctx_termimg_free (CtxTermImg *termimg)
33168 {
33169   while (termimg->lines)
33170   {
33171     free (termimg->lines->data);
33172     ctx_list_remove (&termimg->lines, termimg->lines->data);
33173   }
33174   printf ("\e[?25h"); // cursor on
33175   nc_at_exit ();
33176   free (termimg->pixels);
33177   ctx_free (termimg->host);
33178   free (termimg);
33179   /* we're not destoring the ctx member, this is function is called in ctx' teardown */
33180 }
33181 
ctx_renderer_is_termimg(Ctx * ctx)33182 int ctx_renderer_is_termimg (Ctx *ctx)
33183 {
33184   if (ctx->renderer &&
33185       ctx->renderer->free == (void*)ctx_termimg_free)
33186           return 1;
33187   return 0;
33188 }
33189 
ctx_new_termimg(int width,int height)33190 Ctx *ctx_new_termimg (int width, int height)
33191 {
33192   Ctx *ctx = ctx_new ();
33193 #if CTX_RASTERIZER
33194   fprintf (stdout, "\e[?1049h");
33195   fprintf (stdout, "\e[?25l"); // cursor off
33196   CtxTermImg *termimg = (CtxTermImg*)calloc (sizeof (CtxTermImg), 1);
33197 
33198 
33199   int maxwidth = ctx_terminal_width ();
33200 
33201   int colwidth = maxwidth/ctx_terminal_cols ();
33202   maxwidth-=colwidth;
33203 
33204   int maxheight = ctx_terminal_height ();
33205   if (width <= 0 || height <= 0)
33206   {
33207     width  = maxwidth;
33208     height = maxheight;
33209   }
33210   if (width > maxwidth) width = maxwidth;
33211   if (height > maxheight) height = maxheight;
33212   termimg->ctx = ctx;
33213   termimg->width  = width;
33214   termimg->height = height;
33215   termimg->lines = 0;
33216   termimg->pixels = (uint8_t*)malloc (width * height * 3);
33217   termimg->host = ctx_new_for_framebuffer (termimg->pixels,
33218                                            width, height,
33219                                            width * 3, CTX_FORMAT_RGB8);
33220   _ctx_mouse (ctx, NC_MOUSE_DRAG);
33221   ctx_set_renderer (ctx, termimg);
33222   ctx_set_size (ctx, width, height);
33223   ctx_font_size (ctx, 14.0f);
33224   termimg->render = ctx_termimg_render;
33225   termimg->flush = (void(*)(void*))ctx_termimg_flush;
33226   termimg->free  = (void(*)(void*))ctx_termimg_free;
33227 #endif
33228 
33229   return ctx;
33230 }
33231 
33232 #endif
33233 
33234 #if CTX_FORMATTER
33235 
33236 typedef struct _CtxFormatter  CtxFormatter;
33237 struct _CtxFormatter
33238 {
33239   void *target; // FILE
33240   int   longform;
33241   int   indent;
33242 
33243   void (*add_str)(CtxFormatter *formatter, const char *str, int len);
33244 };
33245 
ctx_formatter_addstr(CtxFormatter * formatter,const char * str,int len)33246 static inline void ctx_formatter_addstr (CtxFormatter *formatter, const char *str, int len)
33247 {
33248   formatter->add_str (formatter, str, len);
33249 }
33250 
ctx_formatter_addstrf(CtxFormatter * formatter,const char * format,...)33251 static inline void ctx_formatter_addstrf (CtxFormatter *formatter, const char *format, ...)
33252 {
33253    va_list ap;
33254    size_t needed;
33255    char *buffer;
33256    va_start (ap, format);
33257    needed = vsnprintf (NULL, 0, format, ap) + 1;
33258    buffer = (char*) malloc (needed);
33259    va_end (ap);
33260    va_start (ap, format);
33261    vsnprintf (buffer, needed, format, ap);
33262    va_end (ap);
33263    ctx_formatter_addstr (formatter, buffer, -1);
33264    free (buffer);
33265 }
33266 
_ctx_stream_addstr(CtxFormatter * formatter,const char * str,int len)33267 static void _ctx_stream_addstr (CtxFormatter *formatter, const char *str, int len)
33268 {
33269   if (!str || len == 0)
33270   {
33271     return;
33272   }
33273   if (len < 0) len = strlen (str);
33274   fwrite (str, len, 1, (FILE*)formatter->target);
33275 }
33276 
_ctx_string_addstr(CtxFormatter * formatter,const char * str,int len)33277 void _ctx_string_addstr (CtxFormatter *formatter, const char *str, int len)
33278 {
33279   if (!str || len == 0)
33280   {
33281     return;
33282   }
33283   if (len < 0) len = strlen (str);
33284   ctx_string_append_data ((CtxString*)(formatter->target), str, len);
33285 }
33286 
33287 
_ctx_print_endcmd(CtxFormatter * formatter)33288 static void _ctx_print_endcmd (CtxFormatter *formatter)
33289 {
33290   if (formatter->longform)
33291     {
33292       ctx_formatter_addstr (formatter, ");\n", 3);
33293     }
33294 }
33295 
_ctx_indent(CtxFormatter * formatter)33296 static void _ctx_indent (CtxFormatter *formatter)
33297 {
33298   for (int i = 0; i < formatter->indent; i++)
33299     { ctx_formatter_addstr (formatter, "  ", 2);
33300     }
33301 }
33302 
_ctx_code_to_name(int code)33303 const char *_ctx_code_to_name (int code)
33304 {
33305       switch (code)
33306         {
33307           case CTX_REL_LINE_TO_X4:           return "relLinetoX4"; break;
33308           case CTX_REL_LINE_TO_REL_CURVE_TO: return "relLineToRelCurveTo"; break;
33309           case CTX_REL_CURVE_TO_REL_LINE_TO: return "relCurveToRelLineTo"; break;
33310           case CTX_REL_CURVE_TO_REL_MOVE_TO: return "relCurveToRelMoveTo"; break;
33311           case CTX_REL_LINE_TO_X2:           return "relLineToX2"; break;
33312           case CTX_MOVE_TO_REL_LINE_TO:      return "moveToRelLineTo"; break;
33313           case CTX_REL_LINE_TO_REL_MOVE_TO:  return "relLineToRelMoveTo"; break;
33314           case CTX_FILL_MOVE_TO:             return "fillMoveTo"; break;
33315           case CTX_REL_QUAD_TO_REL_QUAD_TO:  return "relQuadToRelQuadTo"; break;
33316           case CTX_REL_QUAD_TO_S16:          return "relQuadToS16"; break;
33317 
33318           case CTX_SET_KEY:              return "setParam"; break;
33319           case CTX_COLOR:                return "setColor"; break;
33320           case CTX_DEFINE_GLYPH:         return "defineGlyph"; break;
33321           case CTX_KERNING_PAIR:         return "kerningPair"; break;
33322           case CTX_SET_PIXEL:            return "setPixel"; break;
33323           case CTX_GLOBAL_ALPHA:         return "globalAlpha"; break;
33324           case CTX_TEXT:                 return "text"; break;
33325           case CTX_STROKE_TEXT:          return "strokeText"; break;
33326           case CTX_SAVE:                 return "save"; break;
33327           case CTX_RESTORE:              return "restore"; break;
33328           case CTX_STROKE_SOURCE:        return "strokeSource"; break;
33329           case CTX_NEW_PAGE:             return "newPage"; break;
33330           case CTX_START_GROUP:          return "startGroup"; break;
33331           case CTX_END_GROUP:            return "endGroup"; break;
33332           case CTX_RECTANGLE:            return "rectangle"; break;
33333           case CTX_ROUND_RECTANGLE:      return "roundRectangle"; break;
33334           case CTX_LINEAR_GRADIENT:      return "linearGradient"; break;
33335           case CTX_RADIAL_GRADIENT:      return "radialGradient"; break;
33336           case CTX_GRADIENT_STOP:        return "gradientAddStop"; break;
33337           case CTX_VIEW_BOX:             return "viewBox"; break;
33338           case CTX_MOVE_TO:              return "moveTo"; break;
33339           case CTX_LINE_TO:              return "lineTo"; break;
33340           case CTX_BEGIN_PATH:           return "beginPath"; break;
33341           case CTX_REL_MOVE_TO:          return "relMoveTo"; break;
33342           case CTX_REL_LINE_TO:          return "relLineTo"; break;
33343           case CTX_FILL:                 return "fill"; break;
33344           case CTX_EXIT:                 return "exit"; break;
33345           case CTX_APPLY_TRANSFORM:      return "transform"; break;
33346           case CTX_SOURCE_TRANSFORM:     return "sourceTransform"; break;
33347           case CTX_REL_ARC_TO:           return "relArcTo"; break;
33348           case CTX_GLYPH:                return "glyph"; break;
33349           case CTX_TEXTURE:              return "texture"; break;
33350           case CTX_DEFINE_TEXTURE:       return "defineTexture"; break;
33351           case CTX_IDENTITY:             return "identity"; break;
33352           case CTX_CLOSE_PATH:           return "closePath"; break;
33353           case CTX_PRESERVE:             return "preserve"; break;
33354           case CTX_FLUSH:                return "flush"; break;
33355           case CTX_RESET:                return "reset"; break;
33356           case CTX_FONT:                 return "font"; break;
33357           case CTX_STROKE:               return "stroke"; break;
33358           case CTX_CLIP:                 return "clip"; break;
33359           case CTX_ARC:                  return "arc"; break;
33360           case CTX_SCALE:                return "scale"; break;
33361           case CTX_TRANSLATE:            return "translate"; break;
33362           case CTX_ROTATE:               return "rotate"; break;
33363           case CTX_ARC_TO:               return "arcTo"; break;
33364           case CTX_CURVE_TO:             return "curveTo"; break;
33365           case CTX_REL_CURVE_TO:         return "relCurveTo"; break;
33366           case CTX_REL_QUAD_TO:          return "relQuadTo"; break;
33367           case CTX_QUAD_TO:              return "quadTo"; break;
33368           case CTX_SMOOTH_TO:            return "smoothTo"; break;
33369           case CTX_REL_SMOOTH_TO:        return "relSmoothTo"; break;
33370           case CTX_SMOOTHQ_TO:           return "smoothqTo"; break;
33371           case CTX_REL_SMOOTHQ_TO:       return "relSmoothqTo"; break;
33372           case CTX_HOR_LINE_TO:          return "horLineTo"; break;
33373           case CTX_VER_LINE_TO:          return "verLineTo"; break;
33374           case CTX_REL_HOR_LINE_TO:      return "relHorLineTo"; break;
33375           case CTX_REL_VER_LINE_TO:      return "relVerLineTo"; break;
33376           case CTX_COMPOSITING_MODE:     return "compositingMode"; break;
33377           case CTX_BLEND_MODE:           return "blendMode"; break;
33378           case CTX_TEXT_ALIGN:           return "textAlign"; break;
33379           case CTX_TEXT_BASELINE:        return "textBaseline"; break;
33380           case CTX_TEXT_DIRECTION:       return "textDirection"; break;
33381           case CTX_FONT_SIZE:            return "fontSize"; break;
33382           case CTX_MITER_LIMIT:          return "miterLimit"; break;
33383           case CTX_LINE_JOIN:            return "lineJoin"; break;
33384           case CTX_LINE_CAP:             return "lineCap"; break;
33385           case CTX_LINE_WIDTH:           return "lineWidth"; break;
33386           case CTX_LINE_DASH_OFFSET:     return "lineDashOffset"; break;
33387           case CTX_IMAGE_SMOOTHING:      return "imageSmoothing"; break;
33388           case CTX_SHADOW_BLUR:          return "shadowBlur";  break;
33389           case CTX_FILL_RULE:            return "fillRule"; break;
33390         }
33391       return NULL;
33392 }
33393 
_ctx_print_name(CtxFormatter * formatter,int code)33394 static void _ctx_print_name (CtxFormatter *formatter, int code)
33395 {
33396 #define CTX_VERBOSE_NAMES 1
33397 #if CTX_VERBOSE_NAMES
33398   if (formatter->longform)
33399     {
33400       const char *name = NULL;
33401       _ctx_indent (formatter);
33402       //switch ((CtxCode)code)
33403       name = _ctx_code_to_name (code);
33404       if (name)
33405         {
33406           ctx_formatter_addstr (formatter, name, -1);
33407           ctx_formatter_addstr (formatter, " (", 2);
33408           if (code == CTX_SAVE)
33409             { formatter->indent ++; }
33410           else if (code == CTX_RESTORE)
33411             { formatter->indent --; }
33412           return;
33413         }
33414     }
33415 #endif
33416   {
33417     char name[3];
33418     name[0]=CTX_SET_KEY;
33419     name[2]='\0';
33420     switch (code)
33421       {
33422         case CTX_GLOBAL_ALPHA:      name[1]='a'; break;
33423         case CTX_COMPOSITING_MODE:  name[1]='m'; break;
33424         case CTX_BLEND_MODE:        name[1]='B'; break;
33425         case CTX_TEXT_ALIGN:        name[1]='t'; break;
33426         case CTX_TEXT_BASELINE:     name[1]='b'; break;
33427         case CTX_TEXT_DIRECTION:    name[1]='d'; break;
33428         case CTX_FONT_SIZE:         name[1]='f'; break;
33429         case CTX_MITER_LIMIT:       name[1]='l'; break;
33430         case CTX_LINE_JOIN:         name[1]='j'; break;
33431         case CTX_LINE_CAP:          name[1]='c'; break;
33432         case CTX_LINE_WIDTH:        name[1]='w'; break;
33433         case CTX_LINE_DASH_OFFSET:  name[1]='D'; break;
33434         case CTX_IMAGE_SMOOTHING:   name[1]='S'; break;
33435         case CTX_SHADOW_BLUR:       name[1]='s'; break;
33436         case CTX_SHADOW_COLOR:      name[1]='C'; break;
33437         case CTX_SHADOW_OFFSET_X:   name[1]='x'; break;
33438         case CTX_SHADOW_OFFSET_Y:   name[1]='y'; break;
33439         case CTX_FILL_RULE:         name[1]='r'; break;
33440         default:
33441           name[0] = code;
33442           name[1] = 0;
33443           break;
33444       }
33445     ctx_formatter_addstr (formatter, name, -1);
33446     if (formatter->longform)
33447       ctx_formatter_addstr (formatter, " (", 2);
33448     else
33449       ctx_formatter_addstr (formatter, " ", 1);
33450   }
33451 }
33452 
33453 static void
ctx_print_entry_enum(CtxFormatter * formatter,CtxEntry * entry,int args)33454 ctx_print_entry_enum (CtxFormatter *formatter, CtxEntry *entry, int args)
33455 {
33456   _ctx_print_name (formatter, entry->code);
33457   for (int i = 0; i <  args; i ++)
33458     {
33459       int val = ctx_arg_u8 (i);
33460       if (i>0)
33461         {
33462           ctx_formatter_addstr (formatter, " ", 1);
33463         }
33464 #if CTX_VERBOSE_NAMES
33465       if (formatter->longform)
33466         {
33467           const char *str = NULL;
33468           switch (entry->code)
33469             {
33470               case CTX_TEXT_BASELINE:
33471                 switch (val)
33472                   {
33473                     case CTX_TEXT_BASELINE_ALPHABETIC: str = "alphabetic"; break;
33474                     case CTX_TEXT_BASELINE_TOP:        str = "top";        break;
33475                     case CTX_TEXT_BASELINE_BOTTOM:     str = "bottom";     break;
33476                     case CTX_TEXT_BASELINE_HANGING:    str = "hanging";    break;
33477                     case CTX_TEXT_BASELINE_MIDDLE:     str = "middle";     break;
33478                     case CTX_TEXT_BASELINE_IDEOGRAPHIC:str = "ideographic";break;
33479                   }
33480                 break;
33481               case CTX_TEXT_ALIGN:
33482                 switch (val)
33483                   {
33484                     case CTX_TEXT_ALIGN_LEFT:   str = "left"; break;
33485                     case CTX_TEXT_ALIGN_RIGHT:  str = "right"; break;
33486                     case CTX_TEXT_ALIGN_START:  str = "start"; break;
33487                     case CTX_TEXT_ALIGN_END:    str = "end"; break;
33488                     case CTX_TEXT_ALIGN_CENTER: str = "center"; break;
33489                   }
33490                 break;
33491               case CTX_LINE_CAP:
33492                 switch (val)
33493                   {
33494                     case CTX_CAP_NONE:   str = "none"; break;
33495                     case CTX_CAP_ROUND:  str = "round"; break;
33496                     case CTX_CAP_SQUARE: str = "square"; break;
33497                   }
33498                 break;
33499               case CTX_LINE_JOIN:
33500                 switch (val)
33501                   {
33502                     case CTX_JOIN_MITER: str = "miter"; break;
33503                     case CTX_JOIN_ROUND: str = "round"; break;
33504                     case CTX_JOIN_BEVEL: str = "bevel"; break;
33505                   }
33506                 break;
33507               case CTX_FILL_RULE:
33508                 switch (val)
33509                   {
33510                     case CTX_FILL_RULE_WINDING:  str = "winding"; break;
33511                     case CTX_FILL_RULE_EVEN_ODD: str = "evenodd"; break;
33512                   }
33513                 break;
33514               case CTX_BLEND_MODE:
33515                 val = ctx_arg_u32 (i);
33516                 switch (val)
33517                   {
33518             case CTX_BLEND_NORMAL:      str = "normal"; break;
33519             case CTX_BLEND_MULTIPLY:    str = "multiply"; break;
33520             case CTX_BLEND_SCREEN:      str = "screen"; break;
33521             case CTX_BLEND_OVERLAY:     str = "overlay"; break;
33522             case CTX_BLEND_DARKEN:      str = "darken"; break;
33523             case CTX_BLEND_LIGHTEN:     str = "lighten"; break;
33524             case CTX_BLEND_COLOR_DODGE: str = "colorDodge"; break;
33525             case CTX_BLEND_COLOR_BURN:  str = "colorBurn"; break;
33526             case CTX_BLEND_HARD_LIGHT:  str = "hardLight"; break;
33527             case CTX_BLEND_SOFT_LIGHT:  str = "softLight"; break;
33528             case CTX_BLEND_DIFFERENCE:  str = "difference"; break;
33529             case CTX_BLEND_EXCLUSION:   str = "exclusion"; break;
33530             case CTX_BLEND_HUE:         str = "hue"; break;
33531             case CTX_BLEND_SATURATION:  str = "saturation"; break;
33532             case CTX_BLEND_COLOR:       str = "color"; break;
33533             case CTX_BLEND_LUMINOSITY:  str = "luminosity"; break;
33534                   }
33535                 break;
33536               case CTX_COMPOSITING_MODE:
33537                 val = ctx_arg_u32 (i);
33538                 switch (val)
33539                   {
33540               case CTX_COMPOSITE_SOURCE_OVER: str = "sourceOver"; break;
33541               case CTX_COMPOSITE_COPY: str = "copy"; break;
33542               case CTX_COMPOSITE_CLEAR: str = "clear"; break;
33543               case CTX_COMPOSITE_SOURCE_IN: str = "sourceIn"; break;
33544               case CTX_COMPOSITE_SOURCE_OUT: str = "sourceOut"; break;
33545               case CTX_COMPOSITE_SOURCE_ATOP: str = "sourceAtop"; break;
33546               case CTX_COMPOSITE_DESTINATION: str = "destination"; break;
33547               case CTX_COMPOSITE_DESTINATION_OVER: str = "destinationOver"; break;
33548               case CTX_COMPOSITE_DESTINATION_IN: str = "destinationIn"; break;
33549               case CTX_COMPOSITE_DESTINATION_OUT: str = "destinationOut"; break;
33550               case CTX_COMPOSITE_DESTINATION_ATOP: str = "destinationAtop"; break;
33551               case CTX_COMPOSITE_XOR: str = "xor"; break;
33552                   }
33553 
33554                break;
33555             }
33556           if (str)
33557             {
33558               ctx_formatter_addstr (formatter, str, -1);
33559             }
33560           else
33561             {
33562               ctx_formatter_addstrf (formatter, "%i", val);
33563             }
33564         }
33565       else
33566 #endif
33567         {
33568           ctx_formatter_addstrf (formatter, "%i", val);
33569         }
33570     }
33571   _ctx_print_endcmd (formatter);
33572 }
33573 
33574 
33575 static void
ctx_print_a85(CtxFormatter * formatter,uint8_t * data,int length)33576 ctx_print_a85 (CtxFormatter *formatter, uint8_t *data, int length)
33577 {
33578   char *tmp = (char*)malloc (ctx_a85enc_len (length));
33579   ctx_a85enc (data, tmp, length);
33580   ctx_formatter_addstr (formatter, " ~", 2);
33581   ctx_formatter_addstr (formatter, tmp, -1);
33582   ctx_formatter_addstr (formatter, "~ ", 2);
33583   free (tmp);
33584 }
33585 
33586 static void
ctx_print_yenc(CtxFormatter * formatter,uint8_t * data,int length)33587 ctx_print_yenc (CtxFormatter *formatter, uint8_t *data, int length)
33588 {
33589   char *tmp = (char*)malloc (length * 2 + 2);// worst case scenario
33590   int enclength = ctx_yenc ((char*)data, tmp, length);
33591   data[enclength]=0;
33592   ctx_formatter_addstr (formatter, " =", 2);
33593   ctx_formatter_addstr (formatter, tmp, enclength);
33594   ctx_formatter_addstr (formatter, "=y ", 2);
33595   free (tmp);
33596 }
33597 
33598 static void
ctx_print_escaped_string(CtxFormatter * formatter,const char * string)33599 ctx_print_escaped_string (CtxFormatter *formatter, const char *string)
33600 {
33601   if (!string) { return; }
33602   for (int i = 0; string[i]; i++)
33603     {
33604       switch (string[i])
33605         {
33606           case '"':
33607             ctx_formatter_addstr (formatter, "\\\"", 2);
33608             break;
33609           case '\\':
33610             ctx_formatter_addstr (formatter, "\\\\", 2);
33611             break;
33612           case '\n':
33613             ctx_formatter_addstr (formatter, "\\n", 2);
33614             break;
33615           default:
33616             ctx_formatter_addstr (formatter, &string[i], 1);
33617         }
33618     }
33619 }
33620 
33621 static void
ctx_print_float(CtxFormatter * formatter,float val)33622 ctx_print_float (CtxFormatter *formatter, float val)
33623 {
33624   char temp[128];
33625   sprintf (temp, "%0.3f", val);
33626   int j;
33627   for (j = 0; temp[j]; j++)
33628     if (j == ',') { temp[j] = '.'; }
33629   j--;
33630   if (j>0)
33631     while (temp[j] == '0')
33632       {
33633         temp[j]=0;
33634         j--;
33635       }
33636   if (temp[j]=='.')
33637     { temp[j]='\0'; }
33638   ctx_formatter_addstr (formatter, temp, -1);
33639 }
33640 
33641 static void
ctx_print_int(CtxFormatter * formatter,int val)33642 ctx_print_int (CtxFormatter *formatter, int val)
33643 {
33644   ctx_formatter_addstrf (formatter, "%i", val);
33645 }
33646 
33647 static void
ctx_print_entry(CtxFormatter * formatter,CtxEntry * entry,int args)33648 ctx_print_entry (CtxFormatter *formatter, CtxEntry *entry, int args)
33649 {
33650   _ctx_print_name (formatter, entry->code);
33651   for (int i = 0; i <  args; i ++)
33652     {
33653       float val = ctx_arg_float (i);
33654       if (i>0 && val >= 0.0f)
33655         {
33656           if (formatter->longform)
33657             {
33658               ctx_formatter_addstr (formatter, ", ", 2);
33659             }
33660           else
33661             {
33662               if (val >= 0.0f)
33663                 ctx_formatter_addstr (formatter, " ", 1);
33664             }
33665         }
33666       ctx_print_float (formatter, val);
33667     }
33668   _ctx_print_endcmd (formatter);
33669 }
33670 
33671 static void
ctx_print_glyph(CtxFormatter * formatter,CtxEntry * entry,int args)33672 ctx_print_glyph (CtxFormatter *formatter, CtxEntry *entry, int args)
33673 {
33674   _ctx_print_name (formatter, entry->code);
33675   ctx_formatter_addstrf (formatter, "%i", entry->data.u32[0]);
33676   _ctx_print_endcmd (formatter);
33677 }
33678 
33679 static void
33680 ctx_formatter_process (void *user_data, CtxCommand *c);
33681 
33682 
33683 static void
ctx_formatter_process(void * user_data,CtxCommand * c)33684 ctx_formatter_process (void *user_data, CtxCommand *c)
33685 {
33686   CtxEntry *entry = &c->entry;
33687   CtxFormatter *formatter = (CtxFormatter*)user_data;
33688 
33689   switch (entry->code)
33690   //switch ((CtxCode)(entry->code))
33691     {
33692       case CTX_GLYPH:
33693         ctx_print_glyph (formatter, entry, 1);
33694         break;
33695       case CTX_LINE_TO:
33696       case CTX_REL_LINE_TO:
33697       case CTX_SCALE:
33698       case CTX_TRANSLATE:
33699       case CTX_MOVE_TO:
33700       case CTX_REL_MOVE_TO:
33701       case CTX_SMOOTHQ_TO:
33702       case CTX_REL_SMOOTHQ_TO:
33703         ctx_print_entry (formatter, entry, 2);
33704         break;
33705       case CTX_TEXTURE:
33706         _ctx_print_name (formatter, entry->code);
33707         ctx_formatter_addstrf (formatter, "\"");
33708         ctx_print_escaped_string (formatter, c->texture.eid);
33709         ctx_formatter_addstrf (formatter, "\", ");
33710         ctx_print_float (formatter, c->texture.x);
33711         ctx_formatter_addstrf (formatter, ", ");
33712         ctx_print_float (formatter, c->texture.y);
33713         ctx_formatter_addstrf (formatter, " ");
33714         _ctx_print_endcmd (formatter);
33715         break;
33716 
33717       case CTX_DEFINE_TEXTURE:
33718         {
33719         _ctx_print_name (formatter, entry->code);
33720         ctx_formatter_addstrf (formatter, "\"");
33721         ctx_print_escaped_string (formatter, c->define_texture.eid);
33722         ctx_formatter_addstrf (formatter, "\", ");
33723         ctx_print_int (formatter, c->define_texture.width);
33724         ctx_formatter_addstrf (formatter, ", ");
33725         ctx_print_int (formatter, c->define_texture.height);
33726         ctx_formatter_addstrf (formatter, ",%i, ", c->define_texture.format);
33727 
33728         uint8_t *pixel_data = ctx_define_texture_pixel_data (entry);
33729 #if 1
33730 
33731         int stride = ctx_pixel_format_get_stride ((CtxPixelFormat)c->define_texture.format, c->define_texture.width);
33732         int data_len = stride * c->define_texture.height;
33733         if (c->define_texture.format == CTX_FORMAT_YUV420)
33734           data_len = c->define_texture.height * c->define_texture.width +
33735                        2*(c->define_texture.height/2) * (c->define_texture.width/2);
33736         //fprintf (stderr, "encoding %i bytes\n", c->define_texture.height *stride);
33737         //ctx_print_a85 (formatter, pixel_data, c->define_texture.height * stride);
33738         ctx_print_yenc (formatter, pixel_data, data_len);
33739 #else
33740         ctx_formatter_addstrf (formatter, "\"");
33741         ctx_print_escaped_string (formatter, pixel_data);
33742         ctx_formatter_addstrf (formatter, "\" ");
33743 
33744 #endif
33745 
33746         _ctx_print_endcmd (formatter);
33747         }
33748         break;
33749 
33750       case CTX_REL_ARC_TO:
33751       case CTX_ARC_TO:
33752       case CTX_ROUND_RECTANGLE:
33753         ctx_print_entry (formatter, entry, 5);
33754         break;
33755       case CTX_CURVE_TO:
33756       case CTX_REL_CURVE_TO:
33757       case CTX_ARC:
33758       case CTX_RADIAL_GRADIENT:
33759       case CTX_APPLY_TRANSFORM:
33760       case CTX_SOURCE_TRANSFORM:
33761         ctx_print_entry (formatter, entry, 6);
33762         break;
33763       case CTX_QUAD_TO:
33764       case CTX_RECTANGLE:
33765       case CTX_REL_QUAD_TO:
33766       case CTX_LINEAR_GRADIENT:
33767       case CTX_VIEW_BOX:
33768       case CTX_SMOOTH_TO:
33769       case CTX_REL_SMOOTH_TO:
33770         ctx_print_entry (formatter, entry, 4);
33771         break;
33772       case CTX_FONT_SIZE:
33773       case CTX_MITER_LIMIT:
33774       case CTX_ROTATE:
33775       case CTX_LINE_WIDTH:
33776       case CTX_LINE_DASH_OFFSET:
33777       case CTX_GLOBAL_ALPHA:
33778       case CTX_SHADOW_BLUR:
33779       case CTX_SHADOW_OFFSET_X:
33780       case CTX_SHADOW_OFFSET_Y:
33781       case CTX_VER_LINE_TO:
33782       case CTX_HOR_LINE_TO:
33783       case CTX_REL_VER_LINE_TO:
33784       case CTX_REL_HOR_LINE_TO:
33785         ctx_print_entry (formatter, entry, 1);
33786         break;
33787 #if 0
33788       case CTX_SET:
33789         _ctx_print_name (formatter, entry->code);
33790         switch (c->set.key_hash)
33791         {
33792            case CTX_x: ctx_formatter_addstrf (formatter, " 'x' "); break;
33793            case CTX_y: ctx_formatter_addstrf (formatter, " 'y' "); break;
33794            case CTX_width: ctx_formatter_addstrf (formatter, " width "); break;
33795            case CTX_height: ctx_formatter_addstrf (formatter, " height "); break;
33796            default:
33797              ctx_formatter_addstrf (formatter, " %d ", c->set.key_hash);
33798         }
33799         ctx_formatter_addstrf (formatter, "\"");
33800         ctx_print_escaped_string (formatter, (char*)c->set.utf8);
33801         ctx_formatter_addstrf (formatter, "\"");
33802         _ctx_print_endcmd (formatter);
33803         break;
33804 #endif
33805       case CTX_COLOR:
33806         if (formatter->longform ||  1)
33807           {
33808             _ctx_indent (formatter);
33809             int model = (int) c->set_color.model;
33810             const char *suffix="";
33811             if (model & 512)
33812             {
33813               model = model & 511;
33814               suffix = "S";
33815             }
33816             switch (model)
33817               {
33818                 case CTX_GRAY:
33819                   ctx_formatter_addstrf (formatter, "gray%s ", suffix);
33820                   ctx_print_float (formatter, c->graya.g);
33821                   break;
33822                 case CTX_GRAYA:
33823                   ctx_formatter_addstrf (formatter, "graya%s ", suffix);
33824                   ctx_print_float (formatter, c->graya.g);
33825                   ctx_formatter_addstrf (formatter, " ");
33826                   ctx_print_float (formatter, c->graya.a);
33827                   break;
33828                 case CTX_RGBA:
33829                   if (c->rgba.a != 1.0)
33830                   {
33831                     ctx_formatter_addstrf (formatter, "rgba%s ", suffix);
33832                     ctx_print_float (formatter, c->rgba.r);
33833                     ctx_formatter_addstrf (formatter, " ");
33834                     ctx_print_float (formatter, c->rgba.g);
33835                     ctx_formatter_addstrf (formatter, " ");
33836                     ctx_print_float (formatter, c->rgba.b);
33837                     ctx_formatter_addstrf (formatter, " ");
33838                     ctx_print_float (formatter, c->rgba.a);
33839                     break;
33840                   }
33841                   /* FALLTHROUGH */
33842                 case CTX_RGB:
33843                   if (c->rgba.r == c->rgba.g && c->rgba.g == c->rgba.b)
33844                   {
33845                     ctx_formatter_addstrf (formatter, "gray%s ", suffix);
33846                     ctx_print_float (formatter, c->rgba.r);
33847                     ctx_formatter_addstrf (formatter, " ");
33848                     break;
33849                   }
33850                   ctx_formatter_addstrf (formatter, "rgb%s ", suffix);
33851                   ctx_print_float (formatter, c->rgba.r);
33852                   ctx_formatter_addstrf (formatter, " ");
33853                   ctx_print_float (formatter, c->rgba.g);
33854                   ctx_formatter_addstrf (formatter, " ");
33855                   ctx_print_float (formatter, c->rgba.b);
33856                   break;
33857                 case CTX_DRGB:
33858                   ctx_formatter_addstrf (formatter, "drgb%s ", suffix);
33859                   ctx_print_float (formatter, c->rgba.r);
33860                   ctx_formatter_addstrf (formatter, " ");
33861                   ctx_print_float (formatter, c->rgba.g);
33862                   ctx_formatter_addstrf (formatter, " ");
33863                   ctx_print_float (formatter, c->rgba.b);
33864                   break;
33865                 case CTX_DRGBA:
33866                   ctx_formatter_addstrf (formatter, "drgba%s ", suffix);
33867                   ctx_print_float (formatter, c->rgba.r);
33868                   ctx_formatter_addstrf (formatter, " ");
33869                   ctx_print_float (formatter, c->rgba.g);
33870                   ctx_formatter_addstrf (formatter, " ");
33871                   ctx_print_float (formatter, c->rgba.b);
33872                   ctx_formatter_addstrf (formatter, " ");
33873                   ctx_print_float (formatter, c->rgba.a);
33874                   break;
33875                 case CTX_CMYK:
33876                   ctx_formatter_addstrf (formatter, "cmyk%s ", suffix);
33877                   ctx_print_float (formatter, c->cmyka.c);
33878                   ctx_formatter_addstrf (formatter, " ");
33879                   ctx_print_float (formatter, c->cmyka.m);
33880                   ctx_formatter_addstrf (formatter, " ");
33881                   ctx_print_float (formatter, c->cmyka.y);
33882                   ctx_formatter_addstrf (formatter, " ");
33883                   ctx_print_float (formatter, c->cmyka.k);
33884                   break;
33885                 case CTX_CMYKA:
33886                   ctx_formatter_addstrf (formatter, "cmyka%s ", suffix);
33887                   ctx_print_float (formatter, c->cmyka.c);
33888                   ctx_formatter_addstrf (formatter, " ");
33889                   ctx_print_float (formatter, c->cmyka.m);
33890                   ctx_formatter_addstrf (formatter, " ");
33891                   ctx_print_float (formatter, c->cmyka.y);
33892                   ctx_formatter_addstrf (formatter, " ");
33893                   ctx_print_float (formatter, c->cmyka.k);
33894                   ctx_formatter_addstrf (formatter, " ");
33895                   ctx_print_float (formatter, c->cmyka.a);
33896                   break;
33897                 case CTX_DCMYK:
33898                   ctx_formatter_addstrf (formatter, "dcmyk%s ", suffix);
33899                   ctx_print_float (formatter, c->cmyka.c);
33900                   ctx_formatter_addstrf (formatter, " ");
33901                   ctx_print_float (formatter, c->cmyka.m);
33902                   ctx_formatter_addstrf (formatter, " ");
33903                   ctx_print_float (formatter, c->cmyka.y);
33904                   ctx_formatter_addstrf (formatter, " ");
33905                   ctx_print_float (formatter, c->cmyka.k);
33906                   break;
33907                 case CTX_DCMYKA:
33908                   ctx_formatter_addstrf (formatter, "dcmyka%s ", suffix);
33909                   ctx_print_float (formatter, c->cmyka.c);
33910                   ctx_formatter_addstrf (formatter, " ");
33911                   ctx_print_float (formatter, c->cmyka.m);
33912                   ctx_formatter_addstrf (formatter, " ");
33913                   ctx_print_float (formatter, c->cmyka.y);
33914                   ctx_formatter_addstrf (formatter, " ");
33915                   ctx_print_float (formatter, c->cmyka.k);
33916                   ctx_formatter_addstrf (formatter, " ");
33917                   ctx_print_float (formatter, c->cmyka.a);
33918                   break;
33919               }
33920           }
33921         else
33922           {
33923             ctx_print_entry (formatter, entry, 1);
33924           }
33925         break;
33926       case CTX_SET_RGBA_U8:
33927         if (formatter->longform)
33928           {
33929             _ctx_indent (formatter);
33930             ctx_formatter_addstrf (formatter, "rgba (");
33931           }
33932         else
33933           {
33934             ctx_formatter_addstrf (formatter, "rgba (");
33935           }
33936         for (int c = 0; c < 4; c++)
33937           {
33938             if (c)
33939               {
33940                 if (formatter->longform)
33941                   ctx_formatter_addstrf (formatter, ", ");
33942                 else
33943                   ctx_formatter_addstrf (formatter, " ");
33944               }
33945             ctx_print_float (formatter, ctx_u8_to_float (ctx_arg_u8 (c) ) );
33946           }
33947         _ctx_print_endcmd (formatter);
33948         break;
33949       case CTX_SET_PIXEL:
33950 #if 0
33951         ctx_set_pixel_u8 (d_ctx,
33952                           ctx_arg_u16 (2), ctx_arg_u16 (3),
33953                           ctx_arg_u8 (0),
33954                           ctx_arg_u8 (1),
33955                           ctx_arg_u8 (2),
33956                           ctx_arg_u8 (3) );
33957 #endif
33958         break;
33959       case CTX_FILL:
33960       case CTX_RESET:
33961       case CTX_STROKE:
33962       case CTX_IDENTITY:
33963       case CTX_CLIP:
33964       case CTX_BEGIN_PATH:
33965       case CTX_CLOSE_PATH:
33966       case CTX_SAVE:
33967       case CTX_PRESERVE:
33968       case CTX_START_GROUP:
33969       case CTX_NEW_PAGE:
33970       case CTX_END_GROUP:
33971       case CTX_RESTORE:
33972       case CTX_STROKE_SOURCE:
33973         ctx_print_entry (formatter, entry, 0);
33974         break;
33975       case CTX_TEXT_ALIGN:
33976       case CTX_TEXT_BASELINE:
33977       case CTX_TEXT_DIRECTION:
33978       case CTX_FILL_RULE:
33979       case CTX_LINE_CAP:
33980       case CTX_LINE_JOIN:
33981       case CTX_COMPOSITING_MODE:
33982       case CTX_BLEND_MODE:
33983       case CTX_IMAGE_SMOOTHING:
33984         ctx_print_entry_enum (formatter, entry, 1);
33985         break;
33986       case CTX_GRADIENT_STOP:
33987         _ctx_print_name (formatter, entry->code);
33988         for (int c = 0; c < 4; c++)
33989           {
33990             if (c)
33991               ctx_formatter_addstrf (formatter, " ");
33992             ctx_print_float (formatter, ctx_u8_to_float (ctx_arg_u8 (4+c) ) );
33993           }
33994         _ctx_print_endcmd (formatter);
33995         break;
33996       case CTX_TEXT:
33997       case CTX_STROKE_TEXT:
33998       case CTX_FONT:
33999         _ctx_print_name (formatter, entry->code);
34000         ctx_formatter_addstrf (formatter, "\"");
34001         ctx_print_escaped_string (formatter, ctx_arg_string() );
34002         ctx_formatter_addstrf (formatter, "\"");
34003         _ctx_print_endcmd (formatter);
34004         break;
34005       case CTX_CONT:
34006       case CTX_EDGE:
34007       case CTX_DATA:
34008       case CTX_DATA_REV:
34009       case CTX_FLUSH:
34010         break;
34011       case CTX_KERNING_PAIR:
34012         _ctx_print_name (formatter, entry->code);
34013         ctx_formatter_addstrf (formatter, "\"");
34014         {
34015            uint8_t utf8[16];
34016            utf8[ctx_unichar_to_utf8 (c->kern.glyph_before, utf8)]=0;
34017            ctx_print_escaped_string (formatter, (char*)utf8);
34018            ctx_formatter_addstrf (formatter, "\", \"");
34019            utf8[ctx_unichar_to_utf8 (c->kern.glyph_after, utf8)]=0;
34020            ctx_print_escaped_string (formatter, (char*)utf8);
34021            ctx_formatter_addstrf (formatter, "\"");
34022            sprintf ((char*)utf8, ", %f", c->kern.amount / 256.0);
34023            ctx_print_escaped_string (formatter, (char*)utf8);
34024         }
34025         _ctx_print_endcmd (formatter);
34026         break;
34027 
34028       case CTX_DEFINE_GLYPH:
34029         _ctx_print_name (formatter, entry->code);
34030         ctx_formatter_addstrf (formatter, "\"");
34031         {
34032            uint8_t utf8[16];
34033            utf8[ctx_unichar_to_utf8 (entry->data.u32[0], utf8)]=0;
34034            ctx_print_escaped_string (formatter, (char*)utf8);
34035            ctx_formatter_addstrf (formatter, "\"");
34036            sprintf ((char*)utf8, ", %f", entry->data.u32[1]/256.0);
34037            ctx_print_escaped_string (formatter, (char*)utf8);
34038         }
34039         _ctx_print_endcmd (formatter);
34040         break;
34041     }
34042 }
34043 
34044 void
ctx_render_stream(Ctx * ctx,FILE * stream,int longform)34045 ctx_render_stream (Ctx *ctx, FILE *stream, int longform)
34046 {
34047   CtxIterator iterator;
34048   CtxFormatter formatter;
34049   formatter.target= stream;
34050   formatter.longform = longform;
34051   formatter.indent = 0;
34052   formatter.add_str = _ctx_stream_addstr;
34053   CtxCommand *command;
34054   ctx_iterator_init (&iterator, &ctx->drawlist, 0,
34055                      CTX_ITERATOR_EXPAND_BITPACK);
34056   while ( (command = ctx_iterator_next (&iterator) ) )
34057     { ctx_formatter_process (&formatter, command); }
34058   fprintf (stream, "\n");
34059 }
34060 
34061 char *
ctx_render_string(Ctx * ctx,int longform,int * retlen)34062 ctx_render_string (Ctx *ctx, int longform, int *retlen)
34063 {
34064   CtxString *string = ctx_string_new ("");
34065   CtxIterator iterator;
34066   CtxFormatter formatter;
34067   formatter.target= string;
34068   formatter.longform = longform;
34069   formatter.indent = 0;
34070   formatter.add_str = _ctx_string_addstr;
34071   CtxCommand *command;
34072   ctx_iterator_init (&iterator, &ctx->drawlist, 0,
34073                      CTX_ITERATOR_EXPAND_BITPACK);
34074   while ( (command = ctx_iterator_next (&iterator) ) )
34075     { ctx_formatter_process (&formatter, command); }
34076   char *ret = string->str;
34077   if (retlen)
34078     *retlen = string->length;
34079   ctx_string_free (string, 0);
34080   return ret;
34081 }
34082 
34083 
34084 #endif
34085 #include <ctype.h>
34086 #include <sys/stat.h>
34087 
34088 #if CTX_EVENTS
ctx_width(Ctx * ctx)34089 int ctx_width (Ctx *ctx)
34090 {
34091   return ctx->events.width;
34092 }
ctx_height(Ctx * ctx)34093 int ctx_height (Ctx *ctx)
34094 {
34095   return ctx->events.height;
34096 }
34097 #else
ctx_width(Ctx * ctx)34098 int ctx_width (Ctx *ctx)
34099 {
34100   return 512;
34101 }
ctx_height(Ctx * ctx)34102 int ctx_height (Ctx *ctx)
34103 {
34104   return 384;
34105 }
34106 #endif
34107 
ctx_rev(Ctx * ctx)34108 int ctx_rev (Ctx *ctx)
34109 {
34110   return ctx->rev;
34111 }
34112 
ctx_get_state(Ctx * ctx)34113 CtxState *ctx_get_state (Ctx *ctx)
34114 {
34115   return &ctx->state;
34116 }
34117 
ctx_dirty_rect(Ctx * ctx,int * x,int * y,int * width,int * height)34118 void ctx_dirty_rect (Ctx *ctx, int *x, int *y, int *width, int *height)
34119 {
34120   if ( (ctx->state.min_x > ctx->state.max_x) ||
34121        (ctx->state.min_y > ctx->state.max_y) )
34122     {
34123       if (x) { *x = 0; }
34124       if (y) { *y = 0; }
34125       if (width) { *width = 0; }
34126       if (height) { *height = 0; }
34127       return;
34128     }
34129   if (ctx->state.min_x < 0)
34130     { ctx->state.min_x = 0; }
34131   if (ctx->state.min_y < 0)
34132     { ctx->state.min_y = 0; }
34133   if (x) { *x = ctx->state.min_x; }
34134   if (y) { *y = ctx->state.min_y; }
34135   if (width) { *width = ctx->state.max_x - ctx->state.min_x; }
34136   if (height) { *height = ctx->state.max_y - ctx->state.min_y; }
34137 }
34138 
34139 #if CTX_CURRENT_PATH
34140 CtxIterator *
ctx_current_path(Ctx * ctx)34141 ctx_current_path (Ctx *ctx)
34142 {
34143   CtxIterator *iterator = &ctx->current_path_iterator;
34144   ctx_iterator_init (iterator, &ctx->current_path, 0, CTX_ITERATOR_EXPAND_BITPACK);
34145   return iterator;
34146 }
34147 
34148 void
ctx_path_extents(Ctx * ctx,float * ex1,float * ey1,float * ex2,float * ey2)34149 ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
34150 {
34151   float minx = 50000.0;
34152   float miny = 50000.0;
34153   float maxx = -50000.0;
34154   float maxy = -50000.0;
34155   float x = 0;
34156   float y = 0;
34157 
34158   CtxIterator *iterator = ctx_current_path (ctx);
34159   CtxCommand *command;
34160 
34161   while ((command = ctx_iterator_next (iterator)))
34162   {
34163      int got_coord = 0;
34164      switch (command->code)
34165      {
34166         // XXX missing many curve types
34167         case CTX_LINE_TO:
34168         case CTX_MOVE_TO:
34169           x = command->move_to.x;
34170           y = command->move_to.y;
34171           got_coord++;
34172           break;
34173         case CTX_REL_LINE_TO:
34174         case CTX_REL_MOVE_TO:
34175           x += command->move_to.x;
34176           y += command->move_to.y;
34177           got_coord++;
34178           break;
34179         case CTX_CURVE_TO:
34180           x = command->curve_to.x;
34181           y = command->curve_to.y;
34182           got_coord++;
34183           break;
34184         case CTX_REL_CURVE_TO:
34185           x += command->curve_to.x;
34186           y += command->curve_to.y;
34187           got_coord++;
34188           break;
34189         case CTX_ARC:
34190           minx = ctx_minf (minx, command->arc.x - command->arc.radius);
34191           miny = ctx_minf (miny, command->arc.y - command->arc.radius);
34192           maxx = ctx_maxf (maxx, command->arc.x + command->arc.radius);
34193           maxy = ctx_maxf (maxy, command->arc.y + command->arc.radius);
34194 
34195           break;
34196         case CTX_RECTANGLE:
34197         case CTX_ROUND_RECTANGLE:
34198           x = command->rectangle.x;
34199           y = command->rectangle.y;
34200           minx = ctx_minf (minx, x);
34201           miny = ctx_minf (miny, y);
34202           maxx = ctx_maxf (maxx, x);
34203           maxy = ctx_maxf (maxy, y);
34204 
34205           x += command->rectangle.width;
34206           y += command->rectangle.height;
34207           got_coord++;
34208           break;
34209      }
34210     if (got_coord)
34211     {
34212       minx = ctx_minf (minx, x);
34213       miny = ctx_minf (miny, y);
34214       maxx = ctx_maxf (maxx, x);
34215       maxy = ctx_maxf (maxy, y);
34216     }
34217   }
34218 
34219   if (ex1) *ex1 = minx;
34220   if (ey1) *ey1 = miny;
34221   if (ex2) *ex2 = maxx;
34222   if (ey2) *ey2 = maxy;
34223 }
34224 
34225 #else
34226 void
ctx_path_extents(Ctx * ctx,float * ex1,float * ey1,float * ex2,float * ey2)34227 ctx_path_extents (Ctx *ctx, float *ex1, float *ey1, float *ex2, float *ey2)
34228 {
34229 }
34230 #endif
34231 
34232 
34233 static inline void
ctx_gstate_push(CtxState * state)34234 ctx_gstate_push (CtxState *state)
34235 {
34236   if (state->gstate_no + 1 >= CTX_MAX_STATES)
34237     { return; }
34238   state->gstate_stack[state->gstate_no] = state->gstate;
34239   state->gstate_no++;
34240   ctx_state_set (state, CTX_new_state, 0.0);
34241   state->has_clipped=0;
34242 }
34243 
34244 static inline void
ctx_gstate_pop(CtxState * state)34245 ctx_gstate_pop (CtxState *state)
34246 {
34247   if (state->gstate_no <= 0)
34248     { return; }
34249   state->gstate = state->gstate_stack[state->gstate_no-1];
34250   state->gstate_no--;
34251 }
34252 
34253 void
ctx_close_path(Ctx * ctx)34254 ctx_close_path (Ctx *ctx)
34255 {
34256   CTX_PROCESS_VOID (CTX_CLOSE_PATH);
34257 }
34258 
34259 
34260 void
ctx_get_image_data(Ctx * ctx,int sx,int sy,int sw,int sh,CtxPixelFormat format,int dst_stride,uint8_t * dst_data)34261 ctx_get_image_data (Ctx *ctx, int sx, int sy, int sw, int sh,
34262                     CtxPixelFormat format, int dst_stride,
34263                     uint8_t *dst_data)
34264 {
34265    if (0)
34266    {
34267    }
34268 #if CTX_RASTERIZER
34269    else if (_ctx_is_rasterizer (ctx))
34270    {
34271      CtxRasterizer *rasterizer = (CtxRasterizer*)ctx->renderer;
34272      if (rasterizer->format->pixel_format == format)
34273      {
34274        if (dst_stride <= 0) dst_stride = ctx_pixel_format_get_stride (format, sw);
34275        int bytes_per_pix = rasterizer->format->bpp/8;
34276        int y = 0;
34277        for (int v = sy; v < sy + sh; v++, y++)
34278        {
34279          int x = 0;
34280          for (int u = sx; u < sx + sw; u++, x++)
34281          {
34282             uint8_t* src_buf = (uint8_t*)rasterizer->buf;
34283             memcpy (&dst_data[y * dst_stride + x * bytes_per_pix], &src_buf[v * rasterizer->blit_stride + u * bytes_per_pix], bytes_per_pix);
34284          }
34285        }
34286        return;
34287      }
34288    }
34289 #endif
34290    else if (format == CTX_FORMAT_RGBA8 &&
34291                    ( 1
34292 #if CTX_FB
34293                    || ctx_renderer_is_fb (ctx)
34294 #endif
34295 #if CTX_KMS
34296                    || ctx_renderer_is_kms (ctx)
34297 #endif
34298 #if CTX_SDL
34299                    || ctx_renderer_is_sdl (ctx)
34300 #endif
34301                    ))
34302    {
34303      CtxTiled *tiled = (CtxTiled*)ctx->renderer;
34304      {
34305        if (dst_stride <= 0) dst_stride = ctx_pixel_format_get_stride (format, sw);
34306        int bytes_per_pix = 4;
34307        int y = 0;
34308        for (int v = sy; v < sy + sh; v++, y++)
34309        {
34310          int x = 0;
34311          for (int u = sx; u < sx + sw; u++, x++)
34312          {
34313             uint8_t* src_buf = (uint8_t*)tiled->pixels;
34314             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);
34315          }
34316        }
34317        return;
34318      }
34319    }
34320 }
34321 
34322 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)34323 ctx_put_image_data (Ctx *ctx, int w, int h, int stride, int format,
34324                     uint8_t *data,
34325                     int ox, int oy,
34326                     int dirtyX, int dirtyY,
34327                     int dirtyWidth, int dirtyHeight)
34328 {
34329    char eid[65]="";
34330    ctx_save (ctx);
34331    ctx_identity (ctx);
34332    ctx_define_texture (ctx, NULL, w, h, stride, format, data, eid);
34333    if (eid[0])
34334    {
34335      // XXX set compositor to source
34336      ctx_compositing_mode (ctx, CTX_COMPOSITE_COPY);
34337      ctx_draw_texture_clipped (ctx, eid, ox, oy, w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
34338    }
34339    ctx_restore (ctx);
34340 }
34341 
34342 /* checking if an eid is valid also sets the frame for it
34343  */
ctx_eid_valid(Ctx * ctx,const char * eid,int * w,int * h)34344 static int ctx_eid_valid (Ctx *ctx, const char *eid, int *w, int *h)
34345 {
34346   ctx = ctx->texture_cache;
34347   CtxList *to_remove = NULL;
34348   int ret = 0;
34349   //fprintf (stderr, "{%i}\n", ctx->frame);
34350   for (CtxList *l = ctx->eid_db; l; l = l->next)
34351   {
34352     CtxEidInfo *eid_info = (CtxEidInfo*)l->data;
34353     if (ctx->frame - eid_info->frame >= 2)
34354             /* XXX XXX XXX this breaks texture caching since
34355              *   it is wrong in some cases where more frames
34356              *   have passed?
34357              */
34358     {
34359       ctx_list_prepend (&to_remove, eid_info);
34360     }
34361     else if (!strcmp (eid_info->eid, eid) &&
34362              ctx->frame - eid_info->frame < 2)
34363     {
34364     //fclose (f);
34365       eid_info->frame = ctx->frame;
34366       if (w) *w = eid_info->width;
34367       if (h) *h = eid_info->height;
34368       ret = 1;
34369     }
34370   }
34371   while (to_remove)
34372   {
34373     CtxEidInfo *eid_info = (CtxEidInfo*)to_remove->data;
34374     //FILE  *f  = fopen ("/tmp/l", "a");
34375     //fprintf (f, "%i client removing %s\n", getpid(), eid_info->eid);
34376     //fclose (f);
34377     free (eid_info->eid);
34378     free (eid_info);
34379     ctx_list_remove (&ctx->eid_db, eid_info);
34380     ctx_list_remove (&to_remove, eid_info);
34381   }
34382   return ret;
34383 }
34384 
ctx_texture(Ctx * ctx,const char * eid,float x,float y)34385 void ctx_texture (Ctx *ctx, const char *eid, float x, float y)
34386 {
34387   int eid_len = strlen (eid);
34388   char ascii[41]="";
34389   //fprintf (stderr, "tx %s\n", eid);
34390   if (eid_len > 50)
34391   {
34392     CtxSHA1 *sha1 = ctx_sha1_new ();
34393     uint8_t hash[20]="";
34394     ctx_sha1_process (sha1, (uint8_t*)eid, eid_len);
34395     ctx_sha1_done (sha1, hash);
34396     ctx_sha1_free (sha1);
34397     const char *hex="0123456789abcdef";
34398     for (int i = 0; i < 20; i ++)
34399     {
34400        ascii[i*2]=hex[hash[i]/16];
34401        ascii[i*2+1]=hex[hash[i]%16];
34402     }
34403     ascii[40]=0;
34404     eid=ascii;
34405   }
34406 
34407     //FILE  *f = fopen ("/tmp/l", "a");
34408   if (ctx_eid_valid (ctx, eid, 0, 0))
34409   {
34410     ctx_process_cmd_str_float (ctx, CTX_TEXTURE, eid, x, y);
34411     //fprintf (stderr, "setting texture eid %s\n", eid);
34412   }
34413   else
34414   {
34415     //fprintf (stderr, "tried setting invalid texture eid %s\n", eid);
34416   }
34417     //fclose (f);
34418 }
34419 int
_ctx_frame(Ctx * ctx)34420 _ctx_frame (Ctx *ctx)
34421 {
34422    return ctx->frame;
34423 }
34424 int
_ctx_set_frame(Ctx * ctx,int frame)34425 _ctx_set_frame (Ctx *ctx, int frame)
34426 {
34427    return ctx->frame = frame;
34428 }
34429 
ctx_define_texture(Ctx * ctx,const char * eid,int width,int height,int stride,int format,void * data,char * ret_eid)34430 void ctx_define_texture (Ctx *ctx,
34431                          const char *eid,
34432                          int width, int height, int stride, int format, void *data,
34433                          char *ret_eid)
34434 {
34435   uint8_t hash[20]="";
34436   char ascii[41]="";
34437   int dst_stride = width;
34438   //fprintf (stderr, "df %s\n", eid);
34439 
34440   dst_stride = ctx_pixel_format_get_stride ((CtxPixelFormat)format, width);
34441   if (stride <= 0)
34442     stride = dst_stride;
34443 
34444   int data_len;
34445 
34446   if (format == CTX_FORMAT_YUV420)
34447   data_len = width * height + ((width/2) * (height/2)) * 2;
34448   else
34449   data_len = height * dst_stride;
34450 
34451   if (eid == NULL)
34452   {
34453     CtxSHA1 *sha1 = ctx_sha1_new ();
34454     uint8_t *src = (uint8_t*)data;
34455     for (int y = 0; y < height; y++)
34456     {
34457        ctx_sha1_process (sha1, src, dst_stride);
34458        src += stride;
34459     }
34460     ctx_sha1_done (sha1, hash);
34461     ctx_sha1_free (sha1);
34462     const char *hex="0123456789abcdef";
34463     for (int i = 0; i < 20; i ++)
34464     {
34465        ascii[i*2]  =hex[hash[i]/16];
34466        ascii[i*2+1]=hex[hash[i]%16];
34467     }
34468     ascii[40]=0;
34469     eid = ascii;
34470   }
34471 
34472   int eid_len = strlen (eid);
34473 
34474   if (eid_len > 50)
34475   {
34476     CtxSHA1 *sha1 = ctx_sha1_new ();
34477     uint8_t hash[20]="";
34478     ctx_sha1_process (sha1, (uint8_t*)eid, eid_len);
34479     ctx_sha1_done (sha1, hash);
34480     ctx_sha1_free (sha1);
34481     const char *hex="0123456789abcdef";
34482     for (int i = 0; i < 20; i ++)
34483     {
34484        ascii[i*2]  =hex[hash[i]/16];
34485        ascii[i*2+1]=hex[hash[i]%16];
34486     }
34487     ascii[40]=0;
34488     eid = ascii;
34489     eid_len = 40;
34490   }
34491 
34492   // we now have eid
34493 
34494   if (ctx_eid_valid (ctx, eid, 0, 0))
34495   {
34496     ctx_texture (ctx, eid, 0.0, 0.0);
34497   }
34498   else
34499 
34500   {
34501     CtxEntry *commands;
34502     int command_size = 1 + (data_len+1+1)/9 + 1 + (eid_len+1+1)/9 + 1 +   8;
34503     if (ctx->renderer && ctx->renderer->process)
34504     {
34505        commands = (CtxEntry*)calloc (sizeof (CtxEntry), command_size);
34506     }
34507     else
34508     {
34509        commands = NULL;
34510        ctx_drawlist_resize (&ctx->drawlist, ctx->drawlist.count + command_size);
34511        commands = &(ctx->drawlist.entries[ctx->drawlist.count]);
34512        memset (commands, 0, sizeof (CtxEntry) * command_size);
34513     }
34514     /* bottleneck,  we can avoid copying sometimes - and even when copying
34515      * we should cut this down to one copy, direct to the drawlist.
34516      *
34517      */
34518     commands[0] = ctx_u32 (CTX_DEFINE_TEXTURE, width, height);
34519     commands[1].data.u16[0] = format;
34520 
34521     int pos = 2;
34522 
34523     commands[pos].code        = CTX_DATA;
34524     commands[pos].data.u32[0] = eid_len;
34525     commands[pos].data.u32[1] = (eid_len+1+1)/9 + 1;
34526     memcpy ((char *) &commands[pos+1].data.u8[0], eid, eid_len);
34527     ((char *) &commands[pos+1].data.u8[0])[eid_len]=0;
34528 
34529     pos = 2 + 1 + ctx_conts_for_entry (&commands[2]);
34530     commands[pos].code        = CTX_DATA;
34531     commands[pos].data.u32[0] = data_len;
34532     commands[pos].data.u32[1] = (data_len+1+1)/9 + 1;
34533     {
34534       uint8_t *src = (uint8_t*)data;
34535       uint8_t *dst = &commands[pos+1].data.u8[0];
34536 #if 1
34537       memcpy (dst, src, data_len);
34538 #else
34539       for (int y = 0; y < height; y++)
34540       {
34541          memcpy (dst, src, dst_stride);
34542          src += stride;
34543          dst += dst_stride;
34544       }
34545 #endif
34546     }
34547     ((char *) &commands[pos+1].data.u8[0])[data_len]=0;
34548 
34549     if (ctx->renderer && ctx->renderer->process)
34550     {
34551       ctx_process (ctx, commands);
34552       free (commands);
34553     }
34554     else
34555     {
34556        ctx->drawlist.count += ctx_conts_for_entry (commands) + 1;
34557     }
34558 
34559     CtxEidInfo *eid_info = (CtxEidInfo*)calloc (sizeof (CtxEidInfo), 1);
34560     eid_info->width      = width;
34561     eid_info->height     = height;
34562     eid_info->frame      = ctx->texture_cache->frame;
34563     //fprintf (stderr, "%i\n", eid_info->frame);
34564     eid_info->eid        = strdup (eid);
34565     ctx_list_prepend (&ctx->texture_cache->eid_db, eid_info);
34566   }
34567 
34568   if (ret_eid)
34569   {
34570     strcpy (ret_eid, eid);
34571     ret_eid[64]=0;
34572   }
34573 }
34574 
34575 void
ctx_texture_load(Ctx * ctx,const char * path,int * tw,int * th,char * reid)34576 ctx_texture_load (Ctx *ctx, const char *path, int *tw, int *th, char *reid)
34577 {
34578   const char *eid = path;
34579   char ascii[41]="";
34580   int eid_len = strlen (eid);
34581   if (eid_len > 50)
34582   {
34583     CtxSHA1 *sha1 = ctx_sha1_new ();
34584     uint8_t hash[20]="";
34585     ctx_sha1_process (sha1, (uint8_t*)eid, eid_len);
34586     ctx_sha1_done (sha1, hash);
34587     ctx_sha1_free (sha1);
34588     const char *hex="0123456789abcdef";
34589     for (int i = 0; i < 20; i ++)
34590     {
34591        ascii[i*2]=hex[hash[i]/16];
34592        ascii[i*2+1]=hex[hash[i]%16];
34593     }
34594     ascii[40]=0;
34595     eid = ascii;
34596   }
34597 
34598   if (ctx_eid_valid (ctx, eid , tw, th))
34599   {
34600      if (reid)
34601      {
34602        strcpy (reid, eid);
34603      }
34604      return;
34605   }
34606 
34607 #ifdef STBI_INCLUDE_STB_IMAGE_H
34608   CtxPixelFormat pixel_format = CTX_FORMAT_RGBA8;
34609   int w, h, components;
34610   unsigned char *pixels = NULL;
34611 
34612   if (!strncmp (path, "file://", 7))
34613   {
34614     pixels = stbi_load (path + 7, &w, &h, &components, 0);
34615   }
34616   else
34617   {
34618     unsigned char *data = NULL;
34619     long length = 0;
34620     ctx_get_contents (path, &data, &length);
34621     if (data)
34622     {
34623        pixels = stbi_load_from_memory (data, length, &w, &h, &components, 0);
34624        free (data);
34625     }
34626   }
34627 
34628   if (pixels)
34629   {
34630     switch (components)
34631     {
34632       case 1: pixel_format = CTX_FORMAT_GRAY8;  break;
34633       case 2: pixel_format = CTX_FORMAT_GRAYA8; break;
34634       case 3: pixel_format = CTX_FORMAT_RGB8;   break;
34635       case 4: pixel_format = CTX_FORMAT_RGBA8;  break;
34636     }
34637     if (tw) *tw = w;
34638     if (th) *th = h;
34639     ctx_define_texture (ctx, eid, w, h, w * components, pixel_format, pixels, reid);
34640     free (pixels);
34641   }
34642   else
34643   {
34644     fprintf (stderr, "texture loading problem for %s\n", path);
34645   }
34646 #endif
34647 }
34648 
34649 void
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)34650 ctx_draw_texture_clipped  (Ctx *ctx, const char *eid,
34651                            float x, float y,
34652                            float width, float height,
34653                            float clip_x, float clip_y,
34654                            float clip_width, float clip_height)
34655 {
34656   int tex_width  = 0;
34657   int tex_height = 0;
34658   if (ctx_eid_valid (ctx, eid , &tex_width, &tex_height))
34659   {
34660     if (width > 0.0 && height > 0.0)
34661     {
34662 #if 0
34663       if (clip_width > 0.0f)
34664       {
34665         ctx_rectangle (ctx, clip_x, clip_y, clip_width, clip_height);
34666         ctx_clip (ctx);
34667       }
34668 #endif
34669       ctx_rectangle (ctx, x, y, width, height);
34670       CtxMatrix matrix;
34671       ctx_matrix_identity (&matrix);
34672 
34673       ctx_texture (ctx, eid, 0, 0);// / (width/tex_width), y / (height/tex_height));
34674       //ctx_rgba (ctx, 1, 0,0,0.5);
34675 #if 1
34676       if (clip_width > 0.0f)
34677       {
34678               // XXX scale is not yet determined to be correct
34679               // in relation to the translate!
34680         ctx_matrix_scale (&matrix, clip_width/width, clip_height/height);
34681         ctx_matrix_translate (&matrix, -clip_x, -clip_y);
34682       }
34683       else
34684       {
34685         ctx_matrix_scale (&matrix, tex_width/width, tex_height/height);
34686       }
34687       ctx_matrix_translate (&matrix, x, y);
34688 #endif
34689       //ctx_matrix_invert (&matrix);
34690       ctx_source_transform_matrix (ctx, &matrix);
34691       //ctx_texture (ctx, eid, x / (width/tex_width), y / (height/tex_height));
34692       ctx_fill (ctx);
34693     }
34694   }
34695 }
34696 
ctx_draw_texture(Ctx * ctx,const char * eid,float x,float y,float w,float h)34697 void ctx_draw_texture (Ctx *ctx, const char *eid, float x, float y, float w, float h)
34698 {
34699   ctx_draw_texture_clipped (ctx, eid, x, y, w, h, 0,0,0,0);
34700 }
34701 
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)34702 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)
34703 {
34704   char reteid[65];
34705   int width, height;
34706   ctx_texture_load (ctx, path, &width, &height, reteid);
34707   if (reteid[0])
34708   {
34709     ctx_draw_texture_clipped (ctx, reteid, x, y, w, h, sx, sy, swidth, sheight);
34710   }
34711 }
34712 
34713 void
ctx_draw_image(Ctx * ctx,const char * path,float x,float y,float w,float h)34714 ctx_draw_image (Ctx *ctx, const char *path, float x, float y, float w, float h)
34715 {
34716   ctx_draw_image_clipped (ctx, path, x, y, w, h, 0,0,0,0);
34717 }
34718 
34719 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)34720 ctx_set_pixel_u8 (Ctx *ctx, uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
34721 {
34722   CtxEntry command = ctx_u8 (CTX_SET_PIXEL, r, g, b, a, 0, 0, 0, 0);
34723   command.data.u16[2]=x;
34724   command.data.u16[3]=y;
34725   ctx_process (ctx, &command);
34726 }
34727 
34728 void
ctx_linear_gradient(Ctx * ctx,float x0,float y0,float x1,float y1)34729 ctx_linear_gradient (Ctx *ctx, float x0, float y0, float x1, float y1)
34730 {
34731   CtxEntry command[2]=
34732   {
34733     ctx_f (CTX_LINEAR_GRADIENT, x0, y0),
34734     ctx_f (CTX_CONT,            x1, y1)
34735   };
34736   ctx_process (ctx, command);
34737 }
34738 
34739 void
ctx_radial_gradient(Ctx * ctx,float x0,float y0,float r0,float x1,float y1,float r1)34740 ctx_radial_gradient (Ctx *ctx, float x0, float y0, float r0, float x1, float y1, float r1)
34741 {
34742   CtxEntry command[3]=
34743   {
34744     ctx_f (CTX_RADIAL_GRADIENT, x0, y0),
34745     ctx_f (CTX_CONT,            r0, x1),
34746     ctx_f (CTX_CONT,            y1, r1)
34747   };
34748   ctx_process (ctx, command);
34749 }
34750 
ctx_preserve(Ctx * ctx)34751 void ctx_preserve (Ctx *ctx)
34752 {
34753   CTX_PROCESS_VOID (CTX_PRESERVE);
34754 }
34755 
ctx_fill(Ctx * ctx)34756 void ctx_fill (Ctx *ctx)
34757 {
34758   CTX_PROCESS_VOID (CTX_FILL);
34759 }
34760 
ctx_stroke(Ctx * ctx)34761 void ctx_stroke (Ctx *ctx)
34762 {
34763   CTX_PROCESS_VOID (CTX_STROKE);
34764 }
34765 
34766 
ctx_empty(Ctx * ctx)34767 static void ctx_empty (Ctx *ctx)
34768 {
34769 #if CTX_RASTERIZER
34770   if (ctx->renderer == NULL)
34771 #endif
34772     {
34773       ctx->drawlist.count = 0;
34774       ctx->drawlist.bitpack_pos = 0;
34775     }
34776 }
34777 
_ctx_set_store_clear(Ctx * ctx)34778 void _ctx_set_store_clear (Ctx *ctx)
34779 {
34780   ctx->transformation |= CTX_TRANSFORMATION_STORE_CLEAR;
34781 }
34782 
34783 #if CTX_EVENTS
34784 static void
ctx_event_free(void * event,void * user_data)34785 ctx_event_free (void *event, void *user_data)
34786 {
34787   free (event);
34788 }
34789 
34790 static void
ctx_collect_events(CtxEvent * event,void * data,void * data2)34791 ctx_collect_events (CtxEvent *event, void *data, void *data2)
34792 {
34793   Ctx *ctx = (Ctx*)data;
34794   CtxEvent *copy;
34795   if (event->type == CTX_KEY_PRESS && !strcmp (event->string, "idle"))
34796     return;
34797   copy = (CtxEvent*)malloc (sizeof (CtxEvent));
34798   *copy = *event;
34799   if (copy->string)
34800     copy->string = strdup (event->string);
34801   ctx_list_append_full (&ctx->events.events, copy, ctx_event_free, NULL);
34802 }
34803 #endif
34804 
34805 #if CTX_EVENTS
34806 static void _ctx_bindings_key_press (CtxEvent *event, void *data1, void *data2);
34807 #endif
34808 
ctx_reset(Ctx * ctx)34809 void ctx_reset (Ctx *ctx)
34810 {
34811         /* we do the callback reset first - maybe we need two cbs,
34812          * one for before and one after default impl?
34813          *
34814          * tiled fb and sdl needs to sync
34815          */
34816   if (ctx->renderer && ctx->renderer->reset)
34817     ctx->renderer->reset (ctx->renderer);
34818 
34819   //CTX_PROCESS_VOID (CTX_RESET);
34820   //if (ctx->transformation & CTX_TRANSFORMATION_STORE_CLEAR)
34821   //  { return; }
34822   ctx_empty (ctx);
34823   ctx_state_init (&ctx->state);
34824 #if CTX_EVENTS
34825   ctx_list_free (&ctx->events.items);
34826   ctx->events.last_item = NULL;
34827 
34828   if (ctx->events.ctx_get_event_enabled)
34829   {
34830     ctx_clear_bindings (ctx);
34831     ctx_listen_full (ctx, 0,0,0,0,
34832                      CTX_KEY_PRESS, _ctx_bindings_key_press, ctx, ctx,
34833                      NULL, NULL);
34834 
34835     ctx_listen_full (ctx, 0,0,0,0,
34836                      CTX_KEY_UP, ctx_collect_events, ctx, ctx,
34837                      NULL, NULL);
34838     ctx_listen_full (ctx, 0,0,0,0,
34839                      CTX_KEY_DOWN, ctx_collect_events, ctx, ctx,
34840                      NULL, NULL);
34841 
34842     ctx_listen_full (ctx, 0, 0, ctx->events.width, ctx->events.height,
34843                      (CtxEventType)(CTX_PRESS|CTX_RELEASE|CTX_MOTION),
34844                      ctx_collect_events, ctx, ctx,
34845                      NULL, NULL);
34846   }
34847 #endif
34848 }
34849 
ctx_begin_path(Ctx * ctx)34850 void ctx_begin_path (Ctx *ctx)
34851 {
34852   CTX_PROCESS_VOID (CTX_BEGIN_PATH);
34853 }
34854 
ctx_clip(Ctx * ctx)34855 void ctx_clip (Ctx *ctx)
34856 {
34857   CTX_PROCESS_VOID (CTX_CLIP);
34858 }
34859 
34860 void
34861 ctx_set (Ctx *ctx, uint32_t key_hash, const char *string, int len);
34862 
ctx_save(Ctx * ctx)34863 void ctx_save (Ctx *ctx)
34864 {
34865   CTX_PROCESS_VOID (CTX_SAVE);
34866 }
ctx_restore(Ctx * ctx)34867 void ctx_restore (Ctx *ctx)
34868 {
34869   CTX_PROCESS_VOID (CTX_RESTORE);
34870 }
34871 
ctx_start_group(Ctx * ctx)34872 void ctx_start_group (Ctx *ctx)
34873 {
34874   CTX_PROCESS_VOID (CTX_START_GROUP);
34875 }
34876 
ctx_end_group(Ctx * ctx)34877 void ctx_end_group (Ctx *ctx)
34878 {
34879   CTX_PROCESS_VOID (CTX_END_GROUP);
34880 }
34881 
ctx_line_width(Ctx * ctx,float x)34882 void ctx_line_width (Ctx *ctx, float x)
34883 {
34884   if (ctx->state.gstate.line_width != x)
34885     CTX_PROCESS_F1 (CTX_LINE_WIDTH, x);
34886 }
34887 
ctx_get_miter_limit(Ctx * ctx)34888 float ctx_get_miter_limit (Ctx *ctx)
34889 {
34890   return ctx->state.gstate.miter_limit;
34891 }
34892 
ctx_get_line_dash_offset(Ctx * ctx)34893 float ctx_get_line_dash_offset (Ctx *ctx)
34894 {
34895   return ctx->state.gstate.line_dash_offset;
34896 }
34897 
ctx_line_dash_offset(Ctx * ctx,float x)34898 void ctx_line_dash_offset (Ctx *ctx, float x)
34899 {
34900   if (ctx->state.gstate.line_dash_offset != x)
34901     CTX_PROCESS_F1 (CTX_LINE_DASH_OFFSET, x);
34902 }
34903 
ctx_get_image_smoothing(Ctx * ctx)34904 int ctx_get_image_smoothing (Ctx *ctx)
34905 {
34906   return ctx->state.gstate.image_smoothing;
34907 }
34908 
ctx_image_smoothing(Ctx * ctx,int enabled)34909 void ctx_image_smoothing (Ctx *ctx, int enabled)
34910 {
34911   if (ctx_get_image_smoothing (ctx) != enabled)
34912     CTX_PROCESS_U8 (CTX_IMAGE_SMOOTHING, enabled);
34913 }
34914 
34915 
ctx_line_dash(Ctx * ctx,float * dashes,int count)34916 void ctx_line_dash (Ctx *ctx, float *dashes, int count)
34917 {
34918   ctx_process_cmd_str_with_len (ctx, CTX_LINE_DASH, (char*)(dashes), count, 0, count * 4);
34919 }
34920 
ctx_shadow_blur(Ctx * ctx,float x)34921 void ctx_shadow_blur (Ctx *ctx, float x)
34922 {
34923 #if CTX_ENABLE_SHADOW_BLUR
34924   if (ctx->state.gstate.shadow_blur != x)
34925 #endif
34926     CTX_PROCESS_F1 (CTX_SHADOW_BLUR, x);
34927 }
34928 
ctx_shadow_rgba(Ctx * ctx,float r,float g,float b,float a)34929 void ctx_shadow_rgba (Ctx *ctx, float r, float g, float b, float a)
34930 {
34931   CtxEntry command[3]=
34932   {
34933     ctx_f (CTX_SHADOW_COLOR, CTX_RGBA, r),
34934     ctx_f (CTX_CONT, g, b),
34935     ctx_f (CTX_CONT, a, 0)
34936   };
34937   ctx_process (ctx, command);
34938 }
34939 
ctx_shadow_offset_x(Ctx * ctx,float x)34940 void ctx_shadow_offset_x (Ctx *ctx, float x)
34941 {
34942 #if CTX_ENABLE_SHADOW_BLUR
34943   if (ctx->state.gstate.shadow_offset_x != x)
34944 #endif
34945     CTX_PROCESS_F1 (CTX_SHADOW_OFFSET_X, x);
34946 }
34947 
ctx_shadow_offset_y(Ctx * ctx,float x)34948 void ctx_shadow_offset_y (Ctx *ctx, float x)
34949 {
34950 #if CTX_ENABLE_SHADOW_BLUR
34951   if (ctx->state.gstate.shadow_offset_y != x)
34952 #endif
34953     CTX_PROCESS_F1 (CTX_SHADOW_OFFSET_Y, x);
34954 }
34955 
34956 void
ctx_global_alpha(Ctx * ctx,float global_alpha)34957 ctx_global_alpha (Ctx *ctx, float global_alpha)
34958 {
34959   if (ctx->state.gstate.global_alpha_f != global_alpha)
34960     CTX_PROCESS_F1 (CTX_GLOBAL_ALPHA, global_alpha);
34961 }
34962 
34963 float
ctx_get_global_alpha(Ctx * ctx)34964 ctx_get_global_alpha (Ctx *ctx)
34965 {
34966   return ctx->state.gstate.global_alpha_f;
34967 }
34968 
34969 void
ctx_font_size(Ctx * ctx,float x)34970 ctx_font_size (Ctx *ctx, float x)
34971 {
34972   CTX_PROCESS_F1 (CTX_FONT_SIZE, x);
34973 }
34974 
ctx_get_font_size(Ctx * ctx)34975 float ctx_get_font_size  (Ctx *ctx)
34976 {
34977   return ctx->state.gstate.font_size;
34978 }
34979 
34980 void
ctx_miter_limit(Ctx * ctx,float limit)34981 ctx_miter_limit (Ctx *ctx, float limit)
34982 {
34983   CTX_PROCESS_F1 (CTX_MITER_LIMIT, limit);
34984 }
34985 
ctx_get_line_width(Ctx * ctx)34986 float ctx_get_line_width (Ctx *ctx)
34987 {
34988   return ctx->state.gstate.line_width;
34989 }
34990 
34991 void
_ctx_font(Ctx * ctx,const char * name)34992 _ctx_font (Ctx *ctx, const char *name)
34993 {
34994   ctx->state.gstate.font = ctx_resolve_font (name);
34995 }
34996 
34997 #if 0
34998 void
34999 ctx_set (Ctx *ctx, uint32_t key_hash, const char *string, int len)
35000 {
35001   if (len <= 0) len = strlen (string);
35002   ctx_process_cmd_str (ctx, CTX_SET, string, key_hash, len);
35003 }
35004 
35005 const char *
35006 ctx_get (Ctx *ctx, const char *key)
35007 {
35008   static char retbuf[32];
35009   int len = 0;
35010   CTX_PROCESS_U32(CTX_GET, ctx_strhash (key), 0);
35011   while (read (STDIN_FILENO, &retbuf[len], 1) != -1)
35012     {
35013       if(retbuf[len]=='\n')
35014         break;
35015       retbuf[++len]=0;
35016     }
35017   return retbuf;
35018 }
35019 #endif
35020 
35021 void
ctx_font_family(Ctx * ctx,const char * name)35022 ctx_font_family (Ctx *ctx, const char *name)
35023 {
35024 #if CTX_BACKEND_TEXT
35025   ctx_process_cmd_str (ctx, CTX_FONT, name, 0, 0);
35026   _ctx_font (ctx, name);
35027 #else
35028   _ctx_font (ctx, name);
35029 #endif
35030 }
35031 
35032 void
ctx_font(Ctx * ctx,const char * family_name)35033 ctx_font (Ctx *ctx, const char *family_name)
35034 {
35035   // should also parse size
35036   ctx_font_family (ctx, family_name);
35037 }
35038 
35039 const char *
ctx_get_font(Ctx * ctx)35040 ctx_get_font (Ctx *ctx)
35041 {
35042   return ctx_fonts[ctx->state.gstate.font].name;
35043 }
35044 
ctx_line_to(Ctx * ctx,float x,float y)35045 void ctx_line_to (Ctx *ctx, float x, float y)
35046 {
35047   if (CTX_UNLIKELY(!ctx->state.has_moved))
35048     { CTX_PROCESS_F (CTX_MOVE_TO, x, y); }
35049   else
35050     { CTX_PROCESS_F (CTX_LINE_TO, x, y); }
35051 }
35052 
ctx_move_to(Ctx * ctx,float x,float y)35053 void ctx_move_to (Ctx *ctx, float x, float y)
35054 {
35055   CTX_PROCESS_F (CTX_MOVE_TO,x,y);
35056 }
35057 
ctx_curve_to(Ctx * ctx,float x0,float y0,float x1,float y1,float x2,float y2)35058 void ctx_curve_to (Ctx *ctx, float x0, float y0,
35059                    float x1, float y1,
35060                    float x2, float y2)
35061 {
35062   CtxEntry command[3]=
35063   {
35064     ctx_f (CTX_CURVE_TO, x0, y0),
35065     ctx_f (CTX_CONT,     x1, y1),
35066     ctx_f (CTX_CONT,     x2, y2)
35067   };
35068   ctx_process (ctx, command);
35069 }
35070 
ctx_round_rectangle(Ctx * ctx,float x0,float y0,float w,float h,float radius)35071 void ctx_round_rectangle (Ctx *ctx,
35072                           float x0, float y0,
35073                           float w, float h,
35074                           float radius)
35075 {
35076   CtxEntry command[3]=
35077   {
35078     ctx_f (CTX_ROUND_RECTANGLE, x0, y0),
35079     ctx_f (CTX_CONT,            w, h),
35080     ctx_f (CTX_CONT,            radius, 0)
35081   };
35082   ctx_process (ctx, command);
35083 }
35084 
ctx_view_box(Ctx * ctx,float x0,float y0,float w,float h)35085 void ctx_view_box (Ctx *ctx,
35086                    float x0, float y0,
35087                    float w, float h)
35088 {
35089   CtxEntry command[3]=
35090   {
35091     ctx_f (CTX_VIEW_BOX, x0, y0),
35092     ctx_f (CTX_CONT,     w, h)
35093   };
35094   ctx_process (ctx, command);
35095 }
35096 
ctx_rectangle(Ctx * ctx,float x0,float y0,float w,float h)35097 void ctx_rectangle (Ctx *ctx,
35098                     float x0, float y0,
35099                     float w, float h)
35100 {
35101   CtxEntry command[3]=
35102   {
35103     ctx_f (CTX_RECTANGLE, x0, y0),
35104     ctx_f (CTX_CONT,      w, h)
35105   };
35106   ctx_process (ctx, command);
35107 }
35108 
ctx_rel_line_to(Ctx * ctx,float x,float y)35109 void ctx_rel_line_to (Ctx *ctx, float x, float y)
35110 {
35111   if (!ctx->state.has_moved)
35112     { return; }
35113   CTX_PROCESS_F (CTX_REL_LINE_TO,x,y);
35114 }
35115 
ctx_rel_move_to(Ctx * ctx,float x,float y)35116 void ctx_rel_move_to (Ctx *ctx, float x, float y)
35117 {
35118   if (!ctx->state.has_moved)
35119     {
35120       CTX_PROCESS_F (CTX_MOVE_TO,x,y);
35121       return;
35122     }
35123   CTX_PROCESS_F (CTX_REL_MOVE_TO,x,y);
35124 }
35125 
ctx_get_line_join(Ctx * ctx)35126 CtxLineJoin ctx_get_line_join (Ctx *ctx)
35127 {
35128   return ctx->state.gstate.line_join;
35129 }
35130 
ctx_get_compositing_mode(Ctx * ctx)35131 CtxCompositingMode ctx_get_compositing_mode (Ctx *ctx)
35132 {
35133   return ctx->state.gstate.compositing_mode;
35134 }
35135 
ctx_get_blend_mode(Ctx * ctx)35136 CtxBlend ctx_get_blend_mode (Ctx *ctx)
35137 {
35138   return ctx->state.gstate.blend_mode;
35139 }
35140 
ctx_get_text_align(Ctx * ctx)35141 CtxTextAlign ctx_get_text_align  (Ctx *ctx)
35142 {
35143   return (CtxTextAlign)ctx_state_get (&ctx->state, CTX_text_align);
35144 }
35145 
ctx_get_text_baseline(Ctx * ctx)35146 CtxTextBaseline ctx_get_text_baseline (Ctx *ctx)
35147 {
35148   return (CtxTextBaseline)ctx_state_get (&ctx->state, CTX_text_baseline);
35149 }
35150 
ctx_get_line_cap(Ctx * ctx)35151 CtxLineCap ctx_get_line_cap (Ctx *ctx)
35152 {
35153   return ctx->state.gstate.line_cap;
35154 }
35155 
ctx_get_fill_rule(Ctx * ctx)35156 CtxFillRule ctx_get_fill_rule (Ctx *ctx)
35157 {
35158   return ctx->state.gstate.fill_rule;
35159 }
35160 
ctx_line_cap(Ctx * ctx,CtxLineCap cap)35161 void ctx_line_cap (Ctx *ctx, CtxLineCap cap)
35162 {
35163   if (ctx->state.gstate.line_cap != cap)
35164     CTX_PROCESS_U8 (CTX_LINE_CAP, cap);
35165 }
35166 
ctx_fill_rule(Ctx * ctx,CtxFillRule fill_rule)35167 void ctx_fill_rule (Ctx *ctx, CtxFillRule fill_rule)
35168 {
35169   if (ctx->state.gstate.fill_rule != fill_rule)
35170     CTX_PROCESS_U8 (CTX_FILL_RULE, fill_rule);
35171 }
ctx_line_join(Ctx * ctx,CtxLineJoin join)35172 void ctx_line_join (Ctx *ctx, CtxLineJoin join)
35173 {
35174   if (ctx->state.gstate.line_join != join)
35175     CTX_PROCESS_U8 (CTX_LINE_JOIN, join);
35176 }
ctx_blend_mode(Ctx * ctx,CtxBlend mode)35177 void ctx_blend_mode (Ctx *ctx, CtxBlend mode)
35178 {
35179   if (ctx->state.gstate.blend_mode != mode)
35180     CTX_PROCESS_U32 (CTX_BLEND_MODE, mode, 0);
35181 }
ctx_compositing_mode(Ctx * ctx,CtxCompositingMode mode)35182 void ctx_compositing_mode (Ctx *ctx, CtxCompositingMode mode)
35183 {
35184   if (ctx->state.gstate.compositing_mode != mode)
35185     CTX_PROCESS_U32 (CTX_COMPOSITING_MODE, mode, 0);
35186 }
ctx_text_align(Ctx * ctx,CtxTextAlign text_align)35187 void ctx_text_align (Ctx *ctx, CtxTextAlign text_align)
35188 {
35189   CTX_PROCESS_U8 (CTX_TEXT_ALIGN, text_align);
35190 }
ctx_text_baseline(Ctx * ctx,CtxTextBaseline text_baseline)35191 void ctx_text_baseline (Ctx *ctx, CtxTextBaseline text_baseline)
35192 {
35193   CTX_PROCESS_U8 (CTX_TEXT_BASELINE, text_baseline);
35194 }
ctx_text_direction(Ctx * ctx,CtxTextDirection text_direction)35195 void ctx_text_direction (Ctx *ctx, CtxTextDirection text_direction)
35196 {
35197   CTX_PROCESS_U8 (CTX_TEXT_DIRECTION, text_direction);
35198 }
35199 
35200 void
ctx_rel_curve_to(Ctx * ctx,float x0,float y0,float x1,float y1,float x2,float y2)35201 ctx_rel_curve_to (Ctx *ctx,
35202                   float x0, float y0,
35203                   float x1, float y1,
35204                   float x2, float y2)
35205 {
35206   if (!ctx->state.has_moved)
35207     { return; }
35208   CtxEntry command[3]=
35209   {
35210     ctx_f (CTX_REL_CURVE_TO, x0, y0),
35211     ctx_f (CTX_CONT, x1, y1),
35212     ctx_f (CTX_CONT, x2, y2)
35213   };
35214   ctx_process (ctx, command);
35215 }
35216 
35217 void
ctx_rel_quad_to(Ctx * ctx,float cx,float cy,float x,float y)35218 ctx_rel_quad_to (Ctx *ctx,
35219                  float cx, float cy,
35220                  float x,  float y)
35221 {
35222   if (!ctx->state.has_moved)
35223     { return; }
35224   CtxEntry command[2]=
35225   {
35226     ctx_f (CTX_REL_QUAD_TO, cx, cy),
35227     ctx_f (CTX_CONT, x, y)
35228   };
35229   ctx_process (ctx, command);
35230 }
35231 
35232 void
ctx_quad_to(Ctx * ctx,float cx,float cy,float x,float y)35233 ctx_quad_to (Ctx *ctx,
35234              float cx, float cy,
35235              float x,  float y)
35236 {
35237   if (!ctx->state.has_moved)
35238     { return; }
35239   CtxEntry command[2]=
35240   {
35241     ctx_f (CTX_QUAD_TO, cx, cy),
35242     ctx_f (CTX_CONT, x, y)
35243   };
35244   ctx_process (ctx, command);
35245 }
35246 
ctx_arc(Ctx * ctx,float x0,float y0,float radius,float angle1,float angle2,int direction)35247 void ctx_arc (Ctx  *ctx,
35248               float x0, float y0,
35249               float radius,
35250               float angle1, float angle2,
35251               int   direction)
35252 {
35253   CtxEntry command[3]=
35254   {
35255     ctx_f (CTX_ARC, x0, y0),
35256     ctx_f (CTX_CONT, radius, angle1),
35257     ctx_f (CTX_CONT, angle2, direction)
35258   };
35259   ctx_process (ctx, command);
35260 }
35261 
ctx_coords_equal(float x1,float y1,float x2,float y2,float tol)35262 static int ctx_coords_equal (float x1, float y1, float x2, float y2, float tol)
35263 {
35264   float dx = x2 - x1;
35265   float dy = y2 - y1;
35266   return dx*dx + dy*dy < tol*tol;
35267 }
35268 
35269 static float
ctx_point_seg_dist_sq(float x,float y,float vx,float vy,float wx,float wy)35270 ctx_point_seg_dist_sq (float x, float y,
35271                        float vx, float vy, float wx, float wy)
35272 {
35273   float l2 = ctx_pow2 (vx-wx) + ctx_pow2 (vy-wy);
35274   if (l2 < 0.0001)
35275     { return ctx_pow2 (x-vx) + ctx_pow2 (y-vy); }
35276   float t = ( (x - vx) * (wx - vx) + (y - vy) * (wy - vy) ) / l2;
35277   t = ctx_maxf (0, ctx_minf (1, t) );
35278   float ix = vx + t * (wx - vx);
35279   float iy = vy + t * (wy - vy);
35280   return ctx_pow2 (x-ix) + ctx_pow2 (y-iy);
35281 }
35282 
35283 static void
ctx_normalize(float * x,float * y)35284 ctx_normalize (float *x, float *y)
35285 {
35286   float length = ctx_hypotf ( (*x), (*y) );
35287   if (length > 1e-6f)
35288     {
35289       float r = 1.0f / length;
35290       *x *= r;
35291       *y *= r;
35292     }
35293 }
35294 
35295 void
ctx_arc_to(Ctx * ctx,float x1,float y1,float x2,float y2,float radius)35296 ctx_arc_to (Ctx *ctx, float x1, float y1, float x2, float y2, float radius)
35297 {
35298   // XXX : should partially move into rasterizer to preserve comand
35299   //       even if an arc preserves all geometry, just to ensure roundtripping
35300   //       of data
35301   /* from nanovg - but not quite working ; uncertain if arc or wrong
35302    * transfusion is the cause.
35303    */
35304   float x0 = ctx->state.x;
35305   float y0 = ctx->state.y;
35306   float dx0,dy0, dx1,dy1, a, d, cx,cy, a0,a1;
35307   int dir;
35308   if (!ctx->state.has_moved)
35309     { return; }
35310   if (1)
35311     {
35312       // Handle degenerate cases.
35313       if (ctx_coords_equal (x0,y0, x1,y1, 0.5f) ||
35314           ctx_coords_equal (x1,y1, x2,y2, 0.5f) ||
35315           ctx_point_seg_dist_sq (x1,y1, x0,y0, x2,y2) < 0.5 ||
35316           radius < 0.5)
35317         {
35318           ctx_line_to (ctx, x1,y1);
35319           return;
35320         }
35321     }
35322   // Calculate tangential circle to lines (x0,y0)-(x1,y1) and (x1,y1)-(x2,y2).
35323   dx0 = x0-x1;
35324   dy0 = y0-y1;
35325   dx1 = x2-x1;
35326   dy1 = y2-y1;
35327   ctx_normalize (&dx0,&dy0);
35328   ctx_normalize (&dx1,&dy1);
35329   a = ctx_acosf (dx0*dx1 + dy0*dy1);
35330   d = radius / ctx_tanf (a/2.0f);
35331 #if 0
35332   if (d > 10000.0f)
35333     {
35334       ctx_line_to (ctx, x1, y1);
35335       return;
35336     }
35337 #endif
35338   if ( (dx1*dy0 - dx0*dy1) > 0.0f)
35339     {
35340       cx = x1 + dx0*d + dy0*radius;
35341       cy = y1 + dy0*d + -dx0*radius;
35342       a0 = ctx_atan2f (dx0, -dy0);
35343       a1 = ctx_atan2f (-dx1, dy1);
35344       dir = 0;
35345     }
35346   else
35347     {
35348       cx = x1 + dx0*d + -dy0*radius;
35349       cy = y1 + dy0*d + dx0*radius;
35350       a0 = ctx_atan2f (-dx0, dy0);
35351       a1 = ctx_atan2f (dx1, -dy1);
35352       dir = 1;
35353     }
35354   ctx_arc (ctx, cx, cy, radius, a0, a1, dir);
35355 }
35356 
35357 void
ctx_rel_arc_to(Ctx * ctx,float x1,float y1,float x2,float y2,float radius)35358 ctx_rel_arc_to (Ctx *ctx, float x1, float y1, float x2, float y2, float radius)
35359 {
35360   x1 += ctx->state.x;
35361   y1 += ctx->state.y;
35362   x2 += ctx->state.x;
35363   y2 += ctx->state.y;
35364   ctx_arc_to (ctx, x1, y1, x2, y2, radius);
35365 }
35366 
35367 void
ctx_exit(Ctx * ctx)35368 ctx_exit (Ctx *ctx)
35369 {
35370   CTX_PROCESS_VOID (CTX_EXIT);
35371 }
35372 
35373 void
ctx_flush(Ctx * ctx)35374 ctx_flush (Ctx *ctx)
35375 {
35376   /* XXX: should be fully moved into the renderers
35377    *      to permit different behavior and get rid
35378    *      of the extranous flush() vfunc.
35379    */
35380   ctx->rev++;
35381 //  CTX_PROCESS_VOID (CTX_FLUSH);
35382 #if 0
35383   //printf (" \e[?2222h");
35384   ctx_drawlist_compact (&ctx->drawlist);
35385   for (int i = 0; i < ctx->drawlist.count - 1; i++)
35386     {
35387       CtxEntry *entry = &ctx->drawlist.entries[i];
35388       fwrite (entry, 9, 1, stdout);
35389 #if 0
35390       uint8_t  *buf = (void *) entry;
35391       for (int j = 0; j < 9; j++)
35392         { printf ("%c", buf[j]); }
35393 #endif
35394     }
35395   printf ("Xx.Xx.Xx.");
35396   fflush (NULL);
35397 #endif
35398   if (ctx->renderer && ctx->renderer->flush)
35399     ctx->renderer->flush (ctx->renderer);
35400   ctx->frame++;
35401   if (ctx->texture_cache != ctx)
35402     ctx->texture_cache->frame++;
35403   ctx->drawlist.count = 0;
35404   ctx_state_init (&ctx->state);
35405 }
35406 
35407 ////////////////////////////////////////
35408 
35409 static inline void
ctx_interpret_style(CtxState * state,CtxEntry * entry,void * data)35410 ctx_interpret_style (CtxState *state, CtxEntry *entry, void *data)
35411 {
35412   CtxCommand *c = (CtxCommand *) entry;
35413   switch (entry->code)
35414     {
35415       case CTX_LINE_DASH_OFFSET:
35416         state->gstate.line_dash_offset = ctx_arg_float (0);
35417         break;
35418       case CTX_LINE_WIDTH:
35419         state->gstate.line_width = ctx_arg_float (0);
35420         break;
35421 #if CTX_ENABLE_SHADOW_BLUR
35422       case CTX_SHADOW_BLUR:
35423         state->gstate.shadow_blur = ctx_arg_float (0);
35424         break;
35425       case CTX_SHADOW_OFFSET_X:
35426         state->gstate.shadow_offset_x = ctx_arg_float (0);
35427         break;
35428       case CTX_SHADOW_OFFSET_Y:
35429         state->gstate.shadow_offset_y = ctx_arg_float (0);
35430         break;
35431 #endif
35432       case CTX_LINE_CAP:
35433         state->gstate.line_cap = (CtxLineCap) ctx_arg_u8 (0);
35434         break;
35435       case CTX_FILL_RULE:
35436         state->gstate.fill_rule = (CtxFillRule) ctx_arg_u8 (0);
35437         break;
35438       case CTX_LINE_JOIN:
35439         state->gstate.line_join = (CtxLineJoin) ctx_arg_u8 (0);
35440         break;
35441       case CTX_COMPOSITING_MODE:
35442         state->gstate.compositing_mode = (CtxCompositingMode) ctx_arg_u32 (0);
35443         break;
35444       case CTX_BLEND_MODE:
35445         state->gstate.blend_mode = (CtxBlend) ctx_arg_u32 (0);
35446         break;
35447       case CTX_TEXT_ALIGN:
35448         ctx_state_set (state, CTX_text_align, ctx_arg_u8 (0) );
35449         break;
35450       case CTX_TEXT_BASELINE:
35451         ctx_state_set (state, CTX_text_baseline, ctx_arg_u8 (0) );
35452         break;
35453       case CTX_TEXT_DIRECTION:
35454         ctx_state_set (state, CTX_text_direction, ctx_arg_u8 (0) );
35455         break;
35456       case CTX_GLOBAL_ALPHA:
35457         state->gstate.global_alpha_u8 = ctx_float_to_u8 (ctx_arg_float (0) );
35458         state->gstate.global_alpha_f = ctx_arg_float (0);
35459         break;
35460       case CTX_FONT_SIZE:
35461         state->gstate.font_size = ctx_arg_float (0);
35462         break;
35463       case CTX_MITER_LIMIT:
35464         state->gstate.miter_limit = ctx_arg_float (0);
35465         break;
35466       case CTX_COLOR_SPACE:
35467         /* move this out of this function and only do it in rasterizer? XXX */
35468         ctx_rasterizer_colorspace_icc (state, (CtxColorSpace)c->colorspace.space_slot,
35469                                               (char*)c->colorspace.data,
35470                                               c->colorspace.data_len);
35471         break;
35472       case CTX_IMAGE_SMOOTHING:
35473         state->gstate.image_smoothing = c->entry.data.u8[0];
35474         break;
35475       case CTX_STROKE_SOURCE:
35476         state->source = 1;
35477         break;
35478 
35479       case CTX_COLOR:
35480         {
35481           int is_stroke = (state->source != 0);
35482           CtxSource *source = is_stroke ?
35483                                 &state->gstate.source_stroke:
35484                                 &state->gstate.source_fill;
35485           state->source = 0;
35486 
35487           source->type = CTX_SOURCE_COLOR;
35488 
35489           //float components[5]={c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, c->cmyka.a};
35490           switch ( ((int) ctx_arg_float (0)) & 511) // XXX remove 511 after stroke source is complete
35491             {
35492               case CTX_RGB:
35493                 ctx_color_set_rgba (state, &source->color, c->rgba.r, c->rgba.g, c->rgba.b, 1.0f);
35494                 break;
35495               case CTX_RGBA:
35496                 ctx_color_set_rgba (state, &source->color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
35497                 break;
35498               case CTX_DRGBA:
35499                 ctx_color_set_drgba (state, &source->color, c->rgba.r, c->rgba.g, c->rgba.b, c->rgba.a);
35500                 break;
35501 #if CTX_ENABLE_CMYK
35502               case CTX_CMYKA:
35503                 ctx_color_set_cmyka (state, &source->color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, c->cmyka.a);
35504                 break;
35505               case CTX_CMYK:
35506                 ctx_color_set_cmyka (state, &source->color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, 1.0f);
35507                 break;
35508               case CTX_DCMYKA:
35509                 ctx_color_set_dcmyka (state, &source->color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, c->cmyka.a);
35510                 break;
35511               case CTX_DCMYK:
35512                 ctx_color_set_dcmyka (state, &source->color, c->cmyka.c, c->cmyka.m, c->cmyka.y, c->cmyka.k, 1.0f);
35513                 break;
35514 #endif
35515               case CTX_GRAYA:
35516                 ctx_color_set_graya (state, &source->color, c->graya.g, c->graya.a);
35517                 break;
35518               case CTX_GRAY:
35519                 ctx_color_set_graya (state, &source->color, c->graya.g, 1.0f);
35520                 break;
35521             }
35522         }
35523         break;
35524       case CTX_SET_RGBA_U8:
35525         //ctx_source_deinit (&state->gstate.source);
35526         //state->gstate.source_fill.type = CTX_SOURCE_COLOR;
35527         {
35528           int is_stroke = (state->source != 0);
35529           CtxSource *source = is_stroke ?
35530                                 &state->gstate.source_stroke:
35531                                 &state->gstate.source_fill;
35532           state->source = 0;
35533 
35534           source->type = CTX_SOURCE_COLOR;
35535 
35536           ctx_color_set_RGBA8 (state, &source->color,
35537                                ctx_arg_u8 (0),
35538                                ctx_arg_u8 (1),
35539                                ctx_arg_u8 (2),
35540                                ctx_arg_u8 (3) );
35541         }
35542         //for (int i = 0; i < 4; i ++)
35543         //  state->gstate.source.color.rgba[i] = ctx_arg_u8(i);
35544         break;
35545       //case CTX_TEXTURE:
35546       //  state->gstate.source.type = CTX_SOURCE_
35547       //  break;
35548       case CTX_LINEAR_GRADIENT:
35549         {
35550           int is_stroke = (state->source != 0);
35551           CtxSource *source = is_stroke ?
35552                                 &state->gstate.source_stroke:
35553                                 &state->gstate.source_fill;
35554           state->source = is_stroke ? 2 : 0;
35555 
35556           float x0 = ctx_arg_float (0);
35557           float y0 = ctx_arg_float (1);
35558           float x1 = ctx_arg_float (2);
35559           float y1 = ctx_arg_float (3);
35560           float dx, dy, length, start, end;
35561 
35562           length = ctx_hypotf (x1-x0,y1-y0);
35563           dx = (x1-x0) / length;
35564           dy = (y1-y0) / length;
35565           start = (x0 * dx + y0 * dy) / length;
35566           end =   (x1 * dx + y1 * dy) / length;
35567           source->linear_gradient.length = length;
35568           source->linear_gradient.dx = dx;
35569           source->linear_gradient.dy = dy;
35570           source->linear_gradient.start = start;
35571           source->linear_gradient.end = end;
35572           source->linear_gradient.rdelta = (end-start)!=0.0?1.0f/(end - start):1.0;
35573           source->type = CTX_SOURCE_LINEAR_GRADIENT;
35574           source->transform = state->gstate.transform;
35575           ctx_matrix_invert (&source->transform);
35576         }
35577         break;
35578       case CTX_RADIAL_GRADIENT:
35579         {
35580           int is_stroke = (state->source != 0);
35581           CtxSource *source = is_stroke ?
35582                                 &state->gstate.source_stroke:
35583                                 &state->gstate.source_fill;
35584           state->source = is_stroke ? 2 : 0;
35585 
35586           float x0 = ctx_arg_float (0);
35587           float y0 = ctx_arg_float (1);
35588           float r0 = ctx_arg_float (2);
35589           float x1 = ctx_arg_float (3);
35590           float y1 = ctx_arg_float (4);
35591           float r1 = ctx_arg_float (5);
35592           source->radial_gradient.x0 = x0;
35593           source->radial_gradient.y0 = y0;
35594           source->radial_gradient.r0 = r0;
35595           source->radial_gradient.x1 = x1;
35596           source->radial_gradient.y1 = y1;
35597           source->radial_gradient.r1 = r1;
35598           source->radial_gradient.rdelta = (r1 - r0) != 0.0 ? 1.0f/(r1-r0):0.0;
35599           source->type      = CTX_SOURCE_RADIAL_GRADIENT;
35600           source->transform = state->gstate.transform;
35601           ctx_matrix_invert (&source->transform);
35602         }
35603         break;
35604     }
35605 }
35606 
35607 static inline void
ctx_interpret_transforms(CtxState * state,CtxEntry * entry,void * data)35608 ctx_interpret_transforms (CtxState *state, CtxEntry *entry, void *data)
35609 {
35610   switch (entry->code)
35611     {
35612       case CTX_SAVE:
35613         ctx_gstate_push (state);
35614         break;
35615       case CTX_RESTORE:
35616         ctx_gstate_pop (state);
35617         break;
35618       case CTX_IDENTITY:
35619         _ctx_matrix_identity (&state->gstate.transform);
35620         break;
35621       case CTX_TRANSLATE:
35622         ctx_matrix_translate (&state->gstate.transform,
35623                               ctx_arg_float (0), ctx_arg_float (1) );
35624         break;
35625       case CTX_SCALE:
35626         ctx_matrix_scale (&state->gstate.transform,
35627                           ctx_arg_float (0), ctx_arg_float (1) );
35628         break;
35629       case CTX_ROTATE:
35630         ctx_matrix_rotate (&state->gstate.transform, ctx_arg_float (0) );
35631         break;
35632       case CTX_APPLY_TRANSFORM:
35633         {
35634           CtxMatrix m;
35635           ctx_matrix_set (&m,
35636                           ctx_arg_float (0), ctx_arg_float (1),
35637                           ctx_arg_float (2), ctx_arg_float (3),
35638                           ctx_arg_float (4), ctx_arg_float (5) );
35639           _ctx_matrix_multiply (&state->gstate.transform,
35640                                 &state->gstate.transform, &m); // XXX verify order
35641         }
35642 #if 0
35643         ctx_matrix_set (&state->gstate.transform,
35644                         ctx_arg_float (0), ctx_arg_float (1),
35645                         ctx_arg_float (2), ctx_arg_float (3),
35646                         ctx_arg_float (4), ctx_arg_float (5) );
35647 #endif
35648         break;
35649     }
35650 }
35651 
35652 /*
35653  * this transforms the contents of entry according to ctx->transformation
35654  */
35655 static inline void
ctx_interpret_pos_transform(CtxState * state,CtxEntry * entry,void * data)35656 ctx_interpret_pos_transform (CtxState *state, CtxEntry *entry, void *data)
35657 {
35658   CtxCommand *c = (CtxCommand *) entry;
35659   float start_x = state->x;
35660   float start_y = state->y;
35661   int had_moved = state->has_moved;
35662   switch (entry->code)
35663     {
35664       case CTX_MOVE_TO:
35665       case CTX_LINE_TO:
35666         {
35667           float x = c->c.x0;
35668           float y = c->c.y0;
35669           if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35670             {
35671               _ctx_user_to_device (state, &x, &y);
35672               ctx_arg_float (0) = x;
35673               ctx_arg_float (1) = y;
35674             }
35675         }
35676         break;
35677       case CTX_ARC:
35678         if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35679           {
35680             float temp;
35681             _ctx_user_to_device (state, &c->arc.x, &c->arc.y);
35682             temp = 0;
35683             _ctx_user_to_device_distance (state, &c->arc.radius, &temp);
35684           }
35685         break;
35686       case CTX_LINEAR_GRADIENT:
35687         if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35688         {
35689         _ctx_user_to_device (state, &c->linear_gradient.x1, &c->linear_gradient.y1);
35690         _ctx_user_to_device (state, &c->linear_gradient.x2, &c->linear_gradient.y2);
35691         }
35692         break;
35693       case CTX_RADIAL_GRADIENT:
35694         if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35695         {
35696           float temp;
35697           _ctx_user_to_device (state, &c->radial_gradient.x1, &c->radial_gradient.y1);
35698           temp = 0;
35699           _ctx_user_to_device_distance (state, &c->radial_gradient.r1, &temp);
35700           _ctx_user_to_device (state, &c->radial_gradient.x2, &c->radial_gradient.y2);
35701           temp = 0;
35702           _ctx_user_to_device_distance (state, &c->radial_gradient.r2, &temp);
35703         }
35704         break;
35705       case CTX_CURVE_TO:
35706         if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35707           {
35708             for (int c = 0; c < 3; c ++)
35709               {
35710                 float x = entry[c].data.f[0];
35711                 float y = entry[c].data.f[1];
35712                 _ctx_user_to_device (state, &x, &y);
35713                 entry[c].data.f[0] = x;
35714                 entry[c].data.f[1] = y;
35715               }
35716           }
35717         break;
35718       case CTX_QUAD_TO:
35719         if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35720           {
35721             for (int c = 0; c < 2; c ++)
35722               {
35723                 float x = entry[c].data.f[0];
35724                 float y = entry[c].data.f[1];
35725                 _ctx_user_to_device (state, &x, &y);
35726                 entry[c].data.f[0] = x;
35727                 entry[c].data.f[1] = y;
35728               }
35729           }
35730         break;
35731       case CTX_REL_MOVE_TO:
35732       case CTX_REL_LINE_TO:
35733         if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35734           {
35735             for (int c = 0; c < 1; c ++)
35736               {
35737                 float x = state->x;
35738                 float y = state->y;
35739                 _ctx_user_to_device (state, &x, &y);
35740                 entry[c].data.f[0] = x;
35741                 entry[c].data.f[1] = y;
35742               }
35743             if (entry->code == CTX_REL_MOVE_TO)
35744               { entry->code = CTX_MOVE_TO; }
35745             else
35746               { entry->code = CTX_LINE_TO; }
35747           }
35748         break;
35749       case CTX_REL_CURVE_TO:
35750         {
35751           float nx = state->x + ctx_arg_float (4);
35752           float ny = state->y + ctx_arg_float (5);
35753           if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35754             {
35755               for (int c = 0; c < 3; c ++)
35756                 {
35757                   float x = nx + entry[c].data.f[0];
35758                   float y = ny + entry[c].data.f[1];
35759                   _ctx_user_to_device (state, &x, &y);
35760                   entry[c].data.f[0] = x;
35761                   entry[c].data.f[1] = y;
35762                 }
35763               entry->code = CTX_CURVE_TO;
35764             }
35765         }
35766         break;
35767       case CTX_REL_QUAD_TO:
35768         {
35769           float nx = state->x + ctx_arg_float (2);
35770           float ny = state->y + ctx_arg_float (3);
35771           if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) )
35772             {
35773               for (int c = 0; c < 2; c ++)
35774                 {
35775                   float x = nx + entry[c].data.f[0];
35776                   float y = ny + entry[c].data.f[1];
35777                   _ctx_user_to_device (state, &x, &y);
35778                   entry[c].data.f[0] = x;
35779                   entry[c].data.f[1] = y;
35780                 }
35781               entry->code = CTX_QUAD_TO;
35782             }
35783         }
35784         break;
35785     }
35786   if ((((Ctx *) (data) )->transformation & CTX_TRANSFORMATION_RELATIVE))
35787     {
35788       int components = 0;
35789       _ctx_user_to_device (state, &start_x, &start_y);
35790       switch (entry->code)
35791         {
35792           case CTX_MOVE_TO:
35793             if (had_moved) { components = 1; }
35794             break;
35795           case CTX_LINE_TO:
35796             components = 1;
35797             break;
35798           case CTX_CURVE_TO:
35799             components = 3;
35800             break;
35801           case CTX_QUAD_TO:
35802             components = 2;
35803             break;
35804         }
35805       if (components)
35806         {
35807           for (int c = 0; c < components; c++)
35808             {
35809               entry[c].data.f[0] -= start_x;
35810               entry[c].data.f[1] -= start_y;
35811             }
35812           switch (entry->code)
35813             {
35814               case CTX_MOVE_TO:
35815                 entry[0].code = CTX_REL_MOVE_TO;
35816                 break;
35817               case CTX_LINE_TO:
35818                 entry[0].code = CTX_REL_LINE_TO;
35819                 break;
35820                 break;
35821               case CTX_CURVE_TO:
35822                 entry[0].code = CTX_REL_CURVE_TO;
35823                 break;
35824               case CTX_QUAD_TO:
35825                 entry[0].code = CTX_REL_QUAD_TO;
35826                 break;
35827             }
35828         }
35829     }
35830 }
35831 
35832 static inline void
ctx_interpret_pos_bare(CtxState * state,CtxEntry * entry,void * data)35833 ctx_interpret_pos_bare (CtxState *state, CtxEntry *entry, void *data)
35834 {
35835   switch (entry->code)
35836     {
35837       case CTX_RESET:
35838         ctx_state_init (state);
35839         break;
35840       case CTX_CLIP:
35841       case CTX_BEGIN_PATH:
35842       case CTX_FILL:
35843       case CTX_STROKE:
35844         state->has_moved = 0;
35845         break;
35846       case CTX_MOVE_TO:
35847       case CTX_LINE_TO:
35848         state->x = ctx_arg_float (0);
35849         state->y = ctx_arg_float (1);
35850         state->has_moved = 1;
35851         break;
35852       case CTX_CURVE_TO:
35853         state->x = ctx_arg_float (4);
35854         state->y = ctx_arg_float (5);
35855         state->has_moved = 1;
35856         break;
35857       case CTX_QUAD_TO:
35858         state->x = ctx_arg_float (2);
35859         state->y = ctx_arg_float (3);
35860         state->has_moved = 1;
35861         break;
35862       case CTX_ARC:
35863         state->x = ctx_arg_float (0) + ctx_cosf (ctx_arg_float (4) ) * ctx_arg_float (2);
35864         state->y = ctx_arg_float (1) + ctx_sinf (ctx_arg_float (4) ) * ctx_arg_float (2);
35865         break;
35866       case CTX_REL_MOVE_TO:
35867       case CTX_REL_LINE_TO:
35868         state->x += ctx_arg_float (0);
35869         state->y += ctx_arg_float (1);
35870         break;
35871       case CTX_REL_CURVE_TO:
35872         state->x += ctx_arg_float (4);
35873         state->y += ctx_arg_float (5);
35874         break;
35875       case CTX_REL_QUAD_TO:
35876         state->x += ctx_arg_float (2);
35877         state->y += ctx_arg_float (3);
35878         break;
35879         // XXX missing some smooths
35880     }
35881 }
35882 
35883 static inline void
ctx_interpret_pos(CtxState * state,CtxEntry * entry,void * data)35884 ctx_interpret_pos (CtxState *state, CtxEntry *entry, void *data)
35885 {
35886   if ( ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_SCREEN_SPACE) ||
35887        ( ( (Ctx *) (data) )->transformation & CTX_TRANSFORMATION_RELATIVE) )
35888     {
35889       ctx_interpret_pos_transform (state, entry, data);
35890     }
35891   ctx_interpret_pos_bare (state, entry, data);
35892 }
35893 
35894 #if CTX_BABL
35895 void ctx_colorspace_babl (CtxState   *state,
35896                           CtxColorSpace  icc_slot,
35897                           const Babl *space);
35898 #endif
35899 
35900 static void
ctx_state_init(CtxState * state)35901 ctx_state_init (CtxState *state)
35902 {
35903   ctx_memset (state, 0, sizeof (CtxState) );
35904   state->gstate.global_alpha_u8 = 255;
35905   state->gstate.global_alpha_f  = 1.0;
35906   state->gstate.font_size       = 23; // default HTML canvas is 10px sans
35907   state->gstate.line_width      = 2.0;
35908   state->gstate.image_smoothing = 1;
35909   state->gstate.source_stroke.type = CTX_SOURCE_INHERIT_FILL;
35910   ctx_state_set (state, CTX_line_spacing, 1.0f);
35911   state->min_x                  = 8192;
35912   state->min_y                  = 8192;
35913   state->max_x                  = -8192;
35914   state->max_y                  = -8192;
35915   _ctx_matrix_identity (&state->gstate.transform);
35916 #if CTX_CM
35917 #if CTX_BABL
35918   //ctx_colorspace_babl (state, CTX_COLOR_SPACE_USER_RGB,   babl_space ("sRGB"));
35919   //ctx_colorspace_babl (state, CTX_COLOR_SPACE_DEVICE_RGB, babl_space ("ACEScg"));
35920 #endif
35921 #endif
35922 }
35923 
_ctx_set_transformation(Ctx * ctx,int transformation)35924 void _ctx_set_transformation (Ctx *ctx, int transformation)
35925 {
35926   ctx->transformation = transformation;
35927 }
35928 
35929 static void
_ctx_init(Ctx * ctx)35930 _ctx_init (Ctx *ctx)
35931 {
35932   for (int i = 0; i <256;i++)
35933     ctx_u8_float[i] = i/255.0f;
35934 
35935   ctx_state_init (&ctx->state);
35936 
35937   ctx->renderer = NULL;
35938 #if CTX_CURRENT_PATH
35939   ctx->current_path.flags |= CTX_DRAWLIST_CURRENT_PATH;
35940 #endif
35941   //ctx->transformation |= (CtxTransformation) CTX_TRANSFORMATION_SCREEN_SPACE;
35942   //ctx->transformation |= (CtxTransformation) CTX_TRANSFORMATION_RELATIVE;
35943 #if CTX_BITPACK
35944   ctx->drawlist.flags |= CTX_TRANSFORMATION_BITPACK;
35945 #endif
35946   ctx->texture_cache = ctx;
35947 }
35948 
35949 static void ctx_setup (void);
35950 
35951 #if CTX_DRAWLIST_STATIC
35952 static Ctx ctx_state;
35953 #endif
35954 
ctx_set_renderer(Ctx * ctx,void * renderer)35955 void ctx_set_renderer (Ctx  *ctx,
35956                        void *renderer)
35957 {
35958   if (ctx->renderer && ctx->renderer->free)
35959     ctx->renderer->free (ctx->renderer);
35960   ctx->renderer = (CtxImplementation*)renderer;
35961 }
35962 
ctx_get_renderer(Ctx * ctx)35963 void *ctx_get_renderer (Ctx *ctx)
35964 {
35965   return ctx->renderer;
35966 }
35967 
35968 Ctx *
ctx_new(void)35969 ctx_new (void)
35970 {
35971   ctx_setup ();
35972 #if CTX_DRAWLIST_STATIC
35973   Ctx *ctx = &ctx_state;
35974 #else
35975   Ctx *ctx = (Ctx *) malloc (sizeof (Ctx) );
35976 #endif
35977   ctx_memset (ctx, 0, sizeof (Ctx) );
35978   _ctx_init (ctx);
35979   return ctx;
35980 }
35981 
35982 static inline void
ctx_drawlist_deinit(CtxDrawlist * drawlist)35983 ctx_drawlist_deinit (CtxDrawlist *drawlist)
35984 {
35985 #if !CTX_DRAWLIST_STATIC
35986   if (drawlist->entries && ! (drawlist->flags & CTX_DRAWLIST_DOESNT_OWN_ENTRIES) )
35987     {
35988       free (drawlist->entries);
35989     }
35990 #endif
35991   drawlist->entries = NULL;
35992   drawlist->size = 0;
35993 }
35994 
ctx_deinit(Ctx * ctx)35995 static void ctx_deinit (Ctx *ctx)
35996 {
35997   if (ctx->renderer)
35998     {
35999       if (ctx->renderer->free)
36000         ctx->renderer->free (ctx->renderer);
36001       ctx->renderer    = NULL;
36002     }
36003   ctx_drawlist_deinit (&ctx->drawlist);
36004 #if CTX_CURRENT_PATH
36005   ctx_drawlist_deinit (&ctx->current_path);
36006 #endif
36007 }
36008 
ctx_free(Ctx * ctx)36009 void ctx_free (Ctx *ctx)
36010 {
36011   if (!ctx)
36012     { return; }
36013 #if CTX_EVENTS
36014   ctx_clear_bindings (ctx);
36015 #endif
36016   ctx_deinit (ctx);
36017 #if !CTX_DRAWLIST_STATIC
36018   free (ctx);
36019 #endif
36020 }
36021 
ctx_new_for_drawlist(void * data,size_t length)36022 Ctx *ctx_new_for_drawlist (void *data, size_t length)
36023 {
36024   Ctx *ctx = ctx_new ();
36025   ctx->drawlist.flags   |= CTX_DRAWLIST_DOESNT_OWN_ENTRIES;
36026   ctx->drawlist.entries  = (CtxEntry *) data;
36027   ctx->drawlist.count    = length / sizeof (CtxEntry);
36028   return ctx;
36029 }
36030 
ctx_setup(void)36031 static void ctx_setup (void)
36032 {
36033   ctx_font_setup ();
36034 }
36035 
36036 void
ctx_render_ctx(Ctx * ctx,Ctx * d_ctx)36037 ctx_render_ctx (Ctx *ctx, Ctx *d_ctx)
36038 {
36039   CtxIterator iterator;
36040   CtxCommand *command;
36041   ctx_iterator_init (&iterator, &ctx->drawlist, 0,
36042                      CTX_ITERATOR_EXPAND_BITPACK);
36043   while ( (command = ctx_iterator_next (&iterator) ) )
36044     {
36045        ctx_process (d_ctx, &command->entry);
36046     }
36047 }
36048 
36049 void
ctx_render_ctx_textures(Ctx * ctx,Ctx * d_ctx)36050 ctx_render_ctx_textures (Ctx *ctx, Ctx *d_ctx)
36051 {
36052   CtxIterator iterator;
36053   CtxCommand *command;
36054   ctx_iterator_init (&iterator, &ctx->drawlist, 0,
36055                      CTX_ITERATOR_EXPAND_BITPACK);
36056   while ( (command = ctx_iterator_next (&iterator) ) )
36057     {
36058        switch (command->code)
36059        {
36060          default:
36061                  //fprintf (stderr, "[%c]", command->code);
36062                  break;
36063          case CTX_TEXTURE:
36064              //fprintf (stderr, "t:%s\n", command->texture.eid);
36065              ctx_process (d_ctx, &command->entry);
36066              break;
36067          case CTX_DEFINE_TEXTURE:
36068              //fprintf (stderr, "d:%s\n", command->define_texture.eid);
36069              ctx_process (d_ctx, &command->entry);
36070            break;
36071        }
36072     }
36073 }
36074 
ctx_quit(Ctx * ctx)36075 void ctx_quit (Ctx *ctx)
36076 {
36077 #if CTX_EVENTS
36078   ctx->quit ++;
36079 #endif
36080 }
36081 
ctx_has_quit(Ctx * ctx)36082 int  ctx_has_quit (Ctx *ctx)
36083 {
36084 #if CTX_EVENTS
36085   return (ctx->quit);
36086 #else
36087   return 1;
36088 #endif
36089 }
36090 
ctx_pixel_format_bits_per_pixel(CtxPixelFormat format)36091 int ctx_pixel_format_bits_per_pixel (CtxPixelFormat format)
36092 {
36093   CtxPixelFormatInfo *info = ctx_pixel_format_info (format);
36094   if (info)
36095     return info->bpp;
36096   return -1;
36097 }
36098 
ctx_pixel_format_get_stride(CtxPixelFormat format,int width)36099 int ctx_pixel_format_get_stride (CtxPixelFormat format, int width)
36100 {
36101   CtxPixelFormatInfo *info = ctx_pixel_format_info (format);
36102   if (info)
36103   {
36104     switch (info->bpp)
36105     {
36106       case 0:
36107       case 1:
36108         return (width + 7)/8;
36109       case 2:
36110         return (width + 3)/4;
36111       case 4:
36112         return (width + 1)/2;
36113       default:
36114         return width * (info->bpp / 8);
36115     }
36116   }
36117   return width;
36118 }
36119 
ctx_pixel_format_ebpp(CtxPixelFormat format)36120 int ctx_pixel_format_ebpp (CtxPixelFormat format)
36121 {
36122   CtxPixelFormatInfo *info = ctx_pixel_format_info (format);
36123   if (info)
36124     return info->ebpp;
36125   return -1;
36126 }
36127 
ctx_pixel_format_components(CtxPixelFormat format)36128 int ctx_pixel_format_components (CtxPixelFormat format)
36129 {
36130   CtxPixelFormatInfo *info = ctx_pixel_format_info (format);
36131   if (info)
36132     return info->components;
36133   return -1;
36134 }
36135 
36136 #if CTX_EVENTS
ctx_set_cursor(Ctx * ctx,CtxCursor cursor)36137 void         ctx_set_cursor (Ctx *ctx, CtxCursor cursor)
36138 {
36139   if (ctx->cursor != cursor)
36140   {
36141     ctx_set_dirty (ctx, 1);
36142     ctx->cursor = cursor;
36143   }
36144 }
ctx_get_cursor(Ctx * ctx)36145 CtxCursor    ctx_get_cursor (Ctx *ctx)
36146 {
36147   return ctx->cursor;
36148 }
36149 
ctx_set_clipboard(Ctx * ctx,const char * text)36150 void ctx_set_clipboard (Ctx *ctx, const char *text)
36151 {
36152   if (ctx->renderer && ctx->renderer->set_clipboard)
36153   {
36154     ctx->renderer->set_clipboard (ctx->renderer, text);
36155     return;
36156   }
36157 }
36158 
ctx_get_clipboard(Ctx * ctx)36159 char *ctx_get_clipboard (Ctx *ctx)
36160 {
36161   if (ctx->renderer && ctx->renderer->get_clipboard)
36162   {
36163     return ctx->renderer->get_clipboard (ctx->renderer);
36164   }
36165   return strdup ("");
36166 }
36167 
ctx_set_texture_source(Ctx * ctx,Ctx * texture_source)36168 void ctx_set_texture_source (Ctx *ctx, Ctx *texture_source)
36169 {
36170   ((CtxRasterizer*)ctx->renderer)->texture_source = texture_source;
36171 }
36172 
ctx_set_texture_cache(Ctx * ctx,Ctx * texture_cache)36173 void ctx_set_texture_cache (Ctx *ctx, Ctx *texture_cache)
36174 {
36175   ctx->texture_cache = texture_cache;
36176 }
36177 
ctx_set_transform(Ctx * ctx,float a,float b,float c,float d,float e,float f)36178 void ctx_set_transform (Ctx *ctx, float a, float b, float c, float d, float e, float f)
36179 {
36180   ctx_identity (ctx);
36181   ctx_apply_transform (ctx, a, b, c, d, e, f);
36182 }
36183 
36184 #endif
36185 
36186 #if CTX_GET_CONTENTS
36187 
36188 #ifndef NO_LIBCURL
36189 #include <curl/curl.h>
36190 static size_t
ctx_string_append_callback(void * contents,size_t size,size_t nmemb,void * userp)36191 ctx_string_append_callback (void *contents, size_t size, size_t nmemb, void *userp)
36192 {
36193   CtxString *string = (CtxString*)userp;
36194   ctx_string_append_data ((CtxString*)string, contents, size * nmemb);
36195   return size * nmemb;
36196 }
36197 
36198 #endif
36199 
36200 int
ctx_get_contents2(const char * uri,unsigned char ** contents,long * length,long max_len)36201 ctx_get_contents2 (const char     *uri,
36202                    unsigned char **contents,
36203                    long           *length,
36204                    long            max_len)
36205 {
36206   char *temp_uri = NULL; // XXX XXX breaks with data uri's
36207   int   success  = -1;
36208 
36209   if (uri[0] == '/')
36210   {
36211     temp_uri = (char*) malloc (strlen (uri) + 8);
36212     sprintf (temp_uri, "file://%s", uri);
36213     uri = temp_uri;
36214   }
36215 
36216   if (strchr (uri, '#'))
36217    strchr (uri, '#')[0]=0;
36218 
36219   for (CtxList *l = registered_contents; l; l = l->next)
36220   {
36221     CtxFileContent *c = (CtxFileContent*)l->data;
36222     if (!strcmp (c->path, uri))
36223     {
36224       contents = malloc (c->length+1);
36225       contents[c->length]=0;
36226       if (length) *length = c->length;
36227       free (temp_uri);
36228       return 0;
36229     }
36230   }
36231 
36232   if (!strncmp (uri, "file://", 5))
36233   {
36234     if (strchr (uri, '?'))
36235      strchr (uri, '?')[0]=0;
36236   }
36237 
36238   if (!strncmp (uri, "file://", 7))
36239     success = ___ctx_file_get_contents (uri + 7, contents, length, max_len);
36240   else
36241   {
36242 #ifndef NO_LIBCURL
36243   CURL *curl = curl_easy_init ();
36244   CURLcode res;
36245 
36246   curl_easy_setopt(curl, CURLOPT_URL, uri);
36247   curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
36248     CtxString *string = ctx_string_new ("");
36249 
36250       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ctx_string_append_callback);
36251    /* we pass our 'chunk' struct to the callback function */
36252   curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)string);
36253 
36254   curl_easy_setopt(curl, CURLOPT_USERAGENT, "ctx/0.0");
36255 
36256    res = curl_easy_perform(curl);
36257   /* check for errors */
36258   if(res != CURLE_OK) {
36259           fprintf(stderr, "curl_easy_perform() failed: %s\n",
36260             curl_easy_strerror(res));
36261      curl_easy_cleanup (curl);
36262   }
36263   else
36264   {
36265      *contents = (unsigned char*)string->str;
36266      *length = string->length;
36267      ctx_string_free (string, 0);
36268      curl_easy_cleanup (curl);
36269      success = 0;
36270   }
36271 #else
36272     success = ___ctx_file_get_contents (uri, contents, length, max_len);
36273 #endif
36274   }
36275   free (temp_uri);
36276   return success;
36277 }
36278 
36279 
36280 int
ctx_get_contents(const char * uri,unsigned char ** contents,long * length)36281 ctx_get_contents (const char     *uri,
36282                   unsigned char **contents,
36283                   long           *length)
36284 {
36285   return ctx_get_contents2 (uri, contents, length, 1024*1024*1024);
36286 }
36287 
36288 
36289 
36290 typedef struct CtxMagicEntry {
36291   const char *mime_type;
36292   const char *ext1;
36293   int len;
36294   uint8_t magic[16];
36295 } CtxMagicEntry;
36296 
36297 static CtxMagicEntry ctx_magics[]={
36298   {"image/bmp",  ".bmp", 0, {0}},
36299   {"image/png",  ".png", 8, {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a}},
36300   {"image/jpeg", ".jpg", 8, {0xff, 0xd8, 0xff, 0xdb, 0xff, 0xd8, 0xff, 0xe0}},
36301   {"image/jpeg", ".jpeg", 8, {0xff, 0xd8, 0xff, 0xdb, 0xff, 0xd8, 0xff, 0xe0}},
36302   {"image/gif",  ".gif", 6, {0x47, 0x49, 0x46, 0x38, 0x37, 0x61}},
36303   {"image/gif",  ".gif", 6, {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}},
36304   {"image/exr",  ".exr", 4, {0x76, 0x2f, 0x31, 0x01}},
36305   {"video/mpeg", ".mpg", 4, {0x00, 0x00, 0x01, 0xba}},
36306   {"application/blender", ".blend", 8, {0x42, 0x4c,0x45,0x4e,0x44,0x45,0x52}},
36307   {"image/xcf",  ".xcf", 8, {0x67, 0x69,0x6d,0x70,0x20,0x78,0x63,0x66}},
36308   {"application/bzip2", ".bz2", 3, {0x42, 0x5a, 0x68}},
36309   {"application/gzip", ".gz", 0, {0x0}},
36310   {"text/x-csrc", ".c", 0, {0,}},
36311   {"text/x-chdr", ".h", 0, {0,}},
36312   {"text/css", ".css", 0, {0x0}},
36313   {"text/csv", ".csv", 0, {0x0}},
36314   {"text/html", ".htm", 0, {0x0}},
36315   {"text/html", ".html", 0, {0x0}},
36316   {"text/x-makefile", "makefile", 0, {0x0}},
36317   {"application/atom+xml", ".atom", 0, {0x0}},
36318   {"application/rdf+xml", ".rdf", 0, {0x0}},
36319   {"application/javascript", ".js", 0, {0x0}},
36320   {"application/json", ".json", 0, {0x0}},
36321   {"application/octet-stream", ".bin", 0, {0x0}},
36322   {"application/x-object", ".o", 0, {0x0}},
36323   {"text/x-sh", ".sh", 0, {0x0}},
36324   {"text/x-python", ".py", 0, {0x0}},
36325   {"text/x-perl", ".pl", 0, {0x0}},
36326   {"text/x-perl", ".pm", 0, {0x0}},
36327   {"application/pdf", ".pdf", 0, {0x0}},
36328   {"application/ctx", ".ctx", 0, {0x0}},
36329   {"text/xml", ".xml",     0, {0x0}},
36330   {"video/mp4", ".mp4",    0, {0x0}},
36331   {"video/ogg", ".ogv",    0, {0x0}},
36332   {"audio/sp-midi", ".mid",  0, {0x0}},
36333   {"audio/x-wav", ".wav",  0, {0x0}},
36334   {"audio/ogg", ".ogg",    0, {0x0}},
36335   {"audio/ogg", ".opus",   0, {0x0}},
36336   {"audio/ogg", ".oga",    0, {0x0}},
36337   {"audio/mpeg", ".mp1",   0, {0x0}},
36338   {"audio/m3u", ".m3u",    0, {0x0}},
36339   {"audio/mpeg", ".mp2",   0, {0x0}},
36340   {"audio/mpeg", ".mp3",   0, {0x0}},
36341   {"audio/mpeg", ".m4a",   0, {0x0}},
36342   {"audio/mpeg", ".mpga",  0, {0x0}},
36343   {"audio/mpeg", ".mpega", 0, {0x0}},
36344   {"font/otf", ".otf", 0,{0x0}},
36345   {"font/ttf", ".ttf", 0,{0x0}},
36346   // inode-directory
36347 };
36348 
ctx_path_is_dir(const char * path)36349 static int ctx_path_is_dir (const char *path)
36350 {
36351   struct stat stat_buf;
36352   if (!path || path[0]==0) return 0;
36353   lstat (path, &stat_buf);
36354   return S_ISDIR (stat_buf.st_mode);
36355 }
36356 
ctx_path_is_exec(const char * path)36357 static int ctx_path_is_exec (const char *path)
36358 {
36359   struct stat stat_buf;
36360   if (!path || path[0]==0) return 0;
36361   lstat (path, &stat_buf);
36362   return stat_buf.st_mode & 0x1;
36363 }
36364 
ctx_guess_media_type(const char * path,const char * content,int len)36365 const char *ctx_guess_media_type (const char *path, const char *content, int len)
36366 {
36367   const char *extension_match = NULL;
36368   if (path && strrchr (path, '.'))
36369   {
36370     char *pathdup = strdup (strrchr(path, '.'));
36371     for (int i = 0; pathdup[i]; i++) pathdup[i]=tolower(pathdup[i]);
36372     for (unsigned int i = 0; i < sizeof (ctx_magics)/sizeof(ctx_magics[0]);i++)
36373     {
36374       if (ctx_magics[i].ext1 && !strcmp (ctx_magics[i].ext1, pathdup))
36375       {
36376         extension_match = ctx_magics[i].mime_type;
36377       }
36378     }
36379     free (pathdup);
36380   }
36381 
36382   if (len > 16)
36383   {
36384     for (unsigned int i = 0; i < sizeof (ctx_magics)/sizeof(ctx_magics[0]);i++)
36385     {
36386        if (ctx_magics[i].len) // skip extension only matches
36387        if (!memcmp (content, ctx_magics[i].magic, ctx_magics[i].len))
36388        {
36389          return ctx_magics[i].mime_type;
36390        }
36391     }
36392   }
36393 
36394   if (extension_match && !strcmp (extension_match, "application/ctx"))
36395   {
36396           fprintf (stderr, "!!\n");
36397     //if (!ctx_path_is_exec (path))
36398     //  extension_match = NULL;
36399   }
36400 
36401   if (extension_match) return extension_match;
36402 
36403 
36404   int non_ascii=0;
36405   for (int i = 0; i < len; i++)
36406   {
36407     int p = content[i];
36408     if (p > 127) non_ascii = 1;
36409     if (p == 0) non_ascii = 1;
36410   }
36411   if (non_ascii)
36412     return "application/octet-stream";
36413   return "text/plain";
36414 }
36415 
36416 
ctx_path_get_media_type(const char * path)36417 const char *ctx_path_get_media_type (const char *path)
36418 {
36419   char *content = NULL;
36420   long length = 0;
36421 
36422   /* XXX : code duplication, factor out in separate fun */
36423   if (path && strrchr (path, '.'))
36424   {
36425     char *pathdup = strdup (strrchr(path, '.'));
36426     for (int i = 0; pathdup[i]; i++) pathdup[i]=tolower(pathdup[i]);
36427     for (unsigned int i = 0; i < sizeof (ctx_magics)/sizeof(ctx_magics[0]);i++)
36428     {
36429       if (ctx_magics[i].ext1 && !strcmp (ctx_magics[i].ext1, pathdup))
36430       {
36431         free (pathdup);
36432         return ctx_magics[i].mime_type;
36433       }
36434     }
36435     free (pathdup);
36436   }
36437   if (ctx_path_is_dir (path))
36438     return "inode/directory";
36439 
36440   ctx_get_contents2 (path, (uint8_t**)&content, &length, 32);
36441   if (content)
36442   {
36443   const char *guess = ctx_guess_media_type (path, content, length);
36444   free (content);
36445   return guess;
36446   }
36447   return "application/none";
36448 }
36449 
ctx_media_type_class(const char * media_type)36450 CtxMediaTypeClass ctx_media_type_class (const char *media_type)
36451 {
36452   CtxMediaTypeClass ret = CTX_MEDIA_TYPE_NONE;
36453   if (!media_type) return ret;
36454   if (!ret){
36455     ret = CTX_MEDIA_TYPE_IMAGE;
36456     if (media_type[0]!='i')ret = 0;
36457     if (media_type[1]!='m')ret = 0;
36458     /*
36459     if (media_type[2]!='a')ret = 0;
36460     if (media_type[3]!='g')ret = 0;
36461     if (media_type[4]!='e')ret = 0;*/
36462   }
36463   if (!ret){
36464     ret = CTX_MEDIA_TYPE_VIDEO;
36465     if (media_type[0]!='v')ret = 0;
36466     if (media_type[1]!='i')ret = 0;
36467     /*
36468     if (media_type[2]!='d')ret = 0;
36469     if (media_type[3]!='e')ret = 0;
36470     if (media_type[4]!='o')ret = 0;*/
36471   }
36472   if (!ret){
36473     ret = CTX_MEDIA_TYPE_AUDIO;
36474     if (media_type[0]!='a')ret = 0;
36475     if (media_type[1]!='u')ret = 0;
36476     /*
36477     if (media_type[2]!='d')ret = 0;
36478     if (media_type[3]!='i')ret = 0;
36479     if (media_type[4]!='o')ret = 0;*/
36480   }
36481   if (!ret){
36482     ret = CTX_MEDIA_TYPE_TEXT;
36483     if (media_type[0]!='t')ret = 0;
36484     if (media_type[1]!='e')ret = 0;
36485     /*
36486     if (media_type[2]!='x')ret = 0;
36487     if (media_type[3]!='t')ret = 0;*/
36488   }
36489   if (!ret){
36490     ret = CTX_MEDIA_TYPE_APPLICATION;
36491     if (media_type[0]!='a')ret = 0;
36492     if (media_type[1]!='p')ret = 0;
36493     /*
36494     if (media_type[2]!='p')ret = 0;
36495     if (media_type[3]!='l')ret = 0;*/
36496   }
36497   if (!ret){
36498     ret = CTX_MEDIA_TYPE_INODE;
36499     if (media_type[0]!='i')ret = 0;
36500     if (media_type[1]!='n')ret = 0;
36501     /*
36502     if (media_type[2]!='o')ret = 0;
36503     if (media_type[3]!='d')ret = 0;
36504     if (media_type[4]!='e')ret = 0;*/
36505   }
36506   return ret;
36507 }
36508 
36509 #endif
36510 
36511 #endif // CTX_IMPLEMENTATION
36512 #ifndef __CTX_CLIENTS_H
36513 #define __CTX_CLIENTS_H
36514 
36515 typedef enum CtxClientFlags {
36516   ITK_CLIENT_UI_RESIZABLE = 1<<0,
36517   ITK_CLIENT_CAN_LAUNCH   = 1<<1,
36518   ITK_CLIENT_MAXIMIZED    = 1<<2,
36519   ITK_CLIENT_ICONIFIED    = 1<<3,
36520   ITK_CLIENT_SHADED       = 1<<4,
36521   ITK_CLIENT_TITLEBAR     = 1<<5,
36522   ITK_CLIENT_LAYER2       = 1<<6,  // used for having a second set
36523                                    // to draw - useful for splitting
36524                                    // scrolled and HUD items
36525                                    // with HUD being LAYER2
36526 
36527   ITK_CLIENT_KEEP_ALIVE   = 1<<7,  // do not automatically
36528   ITK_CLIENT_FINISHED     = 1<<8,  // do not automatically
36529                                    // remove after process quits
36530   ITK_CLIENT_PRELOAD      = 1<<9
36531 } CtxClientFlags;
36532 
36533 typedef struct _CtxClient CtxClient;
36534 typedef void (*CtxClientFinalize)(CtxClient *client, void *user_data);
36535 
36536 struct _CtxClient {
36537   VT    *vt;
36538   Ctx   *ctx;
36539   char  *title;
36540   int    x;
36541   int    y;
36542   int    width;
36543   int    height;
36544   CtxClientFlags flags;
36545 #if 0
36546   int    shaded;
36547   int    iconified;
36548   int    maximized;
36549   int    resizable;
36550 #endif
36551   int    unmaximized_x;
36552   int    unmaximized_y;
36553   int    unmaximized_width;
36554   int    unmaximized_height;
36555   int    do_quit;
36556   long   drawn_rev;
36557   int    id;
36558   int    internal; // render a settings window rather than a vt
36559   void  *user_data;
36560   CtxClientFinalize finalize;
36561 #if CTX_THREADS
36562   mtx_t  mtx;
36563 #endif
36564 #if VT_RECORD
36565   Ctx   *recording;
36566 #endif
36567 };
36568 
36569 
36570 
36571 extern CtxList *clients;
36572 extern CtxClient *active;
36573 extern CtxClient *active_tab;
36574 
36575 
36576 int ctx_client_resize (int id, int width, int height);
36577 void ctx_client_set_font_size (int id, float font_size);
36578 float ctx_client_get_font_size (int id);
36579 void ctx_client_maximize (int id);
36580 
36581 
36582 CtxClient *vt_get_client (VT *vt);
36583 CtxClient *ctx_client_new (Ctx *ctx,
36584                            const char *commandline,
36585                            int x, int y, int width, int height,
36586                            float font_size,
36587                            CtxClientFlags flags,
36588                            void *user_data,
36589                            CtxClientFinalize client_finalize);
36590 CtxClient *ctx_client_new_argv (Ctx *ctx, const char **argv, int x, int y, int width, int height, float font_size, CtxClientFlags flags, void *user_data,
36591                 CtxClientFinalize client_finalize);
36592 int ctx_clients_need_redraw (Ctx *ctx);
36593 
36594 extern float ctx_shape_cache_rate;
36595 extern int _ctx_max_threads;
36596 
36597 void ctx_client_move (int id, int x, int y);
36598 int ctx_client_resize (int id, int w, int h);
36599 void ctx_client_shade_toggle (int id);
36600 float ctx_client_min_y_pos (Ctx *ctx);
36601 float ctx_client_max_y_pos (Ctx *ctx);
36602 
36603 CtxClient *client_by_id (int id);
36604 
36605 int ctx_clients_draw (Ctx *ctx, int layer2);
36606 
36607 void ctx_client_remove (Ctx *ctx, CtxClient *client);
36608 
36609 int ctx_client_height (int id);
36610 
36611 int ctx_client_x (int id);
36612 int ctx_client_y (int id);
36613 void ctx_client_raise_top (int id);
36614 void ctx_client_lower_bottom (int id);
36615 void ctx_client_iconify (int id);
36616 int ctx_client_is_iconified (int id);
36617 void ctx_client_uniconify (int id);
36618 void ctx_client_maximize (int id);
36619 int ctx_client_is_maximized (int id);
36620 void ctx_client_unmaximize (int id);
36621 void ctx_client_maximized_toggle (int id);
36622 void ctx_client_shade (int id);
36623 int ctx_client_is_shaded (int id);
36624 void ctx_client_unshade (int id);
36625 void ctx_client_toggle_maximized (int id);
36626 void ctx_client_shade_toggle (int id);
36627 void ctx_client_move (int id, int x, int y);
36628 int ctx_client_resize (int id, int width, int height);
36629 
36630 
36631 #endif
36632 #ifndef MRG_UTF8_H
36633 #define MRG_UTF8_H
36634 
36635 #if !__COSMOPOLITAN__
36636 #include <string.h>
36637 #include <stdint.h>
36638 #endif
36639 
mrg_utf8_len(const unsigned char first_byte)36640 static inline int mrg_utf8_len (const unsigned char first_byte)
36641 {
36642   if      ((first_byte & 0x80) == 0)
36643     return 1; /* ASCII */
36644   else if ((first_byte & 0xE0) == 0xC0)
36645     return 2;
36646   else if ((first_byte & 0xF0) == 0xE0)
36647     return 3;
36648   else if ((first_byte & 0xF8) == 0xF0)
36649     return 4;
36650   return 1;
36651 }
36652 
mrg_utf8_skip(const char * s,int utf8_length)36653 static inline const char *mrg_utf8_skip (const char *s, int utf8_length)
36654 {
36655    int count;
36656    if (!s)
36657      return NULL;
36658    for (count = 0; *s; s++)
36659    {
36660      if ((*s & 0xC0) != 0x80)
36661        count++;
36662      if (count == utf8_length+1)
36663        return s;
36664    }
36665    return s;
36666 }
36667 
36668 int          mrg_unichar_to_utf8       (unsigned int   ch,
36669                                         unsigned char *dest);
36670 unsigned int mrg_utf8_to_unichar       (unsigned char *utf8);
36671 
36672 //////////////////////////////////////////////////////////////////////////////////
36673 
36674 // Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
36675 // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
36676 
36677 #define UTF8_ACCEPT 0
36678 #define UTF8_REJECT 1
36679 
36680 static const uint8_t utf8d[] = {
36681   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
36682   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
36683   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
36684   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
36685   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
36686   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
36687   8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
36688   0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
36689   0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
36690   0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
36691   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
36692   1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
36693   1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
36694   1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
36695 };
36696 
36697 static inline uint32_t
utf8_decode(uint32_t * state,uint32_t * codep,uint32_t byte)36698 utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
36699   uint32_t type = utf8d[byte];
36700 
36701   *codep = (*state != UTF8_ACCEPT) ?
36702     (byte & 0x3fu) | (*codep << 6) :
36703     (0xff >> type) & (byte);
36704 
36705   *state = utf8d[256 + *state*16 + type];
36706   return *state;
36707 }
36708 
36709 #endif
36710 #if CTX_VT
36711 
36712 /* mrg - MicroRaptor Gui
36713  * Copyright (c) 2014 Øyvind Kolås <pippin@hodefoting.com>
36714  *
36715  * This library is free software; you can redistribute it and/or
36716  * modify it under the terms of the GNU Lesser General Public
36717  * License as published by the Free Software Foundation; either
36718  * version 2 of the License, or (at your option) any later version.
36719  *
36720  * This library is distributed in the hope that it will be useful,
36721  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36722  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36723  * Lesser General Public License for more details.
36724  *
36725  * You should have received a copy of the GNU Lesser General Public
36726  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
36727  */
36728 
36729 #ifndef VT_LINE_H
36730 #define VT_LINE_H
36731 
36732 #include "ctx.h"
36733 
36734 #ifndef CTX_UNLIKELY
36735 #define CTX_UNLIKELY(x)    __builtin_expect(!!(x), 0)
36736 #define CTX_LIKELY(x)      __builtin_expect(!!(x), 1)
36737 #endif
36738 #ifndef CTX_MAX
36739 #define CTX_MAX(a,b) (((a)>(b))?(a):(b))
36740 #endif
36741 
36742 typedef struct _VtLine   VtLine;
36743 
36744 struct _VtLine
36745 {
36746   CtxString string;
36747   /* line extends string, permitting string ops to operate on it  */
36748 
36749   uint64_t *style;
36750   int       style_size;
36751 
36752   void     *ctx; // each line can have an attached ctx context;
36753   char     *prev;
36754   int       prev_length;
36755   CtxString *frame;
36756 
36757   int       wrapped;
36758 
36759   void     *ctx_copy; // each line can have an attached ctx context;
36760   // clearing should be brutal enough to unset the context of the current
36761   // at least in alt-screen mode
36762   int       double_width;
36763   int       double_height_top;
36764   int       double_height_bottom;
36765   int       contains_proportional;
36766   float     xscale;
36767   float     yscale;
36768   float     y_offset;
36769   int       in_scrolling_region;
36770 
36771   /*  XXX:  needs refactoring to a CtxList of links/images */
36772   void     *images[4];
36773   int       image_col[4];
36774   float     image_X[4]; // 0.0 - 1.0 offset in cell
36775   float     image_Y[4];
36776   int       image_rows[4];
36777   int       image_cols[4];
36778   int       image_subx[4];
36779   int       image_suby[4];
36780   int       image_subw[4];
36781   int       image_subh[4];
36782 };
36783 
36784 
vt_line_get_style(VtLine * string,int pos)36785 static inline uint64_t vt_line_get_style (VtLine *string, int pos)
36786 {
36787   if (string->string.is_line==0)
36788     return 0;
36789   if (pos < 0 || pos >= string->style_size)
36790     return 0;
36791   return string->style[pos];
36792 }
36793 
36794 #if !__COSMOPOLITAN__
36795 #include <stdlib.h>
36796 #endif
36797 
vt_line_set_style(VtLine * string,int pos,uint64_t style)36798 static inline void vt_line_set_style (VtLine *string, int pos, uint64_t style)
36799 {
36800   if (string->string.is_line==0)
36801     return;
36802   if (pos < 0 || pos >= 512)
36803     return;
36804   if (pos >= string->style_size)
36805     {
36806       int new_size = pos + 16;
36807       string->style = realloc (string->style, new_size * sizeof (uint64_t) );
36808       memset (&string->style[string->style_size], 0, (new_size - string->style_size) * sizeof (uint64_t) );
36809       string->style_size = new_size;
36810     }
36811   string->style[pos] = style;
36812 }
36813 
36814 VtLine *vt_line_new_with_size (const char *initial, int initial_size);
36815 VtLine *vt_line_new (const char *initial);
36816 
vt_line_free(VtLine * line,int freealloc)36817 static inline void        vt_line_free           (VtLine *line, int freealloc)
36818 {
36819   CtxString *string = (CtxString*)line;
36820 
36821 #if 1
36822   //if (string->is_line)
36823   {
36824     VtLine *line = (VtLine*)string;
36825     if (line->frame)
36826       ctx_string_free (line->frame, 1);
36827     if (line->style)
36828       { free (line->style); }
36829     if (line->ctx)
36830       { ctx_free (line->ctx); }
36831     if (line->ctx_copy)
36832       { ctx_free (line->ctx_copy); }
36833   }
36834 #endif
36835 
36836   ctx_string_free (string, freealloc);
36837 }
vt_line_get(VtLine * line)36838 static inline const char *vt_line_get            (VtLine *line)
36839 {
36840   CtxString *string = (CtxString*)line;
36841   return ctx_string_get (string);
36842 }
vt_line_get_unichar(VtLine * line,int pos)36843 static inline uint32_t    vt_line_get_unichar    (VtLine *line, int pos)
36844 {
36845   CtxString *string = (CtxString*)line;
36846   return ctx_string_get_unichar (string, pos);
36847 }
vt_line_get_length(VtLine * line)36848 static inline int         vt_line_get_length     (VtLine *line)
36849 {
36850   CtxString *string = (CtxString*)line;
36851   return ctx_string_get_length (string);
36852 }
vt_line_get_utf8length(VtLine * line)36853 static inline int         vt_line_get_utf8length     (VtLine *line)
36854 {
36855   CtxString *string = (CtxString*)line;
36856   return ctx_string_get_utf8length (string);
36857 }
vt_line_set(VtLine * line,const char * new_string)36858 static inline void        vt_line_set            (VtLine *line, const char *new_string)
36859 {
36860   CtxString *string = (CtxString*)line;
36861   ctx_string_set (string, new_string);
36862 }
vt_line_clear(VtLine * line)36863 static inline void        vt_line_clear          (VtLine *line)
36864 {
36865   CtxString *string = (CtxString*)line;
36866   ctx_string_clear (string);
36867 }
vt_line_append_str(VtLine * line,const char * str)36868 static inline void        vt_line_append_str     (VtLine *line, const char *str)
36869 {
36870   CtxString *string = (CtxString*)line;
36871   ctx_string_append_str (string, str);
36872 }
36873 
36874 #if 0
36875 static inline void _ctx_string_append_byte (CtxString *string, char  val)
36876 {
36877   if (CTX_LIKELY((val & 0xC0) != 0x80))
36878     { string->utf8_length++; }
36879   if (CTX_UNLIKELY(string->length + 2 >= string->allocated_length))
36880     {
36881       char *old = string->str;
36882       string->allocated_length = CTX_MAX (string->allocated_length * 2, string->length + 2);
36883       string->str = (char*)realloc (old, string->allocated_length);
36884     }
36885   string->str[string->length++] = val;
36886   string->str[string->length] = '\0';
36887 }
36888 #endif
36889 
vt_line_append_byte(VtLine * line,char val)36890 static inline void        vt_line_append_byte    (VtLine *line, char  val)
36891 {
36892   CtxString *string = (CtxString*)line;
36893   _ctx_string_append_byte (string, val);
36894 }
vt_line_append_string(VtLine * line,CtxString * string2)36895 static inline void        vt_line_append_string  (VtLine *line, CtxString *string2)
36896 {
36897   CtxString *string = (CtxString*)line;
36898   ctx_string_append_string (string, string2);
36899 }
vt_line_append_unichar(VtLine * line,unsigned int unichar)36900 static inline void        vt_line_append_unichar (VtLine *line, unsigned int unichar)
36901 {
36902   CtxString *string = (CtxString*)line;
36903   ctx_string_append_unichar (string, unichar);
36904 }
36905 
36906 
vt_line_append_data(VtLine * line,const char * data,int len)36907 static inline void vt_line_append_data    (VtLine *line, const char *data, int len)
36908 {
36909   CtxString *string = (CtxString*)line;
36910   ctx_string_append_data (string, data, len);
36911 }
vt_line_append_utf8char(VtLine * line,const char * str)36912 static inline void vt_line_append_utf8char (VtLine *line, const char *str)
36913 {
36914   CtxString *string = (CtxString*)line;
36915   ctx_string_append_utf8char (string, str);
36916 }
vt_line_replace_utf8(VtLine * line,int pos,const char * new_glyph)36917 static inline void vt_line_replace_utf8   (VtLine *line, int pos, const char *new_glyph)
36918 {
36919   CtxString *string = (CtxString*)line;
36920   ctx_string_replace_utf8 (string, pos, new_glyph);
36921 }
vt_line_insert_utf8(VtLine * line,int pos,const char * new_glyph)36922 static inline void vt_line_insert_utf8    (VtLine *line, int pos, const char *new_glyph)
36923 {
36924   CtxString *string = (CtxString*)line;
36925   ctx_string_insert_utf8 (string, pos, new_glyph);
36926   int len = vt_line_get_length (line);
36927   for (int i = pos; i < len; i++)
36928     vt_line_set_style (line, i, vt_line_get_style (line, i-1));
36929 }
36930 
vt_line_insert_unichar(VtLine * line,int pos,uint32_t new_glyph)36931 static inline void vt_line_insert_unichar (VtLine *line, int pos, uint32_t new_glyph)
36932 {
36933   CtxString *string = (CtxString*)line;
36934   ctx_string_insert_unichar (string, pos, new_glyph);
36935   int len = vt_line_get_length (line);
36936   for (int i = 1; i < len; i++)
36937     vt_line_set_style (line, i, vt_line_get_style (line, i-1));
36938 }
vt_line_replace_unichar(VtLine * line,int pos,uint32_t unichar)36939 static inline void vt_line_replace_unichar (VtLine *line, int pos, uint32_t unichar)
36940 {
36941   CtxString *string = (CtxString*)line;
36942   ctx_string_replace_unichar (string, pos, unichar);
36943 }
36944 
vt_line_remove(VtLine * line,int pos)36945 static inline void vt_line_remove (VtLine *line, int pos)
36946 {
36947   CtxString *string = (CtxString*)line;
36948   ctx_string_remove (string, pos);
36949 
36950   for (int i = pos; i < line->style_size-1; i++)
36951   {
36952     line->style[i] = line->style[i+1];
36953   }
36954 }
36955 
36956 
36957 #ifndef TRUE
36958 #define TRUE 1
36959 #endif
36960 #ifndef FALSE
36961 #define FALSE 0
36962 #endif
36963 
36964 #endif
36965 /* mrg - MicroRaptor Gui
36966  * Copyright (c) 2014 Øyvind Kolås <pippin@hodefoting.com>
36967  *
36968  * This library is free software; you can redistribute it and/or
36969  * modify it under the terms of the GNU Lesser General Public
36970  * License as published by the Free Software Foundation; either
36971  * version 2 of the License, or (at your option) any later version.
36972  *
36973  * This library is distributed in the hope that it will be useful,
36974  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36975  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36976  * Lesser General Public License for more details.
36977  *
36978  * You should have received a copy of the GNU Lesser General Public
36979  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
36980  */
36981 
36982 
36983 #ifndef _DEFAULT_SOURCE
36984 #define _DEFAULT_SOURCE
36985 #endif
36986 
36987 #if !__COSMOPOLITAN__
36988 #include <stdarg.h>
36989 #include <stdio.h>
36990 #include <stdlib.h>
36991 #include <string.h>
36992 #endif
36993 
36994 int ctx_unichar_to_utf8 (uint32_t  ch, uint8_t  *dest);
36995 #define mrg_unichar_to_utf8 ctx_unichar_to_utf8
36996 void ctx_string_init (CtxString *string, int initial_size);
36997 
vt_line_new_with_size(const char * initial,int initial_size)36998 VtLine *vt_line_new_with_size (const char *initial, int initial_size)
36999 {
37000   VtLine *line = calloc (sizeof (VtLine), 1);
37001   CtxString *string = (CtxString*)line;
37002   ctx_string_init (string, initial_size);
37003   if (initial)
37004     { ctx_string_append_str (string, initial); }
37005   line->style = calloc (sizeof (uint64_t), initial_size);
37006   line->style_size = initial_size;
37007   string->is_line = 1;
37008   return line;
37009 }
37010 
vt_line_new(const char * initial)37011 VtLine *vt_line_new (const char *initial)
37012 {
37013   return vt_line_new_with_size (initial, 8);
37014 }
37015 
37016 typedef struct VtPty
37017 {
37018   int        pty;
37019   pid_t      pid;
37020   int        done;
37021 } VtPty;
37022 ssize_t vtpty_read     (void *vtpty, void *buf, size_t count);
37023 ssize_t vtpty_write    (void *vtpty, const void *buf, size_t count);
37024 void    vtpty_resize   (void *vtpty, int cols, int rows,
37025                         int px_width, int px_height);
37026 int     vtpty_waitdata (void  *vtpty, int timeout);
37027 extern  CtxList *vts;
37028 #define MAX_COLS 2048 // used for tabstops
37029 
37030 
37031 typedef struct AudioState
37032 {
37033   int action;
37034   int samplerate; // 8000
37035   int channels;   // 1
37036   int bits;       // 8
37037   int type;       // 'u'    u-law  f-loat  s-igned u-nsigned
37038   int buffer_size; // desired size of audiofragment in frames
37039   // (both for feeding SDL and as desired chunking
37040   //  size)
37041 
37042 
37043   int mic;        // <- should
37044   //    request permisson,
37045   //    and if gotten, start streaming
37046   //    audio packets in the incoming direction
37047   //
37048   int encoding;   // 'a' ascci85 'b' base64
37049   int compression; // '0': none , 'z': zlib   'o': opus(reserved)
37050 
37051   int frames;
37052 
37053   uint8_t *data;
37054   int      data_size;
37055 } AudioState;
37056 
37057 typedef struct GfxState
37058 {
37059   int action;
37060   int id;
37061   int buf_width;
37062   int buf_height;
37063   int format;
37064   int compression;
37065   int transmission;
37066   int multichunk;
37067   int buf_size;
37068   int x;
37069   int y;
37070   int w;
37071   int h;
37072   int x_cell_offset;
37073   int y_cell_offset;
37074   int columns;
37075   int rows;
37076   int z_index;
37077   int delete;
37078 
37079   uint8_t *data;
37080   int   data_size;
37081 } GfxState;
37082 
37083 struct _VT
37084 {
37085   VtPty      vtpty;
37086   int       id;
37087   unsigned char buf[BUFSIZ]; // need one per vt
37088   int keyrepeat;
37089   int       lastx;
37090   int       lasty;
37091   int        result;
37092   long       rev;
37093   //SDL_Rect   dirty;
37094   float  dirtpad;
37095   float  dirtpad1;
37096   float  dirtpad2;
37097   float  dirtpad3;
37098 
37099   void  *client;
37100 
37101   ssize_t (*write)   (void *serial_obj, const void *buf, size_t count);
37102   ssize_t (*read)    (void *serial_obj, void *buf, size_t count);
37103   int     (*waitdata)(void *serial_obj, int timeout);
37104   void    (*resize)  (void *serial_obj, int cols, int rows, int px_width, int px_height);
37105 
37106 
37107   char     *title;
37108   void    (*state) (VT *vt, int byte);
37109 
37110   AudioState audio; // < want to move this one level up and share impl
37111   GfxState   gfx;
37112 
37113   CtxList   *saved_lines;
37114   int       in_alt_screen;
37115   int       had_alt_screen;
37116   int       saved_line_count;
37117   CtxList   *lines;
37118   int       line_count;
37119   CtxList   *scrollback;
37120   int       scrollback_count;
37121   int       leds[4];
37122   uint64_t  cstyle;
37123 
37124   uint8_t   fg_color[3];
37125   uint8_t   bg_color[3];
37126 
37127   int       in_smooth_scroll;
37128   int       smooth_scroll;
37129   float     scroll_offset;
37130   int       debug;
37131   int       bell;
37132   int       origin;
37133   int       at_line_home;
37134   int       charset[4];
37135   int       saved_charset[4];
37136   int       shifted_in;
37137   int       reverse_video;
37138   int       echo;
37139   int       bracket_paste;
37140   int       ctx_events;
37141   int       font_is_mono;
37142   int       palette_no;
37143   int       has_blink; // if any of the set characters are blinking
37144   // updated on each draw of the screen
37145 
37146   int can_launch;
37147 
37148   int unit_pixels;
37149   int mouse;
37150   int mouse_drag;
37151   int mouse_all;
37152   int mouse_decimal;
37153 
37154 
37155   uint8_t    utf8_holding[64]; /* only 4 needed for utf8 - but it's purpose
37156                                  is also overloaded for ctx journal command
37157                                  buffering , and the bigger sizes for the svg-like
37158                                  ctx parsing mode */
37159   int        utf8_expected_bytes;
37160   int        utf8_pos;
37161 
37162 
37163   int        ref_len;
37164   char       reference[16];
37165   int        in_prev_match;
37166   CtxParser *ctxp;
37167   // text related data
37168   float      letter_spacing;
37169 
37170   float      word_spacing;
37171   float      font_stretch;  // horizontal expansion
37172   float      font_size_adjust;
37173   // font-variant
37174   // font-weight
37175   // text-decoration
37176 
37177   int        encoding;  // 0 = utf8 1=pc vga 2=ascii
37178 
37179   int        local_editing; /* terminal operates without pty  */
37180 
37181   int        insert_mode;
37182   int        autowrap;
37183   int        justify;
37184   float      cursor_x;
37185   int        cursor_y;
37186   int        cols;
37187   int        rows;
37188   VtLine    *current_line;
37189 
37190 
37191   int        cr_on_lf;
37192   int        cursor_visible;
37193   int        saved_x;
37194   int        saved_y;
37195   uint32_t   saved_style;
37196   int        saved_origin;
37197   int        cursor_key_application;
37198   int        margin_top;
37199   int        margin_bottom;
37200   int        margin_left;
37201   int        margin_right;
37202 
37203   int        left_right_margin_mode;
37204 
37205   int        scrollback_limit;
37206   float      scroll;
37207   int        scroll_on_input;
37208   int        scroll_on_output;
37209 
37210   char       *argument_buf;
37211   int        argument_buf_len;
37212   int        argument_buf_cap;
37213   uint8_t    tabs[MAX_COLS];
37214   int        inert;
37215 
37216   int        width;
37217   int        height;
37218 
37219   int        cw; // cell width
37220   int        ch; // cell height
37221   float      font_to_cell_scale;
37222   float      font_size; // when set with set_font_size, cw and ch are recomputed
37223   float      line_spacing; // using line_spacing
37224   float      scale_x;
37225   float      scale_y;
37226 
37227   int        ctx_pos;  // 1 is graphics above text, 0 or -1 is below text
37228   Ctx       *root_ctx; /* only used for knowledge of top-level dimensions */
37229 
37230   int        blink_state;
37231 
37232   FILE      *log;
37233 
37234   int cursor_down;
37235 
37236   int select_begin_col;
37237   int select_begin_row;
37238   int select_start_col;
37239   int select_start_row;
37240   int select_end_col;
37241   int select_end_row;
37242   int select_begin_x;
37243   int select_begin_y;
37244   int select_active;
37245 
37246   int popped;
37247 
37248 
37249   /* used to make runs of background on one line be drawn
37250    * as a single filled rectangle
37251    */
37252   int   bg_active;
37253   float bg_x0;
37254   float bg_y0;
37255   float bg_width;
37256   float bg_height;
37257   uint8_t bg_rgba[4];
37258 };
37259 
37260 
37261 VT *vt_new (const char *command, int width, int height, float font_size, float line_spacing, int id, int can_launch);
37262 
37263 void vt_open_log (VT *vt, const char *path);
37264 
37265 int         ctx_vt_had_alt_screen (VT *vt);
37266 void        vt_set_px_size        (VT *vt, int width, int height);
37267 void        vt_set_term_size      (VT *vt, int cols, int rows);
37268 
37269 int         vt_cw                 (VT *vt);
37270 int         vt_ch                 (VT *vt);
37271 void        vt_set_font_size      (VT *vt, float font_size);
37272 float       vt_get_font_size      (VT *vt);
37273 void        vt_set_line_spacing   (VT *vt, float line_spacing);
37274 
37275 const char *vt_find_shell_command (void);
37276 
37277 int         vt_keyrepeat          (VT *vt);
37278 
37279 int         vt_get_result         (VT *vt);
37280 int         vt_is_done            (VT *vt);
37281 int         vt_poll               (VT *vt, int timeout);
37282 long        vt_rev                (VT *vt);
37283 void        vt_destroy            (VT *vt);
37284 int         vt_has_blink (VT *vt);
37285 
37286 /* this is how mrg/mmm based key-events are fed into the vt engine
37287  */
37288 void        vt_feed_keystring     (VT *vt, CtxEvent *event, const char *str);
37289 
37290 void        vt_paste              (VT *vt, const char *str);
37291 
37292 /* not needed when passing a commandline for command to
37293  * run, but could be used for injecting commands, or
37294  * output from stored shell commands/sessions to display
37295  */
37296 //void        vt_feed_byte          (VT *vt, int byte);
37297 
37298 //)#define DEFAULT_SCROLLBACK   (1<<16)
37299 #define DEFAULT_SCROLLBACK   (1<<13)
37300 #define DEFAULT_ROWS         24
37301 #define DEFAULT_COLS         80
37302 
37303 int         vt_get_line_count       (VT *vt);
37304 
37305 pid_t       vt_get_pid              (VT *vt);
37306 
37307 const char *vt_get_line             (VT *vt, int no);
37308 
37309 void        vt_set_scrollback_lines (VT *vt, int scrollback_lines);
37310 int         vt_get_scrollback_lines (VT *vt);
37311 
37312 void        vt_set_scroll           (VT *vt, int scroll);
37313 int         vt_get_scroll           (VT *vt);
37314 
37315 int         vt_get_cols             (VT *vt);
37316 int         vt_get_rows             (VT *vt);
37317 
37318 char       *vt_get_selection        (VT *vt);
37319 int         vt_get_cursor_x         (VT *vt);
37320 int         vt_get_cursor_y         (VT *vt);
37321 
37322 void        vt_draw                 (VT *vt, Ctx *ctx, double x, double y);
37323 void        vt_register_events      (VT *vt, Ctx *ctx, double x0, double y0);
37324 
37325 void        vt_rev_inc              (VT *vt);
37326 
37327 int         vt_mic (VT *vt);
37328 void        vt_set_ctx (VT *vt, Ctx *ctx);  /* XXX: rename, this sets the parent/global ctx  */
37329 
37330 
37331 int         vt_get_local (VT *vt);           // this is a hack for the settings tab
37332 void        vt_set_local (VT *vt, int local);
37333 
37334 
37335 typedef enum VtMouseEvent
37336 {
37337   VT_MOUSE_MOTION = 0,
37338   VT_MOUSE_PRESS,
37339   VT_MOUSE_DRAG,
37340   VT_MOUSE_RELEASE,
37341 } VtMouseEvent;
37342 
37343 void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, int y, int px_x, int px_y);
37344 
vt_write(VT * vt,const void * buf,size_t count)37345 static ssize_t vt_write (VT *vt, const void *buf, size_t count)
37346 {
37347   if (!vt->write) { return 0; }
37348   return vt->write (&vt->vtpty, buf, count);
37349 }
vt_read(VT * vt,void * buf,size_t count)37350 static ssize_t vt_read (VT *vt, void *buf, size_t count)
37351 {
37352   if (!vt->read) { return 0; }
37353   return vt->read (&vt->vtpty, buf, count);
37354 }
vt_waitdata(VT * vt,int timeout)37355 static int vt_waitdata (VT *vt, int timeout)
37356 {
37357   if (!vt->waitdata) { return 0; }
37358   return vt->waitdata (&vt->vtpty, timeout);
37359 }
vt_resize(VT * vt,int cols,int rows,int px_width,int px_height)37360 static void vt_resize (VT *vt, int cols, int rows, int px_width, int px_height)
37361 {
37362   if (vt && vt->resize)
37363     { vt->resize (&vt->vtpty, cols, rows, px_width, px_height); }
37364 }
37365 
37366 /* atty - audio interface and driver for terminals
37367  * Copyright (C) 2020 Øyvind Kolås <pippin@gimp.org>
37368  *
37369  * This library is free software; you can redistribute it and/or
37370  * modify it under the terms of the GNU Lesser General Public
37371  * License as published by the Free Software Foundation; either
37372  * version 2 of the License, or (at your option) any later version.
37373  *
37374  * This library is distributed in the hope that it will be useful,
37375  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37376  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
37377  * Lesser General Public License for more details.
37378  *
37379  * You should have received a copy of the GNU Lesser General Public
37380  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
37381  */
37382 
37383 
37384 #if CTX_SDL
37385 #include <SDL.h>
37386 #include <zlib.h>
37387 
ydec(const void * srcp,void * dstp,int count)37388 static int ydec (const void *srcp, void *dstp, int count)
37389 {
37390   const char *src = srcp;
37391   char *dst = dstp;
37392   int out_len = 0;
37393   for (int i = 0; i < count; i ++)
37394   {
37395     int o = src[i];
37396     switch (o)
37397     {
37398       case '=':
37399               i++;
37400               o = src[i];
37401               o = (o-42-64) % 256;
37402               break;
37403       case '\n':
37404       case '\033':
37405       case '\r':
37406       case '\0':
37407               break;
37408       default:
37409               o = (o-42) % 256;
37410               break;
37411     }
37412     dst[out_len++] = o;
37413   }
37414   dst[out_len]=0;
37415   return out_len;
37416 }
37417 
37418 #if CTX_SDL
37419 static SDL_AudioDeviceID speaker_device = 0;
37420 #endif
37421 
37422 //#define AUDIO_CHUNK_SIZE 512
37423 
37424 // our pcm queue is currently always 16 bit
37425 // signed stereo
37426 
37427 static int16_t pcm_queue[1<<18];
37428 static int     pcm_write_pos = 0;
37429 static int     pcm_read_pos  = 0;
37430 
terminal_queue_pcm(int16_t sample_left,int16_t sample_right)37431 void terminal_queue_pcm (int16_t sample_left, int16_t sample_right)
37432 {
37433   if (pcm_write_pos >= (1<<18)-1)
37434   {
37435     /*  TODO  :  fix cyclic buffer */
37436     pcm_write_pos = 0;
37437     pcm_read_pos  = 0;
37438   }
37439   pcm_queue[pcm_write_pos++]=sample_left;
37440   pcm_queue[pcm_write_pos++]=sample_right;
37441 }
37442 
37443 float click_volume = 0.05;
37444 
37445 void vt_feed_audio (VT *vt, void *samples, int bytes);
37446 int mic_device = 0;   // when non 0 we have an active mic device
37447 
37448 
37449 /*  https://jonathanhays.me/2018/11/14/mu-law-and-a-law-compression-tutorial/
37450  */
37451 
37452 #if 0
37453 static char MuLawCompressTable[256] =
37454 {
37455    0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
37456    4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
37457    5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
37458    5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
37459    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
37460    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
37461    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
37462    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
37463    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
37464    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
37465    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
37466    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
37467    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
37468    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
37469    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
37470    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
37471 };
37472 
37473 unsigned char LinearToMuLawSample(int16_t sample)
37474 {
37475   const int cBias = 0x84;
37476   const int cClip = 32635;
37477   int sign = (sample >> 8) & 0x80;
37478 
37479   if (sign)
37480     sample = (int16_t)-sample;
37481 
37482   if (sample > cClip)
37483     sample = cClip;
37484 
37485   sample = (int16_t)(sample + cBias);
37486 
37487   int exponent = (int)MuLawCompressTable[(sample>>7) & 0xFF];
37488   int mantissa = (sample >> (exponent+3)) & 0x0F;
37489 
37490   int compressedByte = ~ (sign | (exponent << 4) | mantissa);
37491 
37492   return (unsigned char)compressedByte;
37493 }
37494 #endif
37495 
vt_feed_audio(VT * vt,void * samples,int bytes)37496 void vt_feed_audio (VT *vt, void *samples, int bytes)
37497 {
37498   char buf[256];
37499   AudioState *audio = &vt->audio;
37500   uint8_t *data = samples;
37501   int frames = bytes / (audio->bits/8) / audio->channels;
37502 
37503   if (audio->compression == 'z')
37504   {
37505     uLongf len = compressBound(bytes);
37506     data = malloc (len);
37507     int z_result = compress (data, &len, samples, len);
37508     if (z_result != Z_OK)
37509     {
37510       char buf[256]= "\033_Ao=z;zlib error2\033\\";
37511       vt_write (vt, buf, strlen(buf));
37512       data = samples;
37513     }
37514     else
37515     {
37516       bytes = len;
37517     }
37518   }
37519 
37520   char *encoded = malloc (bytes * 2);
37521   encoded[0]=0;
37522   if (audio->encoding == 'a')
37523   {
37524     ctx_a85enc (data, encoded, bytes);
37525   }
37526   else /* if (audio->encoding == 'b')  */
37527   {
37528     ctx_bin2base64 (data, bytes, encoded);
37529   }
37530 
37531   sprintf (buf, "\033[_Af=%i;", frames);
37532   vt_write (vt, buf, strlen (buf));
37533   vt_write (vt, encoded, strlen(encoded));
37534   free (encoded);
37535 
37536   if (data != samples)
37537     free (data);
37538 
37539   //vt_write (vt, samples, bytes);
37540   buf[0]='\033';
37541   buf[1]='\\';
37542   buf[2]=0;
37543   vt_write (vt, buf, 2);
37544 }
37545 
37546 #define MIC_BUF_LEN 40960
37547 
37548 uint8_t mic_buf[MIC_BUF_LEN];
37549 int     mic_buf_pos = 0;
37550 
mic_callback(void * userdata,uint8_t * stream,int len)37551 static void mic_callback(void*     userdata,
37552                          uint8_t * stream,
37553                          int       len)
37554 {
37555   AudioState *audio = userdata;
37556   int16_t *sstream = (void*)stream;
37557   int frames;
37558   int channels = audio->channels;
37559 
37560   frames = len / 2;
37561 
37562   if (audio->bits == 8)
37563   {
37564     if (audio->type == 'u')
37565     {
37566       for (int i = 0; i < frames; i++)
37567       {
37568         for (int c = 0; c < channels; c++)
37569         {
37570           mic_buf[mic_buf_pos++] = LinearToMuLawSample (sstream[i]);
37571           if (mic_buf_pos >= MIC_BUF_LEN - 4)
37572             mic_buf_pos = 0;
37573         }
37574       }
37575     }
37576     else
37577     {
37578       for (int i = 0; i < frames; i++)
37579       {
37580         for (int c = 0; c <  audio->channels; c++)
37581         {
37582           mic_buf[mic_buf_pos++] = (sstream[i]) / 256;
37583           if (mic_buf_pos >= MIC_BUF_LEN - 4)
37584             mic_buf_pos = 0;
37585         }
37586       }
37587     }
37588   }
37589   else
37590   {
37591     for (int i = 0; i < frames; i++)
37592     {
37593       for (int c = 0; c < audio->channels; c++)
37594       {
37595         *((int16_t*)(&mic_buf[mic_buf_pos])) = (sstream[i]);
37596         mic_buf_pos+=2;
37597         if (mic_buf_pos >= MIC_BUF_LEN - 4)
37598           mic_buf_pos = 0;
37599       }
37600     }
37601   }
37602 }
37603 
ticks(void)37604 static long int ticks (void)
37605 {
37606   struct timeval tp;
37607   gettimeofday(&tp, NULL);
37608   return tp.tv_sec * 1000 + tp.tv_usec / 1000;
37609 }
37610 
37611 static long int silence_start = 0;
37612 
sdl_audio_init()37613 static void sdl_audio_init ()
37614 {
37615   static int done = 0;
37616   if (!done)
37617   {
37618 #if CTX_SDL
37619   if (SDL_Init(SDL_INIT_AUDIO) < 0)
37620   {
37621     fprintf (stderr, "sdl audio init fail\n");
37622   }
37623 #endif
37624   done = 1;
37625   }
37626 }
37627 
vt_audio_task(VT * vt,int click)37628 void vt_audio_task (VT *vt, int click)
37629 {
37630   if (!vt) return;
37631   AudioState *audio = &vt->audio;
37632 #if CTX_SDL
37633 
37634   if (audio->mic)
37635   {
37636     if (mic_device == 0)
37637     {
37638       SDL_AudioSpec spec_want, spec_got;
37639       sdl_audio_init ();
37640 
37641       spec_want.freq     = audio->samplerate;
37642       spec_want.channels = 1;
37643       spec_want.format   = AUDIO_S16;
37644       spec_want.samples  = audio->buffer_size;
37645       spec_want.callback = mic_callback;
37646       spec_want.userdata = audio;
37647       mic_device = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(0, SDL_TRUE), 1, &spec_want, &spec_got, 0);
37648 
37649       SDL_PauseAudioDevice(mic_device, 0);
37650     }
37651 
37652     if (mic_buf_pos)
37653     {
37654       SDL_LockAudioDevice (mic_device);
37655       vt_feed_audio (vt, mic_buf, mic_buf_pos);
37656       mic_buf_pos = 0;
37657       SDL_UnlockAudioDevice (mic_device);
37658     }
37659   }
37660   else
37661   {
37662     if (mic_device)
37663     {
37664       SDL_PauseAudioDevice(mic_device, 1);
37665       SDL_CloseAudioDevice(mic_device);
37666       mic_device = 0;
37667     }
37668   }
37669 
37670   int free_frames = audio->buffer_size - SDL_GetQueuedAudioSize(speaker_device);
37671   int queued = (pcm_write_pos - pcm_read_pos)/2; // 2 for stereo
37672   //if (free_frames > 6) free_frames -= 4;
37673   int frames = queued;
37674 
37675   if (frames > free_frames) frames = free_frames;
37676   if (frames > 0)
37677   {
37678     if (speaker_device == 0)
37679     {
37680       SDL_AudioSpec spec_want, spec_got;
37681       sdl_audio_init ();
37682 
37683        spec_want.freq = audio->samplerate;
37684        if (audio->bits == 8 && audio->type == 'u')
37685        {
37686          spec_want.format = AUDIO_S16;
37687          spec_want.channels = 2;
37688        }
37689        else if (audio->bits == 8 && audio->type == 's')
37690        {
37691          spec_want.format = AUDIO_S8;
37692          spec_want.channels = audio->channels;
37693        }
37694        else if (audio->bits == 16 && audio->type == 's')
37695        {
37696          spec_want.format = AUDIO_S16;
37697          spec_want.channels = audio->channels;
37698        }
37699        else
37700        {
37701          spec_want.format = AUDIO_S16; // XXX  : error
37702          spec_want.channels = audio->channels;
37703        }
37704 
37705        /* In SDL we always set 16bit stereo, but with the
37706         * requested sample rate.
37707         */
37708       spec_want.format = AUDIO_S16;
37709       spec_want.channels = 2;
37710 
37711       spec_want.samples = audio->buffer_size;
37712       spec_want.callback = NULL;
37713 
37714       speaker_device = SDL_OpenAudioDevice (NULL, 0, &spec_want, &spec_got, 0);
37715       if (!speaker_device){
37716         fprintf (stderr, "sdl openaudiodevice fail\n");
37717       }
37718       SDL_PauseAudioDevice (speaker_device, 0);
37719     }
37720 
37721 #if 0
37722     {
37723        int i;
37724        unsigned char *b = (void*)(&pcm_queue[pcm_read_pos]);
37725        for (i = 0; i < frames * 4; i++)
37726        {
37727          if ((b[i] > ' ') && (b[i] <= '~'))
37728            fprintf (stderr, "[%c]", b[i]);
37729          else
37730            fprintf (stderr, "[%i]", b[i]);
37731        }
37732     }
37733 #endif
37734     SDL_QueueAudio (speaker_device, (void*)&pcm_queue[pcm_read_pos], frames * 4);
37735     pcm_read_pos += frames*2;
37736     silence_start = ticks();
37737   }
37738   else
37739   {
37740     if (speaker_device &&  (ticks() - silence_start >  2000))
37741     {
37742       SDL_PauseAudioDevice(speaker_device, 1);
37743       SDL_CloseAudioDevice(speaker_device);
37744       speaker_device = 0;
37745     }
37746   }
37747 #endif
37748 }
37749 
37750 void terminal_queue_pcm (int16_t sample_left, int16_t sample_right);
37751 
37752 static unsigned char vt_bell_audio[] = {
37753 #if 1
37754   0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
37755   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
37756   0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
37757   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
37758   0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
37759   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
37760   0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
37761   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
37762   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
37763 #else
37764   0x7e, 0xfe, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0xff,
37765   0xff, 0xfe, 0xfe, 0x7e, 0xff, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd,
37766   0xfe, 0xfe, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d,
37767   0xfe, 0x7e, 0x7e, 0x7e, 0x7e, 0xfd, 0xfd, 0x7e, 0x7e, 0xfd, 0xfe, 0xfe,
37768   0xfe, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0xfe, 0xfe, 0xff, 0xfe,
37769   0xfe, 0xfe, 0x7d, 0x7c, 0xfb, 0xfa, 0xfc, 0xfd, 0xfc, 0x76, 0x75, 0xfa,
37770   0xfb, 0x7b, 0xfc, 0xef, 0xf6, 0x77, 0x6d, 0x7b, 0xf8, 0x78, 0x78, 0xfa,
37771   0xf7, 0xfd, 0xfd, 0xfc, 0xfc, 0xfa, 0xf5, 0xf7, 0x7d, 0x7b, 0x78, 0x77,
37772   0x7c, 0x6f, 0x7b, 0xf5, 0xfb, 0x7b, 0x7c, 0x78, 0x76, 0xea, 0xf2, 0x6d,
37773   0xfd, 0xed, 0x7a, 0x6d, 0x6e, 0x71, 0xfe, 0x76, 0x6d, 0xfb, 0xef, 0x7e,
37774   0xfa, 0xef, 0xec, 0xed, 0xf8, 0xf0, 0xea, 0xf9, 0x70, 0x7c, 0x7c, 0x6b,
37775   0x6d, 0x75, 0xfb, 0xf1, 0xf9, 0xfe, 0xec, 0xea, 0x7c, 0x75, 0xff, 0xfb,
37776   0x7d, 0x77, 0x7a, 0x71, 0x6e, 0x6c, 0x6e, 0x7b, 0x7e, 0x7a, 0x7c, 0xf4,
37777   0xf9, 0x7b, 0x7b, 0xfa, 0xfe, 0x73, 0x79, 0xfe, 0x7b, 0x76, 0xfe, 0xf3,
37778   0xf9, 0x76, 0x77, 0x7e, 0x7e, 0x7d, 0x7c, 0xf9, 0xee, 0xf2, 0x7d, 0xf8,
37779   0xec, 0xee, 0xf7, 0xfa, 0xf7, 0xf6, 0xfd, 0x77, 0x75, 0x7b, 0xfa, 0xfe,
37780   0x78, 0x79, 0x7c, 0x76, 0x7e, 0xf7, 0xfb, 0xf5, 0xf6, 0x75, 0x6f, 0x74,
37781   0x6e, 0x6e, 0x6d, 0x6c, 0x7a, 0xf9, 0x75, 0x77, 0xf4, 0xf0, 0xf0, 0xf1,
37782   0xef, 0xf3, 0xf6, 0xfd, 0xfc, 0xfb, 0xfd, 0xfc, 0xf6, 0xf8, 0xfb, 0xf9,
37783   0xfa, 0xfd, 0xfb, 0xfc, 0x7a, 0x7c, 0x77, 0x75, 0x78, 0x7a, 0x7a, 0x78,
37784   0x7a, 0xfa, 0xf9, 0x7c, 0xff, 0xfb, 0x7d, 0x77, 0x73, 0x6c, 0x6e, 0x7b,
37785   0xfc, 0xfe, 0x7e, 0xfb, 0xf1, 0xeb, 0xee, 0xf6, 0xf6, 0xef, 0xf7, 0x7c,
37786   0x76, 0x76, 0x7b, 0x7a, 0x7b, 0x73, 0x73, 0x7c, 0x79, 0x70, 0x79, 0xfb,
37787   0xfd, 0xf8, 0xf9, 0xfc, 0xfc, 0xf8, 0xfb, 0xff, 0xfc, 0xf9, 0x75, 0x6f,
37788   0x74, 0xfe, 0xff, 0xfd, 0x7d, 0xf5, 0xef, 0xee, 0xf8, 0xfd, 0xfd, 0xf3,
37789   0xfa, 0xfe, 0xfe, 0x7c, 0x77, 0x7a, 0xfb, 0x79, 0x7e, 0x7b, 0xfd, 0x6d,
37790   0xfc, 0x7a, 0xf0, 0x74, 0xee, 0x79, 0xea, 0x79, 0xf9, 0x6d, 0xf7, 0x71,
37791   0x79, 0x76, 0x7c, 0x77, 0x6f, 0xf3, 0x6c, 0xe8, 0x67, 0xe3, 0x5e, 0xdc,
37792   0x58, 0xd8, 0x4e, 0xce, 0x46, 0xc5, 0x40, 0x67, 0xba, 0x49, 0xac, 0x26,
37793   0xba, 0x3e, 0xc5, 0xc8, 0x2b, 0xa8, 0x32, 0xbd, 0xe4, 0x3e, 0xb7, 0x3b,
37794   0xb7, 0x3a, 0x33, 0xab, 0x3f, 0xc8, 0x46, 0x5f, 0xb7, 0x69, 0xd4, 0x3d,
37795   0xc0, 0x4c, 0xf2, 0xdb, 0x3b, 0xdd, 0x69, 0xc5, 0x5f, 0xd8, 0xd8, 0xda,
37796   0xc6, 0x39, 0xba, 0x3f, 0x35, 0xb3, 0x3e, 0xbb, 0x4a, 0x4a, 0xe7, 0x60,
37797   0xae, 0x2c, 0xcb, 0x53, 0x45, 0xaf, 0x2a, 0xae, 0x3e, 0x4a, 0xae, 0x2a,
37798   0xad, 0x38, 0xcc, 0xbb, 0x36, 0xae, 0x2c, 0xc6, 0xce, 0x38, 0xb1, 0x2f,
37799   0xb9, 0x54, 0x7c, 0xb3, 0x28, 0xae, 0x3d, 0xcf, 0xbb, 0x2e, 0xb4, 0x41,
37800   0xc6, 0x78, 0x39, 0xbc, 0x41, 0xc8, 0x59, 0x5b, 0xc7, 0x43, 0xbc, 0x45,
37801   0xf3, 0xdc, 0x69, 0xd6, 0x48, 0xc9, 0x4e, 0xd9, 0x59, 0x61, 0xde, 0x4b,
37802   0xc9, 0x44, 0xc8, 0xf5, 0x43, 0xc5, 0x37, 0xba, 0x65, 0x4d, 0xc8, 0x31,
37803   0xaf, 0x47, 0xdb, 0xd6, 0x36, 0xad, 0x37, 0xbb, 0x61, 0x3a, 0xae, 0x2d,
37804   0xb4, 0x47, 0x49, 0xb2, 0x30, 0xac, 0x3a, 0xcd, 0xbc, 0x2e, 0xaf, 0x32,
37805   0xbd, 0xd7, 0x34, 0xaf, 0x32, 0xbb, 0x55, 0x4a, 0xb4, 0x30, 0xbb, 0x40,
37806   0xeb, 0xbf, 0x39, 0xba, 0x3a, 0xd6, 0xd3, 0x48, 0xc0, 0x3b, 0xce, 0x5e,
37807   0xe7, 0xd3, 0x46, 0xcb, 0x4c, 0xce, 0x74, 0x7e, 0x7e, 0x55, 0xcf, 0x44,
37808   0xc4, 0x5b, 0x7c, 0xd3, 0x3f, 0xbc, 0x44, 0xcb, 0xfa, 0x46, 0xb9, 0x37,
37809   0xb8, 0x51, 0x54, 0xbe, 0x33, 0xb1, 0x3d, 0xce, 0xc4, 0x34, 0xaf, 0x2f,
37810   0xbd, 0xf8, 0x37, 0xb0, 0x2d, 0xb1, 0x4c, 0x4a, 0xb3, 0x2c, 0xb0, 0x3c,
37811   0xe4, 0xbf, 0x2f, 0xaf, 0x35, 0xc0, 0xdb, 0x39, 0xb3, 0x31, 0xbb, 0x5d,
37812   0x4c, 0xb8, 0x37, 0xb9, 0x48, 0xe8, 0xc7, 0x3d, 0xba, 0x43, 0xce, 0xdd,
37813   0x52, 0xc6, 0x46, 0xce, 0x55, 0xdf, 0xe8, 0x52, 0xd5, 0x48, 0xca, 0x4d,
37814   0xef, 0x68, 0x4c, 0xc7, 0x42, 0xc2, 0x49, 0x78, 0xce, 0x3e, 0xb9, 0x3c,
37815   0xc8, 0xef, 0x43, 0xb7, 0x35, 0xb8, 0x4a, 0x53, 0xb8, 0x32, 0xaf, 0x3b,
37816   0xde, 0xc1, 0x34, 0xaf, 0x32, 0xc3, 0xde, 0x3b, 0xaf, 0x2e, 0xb6, 0x4e,
37817   0x48, 0xb4, 0x2e, 0xb2, 0x3d, 0xf0, 0xbf, 0x33, 0xb2, 0x37, 0xc8, 0xd9,
37818   0x3d, 0xb5, 0x36, 0xbc, 0x56, 0x4f, 0xbc, 0x39, 0xbc, 0x47, 0xf6, 0xcf,
37819   0x44, 0xbf, 0x46, 0xce, 0x68, 0x5b, 0xd0, 0x4a, 0xcc, 0x4d, 0xd3, 0x60,
37820   0x6a, 0xcf, 0x49, 0xc8, 0x45, 0xd0, 0x7b, 0x58, 0xc3, 0x3c, 0xbf, 0x48,
37821   0xe2, 0xc9, 0x3b, 0xb7, 0x39, 0xc5, 0xdb, 0x40, 0xb6, 0x31, 0xb9, 0x50,
37822   0x50, 0xb9, 0x2f, 0xb3, 0x3b, 0xdc, 0xbf, 0x33, 0xaf, 0x32, 0xc1, 0xd6,
37823   0x3b, 0xb0, 0x2f, 0xb8, 0x54, 0x4a, 0xb6, 0x30, 0xb4, 0x3f, 0xfd, 0xc0,
37824   0x36, 0xb5, 0x39, 0xcc, 0xd9, 0x41, 0xb9, 0x39, 0xc2, 0x59, 0x57, 0xc1,
37825   0x3e, 0xc2, 0x49, 0xe2, 0xd7, 0x4c, 0xcb, 0x47, 0xcf, 0x5b, 0xec, 0xe0,
37826   0x53, 0xcb, 0x4b, 0xca, 0x55, 0xf6, 0xdb, 0x48, 0xc0, 0x43, 0xc9, 0x5f,
37827   0x54, 0xc0, 0x3c, 0xbb, 0x43, 0xe8, 0xc8, 0x39, 0xb5, 0x39, 0xc6, 0xde,
37828   0x3d, 0xb4, 0x32, 0xba, 0x4f, 0x4c, 0xb9, 0x30, 0xb2, 0x3c, 0xec, 0xc1,
37829   0x33, 0xaf, 0x35, 0xc4, 0xd7, 0x3a, 0xb2, 0x31, 0xba, 0x56, 0x48, 0xb9,
37830   0x33, 0xb7, 0x44, 0x7e, 0xc3, 0x39, 0xb7, 0x3d, 0xcd, 0xe3, 0x42, 0xbd,
37831   0x3d, 0xc2, 0x58, 0x5d, 0xcb, 0x43, 0xc4, 0x4c, 0xd8, 0xf8, 0x58, 0xcd,
37832   0x4c, 0xcb, 0x4e, 0xda, 0x71, 0x5c, 0xcc, 0x46, 0xc4, 0x49, 0xdc, 0xdc,
37833   0x46, 0xbe, 0x3d, 0xc4, 0x59, 0x53, 0xbe, 0x38, 0xb8, 0x41, 0xe1, 0xc5,
37834   0x39, 0xb3, 0x38, 0xc4, 0xde, 0x3d, 0xb2, 0x32, 0xb9, 0x4e, 0x4b, 0xb7,
37835   0x30, 0xb3, 0x3d, 0xf2, 0xbf, 0x33, 0xb1, 0x36, 0xc9, 0xd9, 0x3a, 0xb4,
37836   0x33, 0xbc, 0x58, 0x49, 0xba, 0x36, 0xb9, 0x46, 0x7e, 0xc8, 0x3c, 0xba,
37837   0x3f, 0xcd, 0xe8, 0x4b, 0xc1, 0x41, 0xc7, 0x57, 0xfe, 0xd3, 0x4e, 0xc9,
37838   0x4d, 0xd0, 0x5e, 0x7c, 0xda, 0x4e, 0xca, 0x47, 0xcd, 0x5b, 0x68, 0xcc,
37839   0x40, 0xbf, 0x42, 0xd2, 0xe4, 0x42, 0xbd, 0x3a, 0xbf, 0x56, 0x50, 0xbd,
37840   0x36, 0xb6, 0x40, 0xe2, 0xc5, 0x36, 0xb2, 0x37, 0xc5, 0xde, 0x3c, 0xb3,
37841   0x32, 0xba, 0x52, 0x4a, 0xb7, 0x31, 0xb4, 0x3f, 0xef, 0xbf, 0x34, 0xb2,
37842   0x39, 0xc8, 0xd3, 0x3c, 0xb6, 0x37, 0xbe, 0x5c, 0x4c, 0xbd, 0x39, 0xbc,
37843   0x49, 0xf2, 0xcc, 0x3f, 0xbf, 0x44, 0xcf, 0xfd, 0x51, 0xca, 0x48, 0xcb,
37844   0x54, 0xe4, 0xeb, 0x57, 0xcf, 0x4d, 0xcc, 0x4f, 0xe0, 0xee, 0x51, 0xc7,
37845   0x44, 0xc6, 0x4f, 0x78, 0xcc, 0x3f, 0xbd, 0x3e, 0xce, 0xe5, 0x42, 0xba,
37846   0x38, 0xbe, 0x50, 0x4f, 0xbb, 0x35, 0xb6, 0x3e, 0xe8, 0xc2, 0x36, 0xb2,
37847   0x37, 0xc6, 0xda, 0x3c, 0xb3, 0x32, 0xba, 0x55, 0x4a, 0xb7, 0x33, 0xb5,
37848   0x41, 0x7e, 0xbf, 0x37, 0xb4, 0x3b, 0xcd, 0xd8, 0x3e, 0xb8, 0x39, 0xc2,
37849   0x5b, 0x4f, 0xc0, 0x3c, 0xbf, 0x4a, 0xee, 0xd1, 0x47, 0xc5, 0x47, 0xd0,
37850   0x68, 0x63, 0xd0, 0x4d, 0xcd, 0x4e, 0xd6, 0x67, 0x68, 0xd6, 0x4b, 0xc9,
37851   0x4a, 0xd1, 0x6e, 0x52, 0xc5, 0x3f, 0xc0, 0x4b, 0xfd, 0xcb, 0x3d, 0xba,
37852   0x3d, 0xcc, 0xe2, 0x41, 0xb8, 0x37, 0xbc, 0x53, 0x4e, 0xba, 0x34, 0xb6,
37853   0x3f, 0xee, 0xc1, 0x36, 0xb2, 0x38, 0xc8, 0xd6, 0x3c, 0xb3, 0x34, 0xbc,
37854   0x58, 0x49, 0xb9, 0x34, 0xb7, 0x44, 0x73, 0xc3, 0x38, 0xb7, 0x3d, 0xce,
37855   0xd9, 0x40, 0xbc, 0x3c, 0xc5, 0x5e, 0x55, 0xc6, 0x40, 0xc3, 0x4d, 0xe5,
37856   0xde, 0x4d, 0xca, 0x4b, 0xce, 0x5c, 0xfa, 0xe1, 0x54, 0xcd, 0x4d, 0xcd,
37857   0x56, 0xf3, 0xd9, 0x4a, 0xc4, 0x44, 0xcb, 0x67, 0x53, 0xc3, 0x3d, 0xbe,
37858   0x48, 0xf0, 0xca, 0x3c, 0xb8, 0x3b, 0xca, 0xdf, 0x3f, 0xb7, 0x36, 0xbc,
37859   0x54, 0x4c, 0xb9, 0x34, 0xb6, 0x40, 0xf7, 0xc1, 0x36, 0xb3, 0x39, 0xca,
37860   0xd6, 0x3c, 0xb4, 0x35, 0xbe, 0x5b, 0x49, 0xba, 0x36, 0xba, 0x47, 0x6f,
37861   0xc5, 0x3b, 0xba, 0x3f, 0xd2, 0xdd, 0x46, 0xbe, 0x3f, 0xc9, 0x5c, 0x5d,
37862   0xcc, 0x47, 0xc8, 0x4e, 0xdd, 0xf5, 0x5a, 0xd1, 0x4e, 0xcf, 0x52, 0xde,
37863   0x7d, 0x5c, 0xcf, 0x49, 0xc9, 0x4d, 0xdd, 0xde, 0x49, 0xc1, 0x3f, 0xc6,
37864   0x5d, 0x53, 0xc0, 0x3b, 0xbc, 0x46, 0xeb, 0xc8, 0x3b, 0xb7, 0x3b, 0xc8,
37865   0xde, 0x3e, 0xb6, 0x35, 0xbb, 0x57, 0x4c, 0xb9, 0x34, 0xb6, 0x42, 0xff,
37866   0xc1, 0x36, 0xb4, 0x3a, 0xcc, 0xd7, 0x3d, 0xb7, 0x37, 0xbf, 0x5e, 0x4a,
37867   0xbc, 0x38, 0xbc, 0x4a, 0x6e, 0xc9, 0x3e, 0xbe, 0x43, 0xd5, 0xe2, 0x4b,
37868   0xc5, 0x45, 0xcb, 0x5e, 0x6e, 0xd6, 0x4e, 0xcd, 0x51, 0xd7, 0x65, 0x74,
37869   0xdc, 0x54, 0xcd, 0x4d, 0xd1, 0x5e, 0x6b, 0xcf, 0x46, 0xc4, 0x47, 0xd7,
37870   0xe3, 0x48, 0xbe, 0x3d, 0xc3, 0x58, 0x54, 0xbe, 0x39, 0xba, 0x43, 0xee,
37871   0xc7, 0x3a, 0xb6, 0x3a, 0xc9, 0xdc, 0x3e, 0xb5, 0x35, 0xbd, 0x57, 0x4b,
37872   0xb9, 0x34, 0xb7, 0x43, 0x6f, 0xc1, 0x38, 0xb6, 0x3c, 0xcf, 0xd3, 0x3e,
37873   0xb8, 0x3a, 0xc3, 0x64, 0x4c, 0xbe, 0x3c, 0xbf, 0x4d, 0x72, 0xcc, 0x42,
37874   0xc1, 0x48, 0xd9, 0xed, 0x51, 0xcc, 0x4b, 0xcf, 0x5a, 0xef, 0xe8, 0x59,
37875   0xd3, 0x50, 0xd1, 0x58, 0xe1, 0xec, 0x56, 0xcc, 0x49, 0xca, 0x55, 0x7c,
37876   0xcf, 0x44, 0xbf, 0x43, 0xcf, 0xe5, 0x47, 0xbc, 0x3b, 0xbf, 0x56, 0x52,
37877   0xbe, 0x38, 0xb9, 0x42, 0xee, 0xc6, 0x39, 0xb6, 0x3a, 0xca, 0xdc, 0x3d,
37878   0xb6, 0x36, 0xbd, 0x59, 0x4a, 0xba, 0x35, 0xb9, 0x45, 0x6b, 0xc2, 0x39,
37879   0xb8, 0x3d, 0xd2, 0xd5, 0x3f, 0xbb, 0x3c, 0xc6, 0x69, 0x4f, 0xc1, 0x3f,
37880   0xc3, 0x50, 0x7d, 0xd0, 0x49, 0xc8, 0x4c, 0xd8, 0x7d, 0x5d, 0xd4, 0x4f,
37881   0xd2, 0x57, 0xde, 0x6e, 0x69, 0xda, 0x50, 0xcd, 0x4e, 0xd6, 0x71, 0x59,
37882   0xca, 0x44, 0xc5, 0x4d, 0xf3, 0xce, 0x41, 0xbd, 0x3f, 0xcd, 0xe5, 0x45,
37883   0xbb, 0x3a, 0xbf, 0x55, 0x51, 0xbd, 0x37, 0xb9, 0x43, 0xf1, 0xc5, 0x39,
37884   0xb6, 0x3b, 0xcc, 0xd9, 0x3d, 0xb7, 0x37, 0xbf, 0x5d, 0x49, 0xbb, 0x37,
37885   0xba, 0x48, 0x69, 0xc4, 0x3b, 0xba, 0x40, 0xd5, 0xd7, 0x42, 0xbd, 0x3f,
37886   0xc9, 0x69, 0x52, 0xc7, 0x44, 0xc7, 0x52, 0xfa, 0xda, 0x4f, 0xcd, 0x4f,
37887   0xd8, 0x66, 0x72, 0xdf, 0x59, 0xd4, 0x52, 0xd6, 0x5d, 0xef, 0xde, 0x4f,
37888   0xca, 0x49, 0xce, 0x64, 0x5a, 0xc8, 0x40, 0xc1, 0x4a, 0xec, 0xcd, 0x3f,
37889   0xbc, 0x3e, 0xcc, 0xe5, 0x43, 0xba, 0x39, 0xbe, 0x55, 0x4f, 0xbc, 0x37,
37890   0xb9, 0x43, 0xf8, 0xc4, 0x39, 0xb6, 0x3b, 0xcd, 0xd7, 0x3e, 0xb7, 0x38,
37891   0xc0, 0x60, 0x4b, 0xbc, 0x39, 0xbc, 0x4b, 0x6b, 0xc6, 0x3d, 0xbd, 0x43,
37892   0xd9, 0xda, 0x47, 0xc1, 0x42, 0xcd, 0x66, 0x5a, 0xcd, 0x48, 0xcc, 0x54,
37893   0xe9, 0xe9, 0x59, 0xd5, 0x54, 0xd5, 0x5c, 0xe4, 0xfb, 0x61, 0xd4, 0x4f,
37894   0xcd, 0x51, 0xdf, 0xe3, 0x4e, 0xc5, 0x45, 0xca, 0x5e, 0x5b, 0xc6, 0x3e,
37895   0xbf, 0x48, 0xea, 0xcc, 0x3e, 0xbb, 0x3d, 0xcb, 0xe4, 0x42, 0xba, 0x38,
37896   0xbe, 0x56, 0x4e, 0xbc, 0x37, 0xb9, 0x44, 0x7b, 0xc4, 0x39, 0xb7, 0x3c,
37897   0xcf, 0xd7, 0x3e, 0xb9, 0x3a, 0xc2, 0x62, 0x4c, 0xbd, 0x3b, 0xbe, 0x4d,
37898   0x6b, 0xc9, 0x3f, 0xbf, 0x46, 0xd9, 0xde, 0x4b, 0xc5, 0x47, 0xce, 0x63,
37899   0x65, 0xd3, 0x4e, 0xcf, 0x55, 0xdf, 0x74, 0x67, 0xdc, 0x55, 0xd3, 0x54,
37900   0xda, 0x68, 0x67, 0xd5, 0x4c, 0xca, 0x4d, 0xdc, 0xe7, 0x4d, 0xc4, 0x42,
37901   0xc8, 0x5b, 0x59, 0xc4, 0x3d, 0xbe, 0x47, 0xec, 0xcc, 0x3d, 0xba, 0x3d,
37902   0xcc, 0xe1, 0x42, 0xba, 0x39, 0xbf, 0x5a, 0x4f, 0xbc, 0x38, 0xba, 0x46,
37903   0x7d, 0xc5, 0x3b, 0xb9, 0x3e, 0xd0, 0xd8, 0x40, 0xbb, 0x3c, 0xc5, 0x63,
37904   0x4d, 0xc0, 0x3d, 0xc1, 0x4e, 0x6e, 0xcd, 0x44, 0xc4, 0x49, 0xdb, 0xec,
37905   0x50, 0xcc, 0x4a, 0xd1, 0x5c, 0x7b, 0xde, 0x56, 0xd2, 0x54, 0xd8, 0x62,
37906   0xf2, 0xe2, 0x58, 0xcf, 0x4e, 0xd0, 0x5d, 0x72, 0xd3, 0x4a, 0xc5, 0x49,
37907   0xd6, 0xe8, 0x4b, 0xc0, 0x3f, 0xc5, 0x5b, 0x58, 0xc2, 0x3c, 0xbd, 0x47,
37908   0xee, 0xca, 0x3d, 0xba, 0x3d, 0xcd, 0xdf, 0x41, 0xba, 0x3a, 0xc0, 0x5b,
37909   0x4d, 0xbd, 0x39, 0xbc, 0x48, 0x73, 0xc6, 0x3c, 0xbb, 0x3f, 0xd4, 0xd9,
37910   0x43, 0xbd, 0x3e, 0xc8, 0x67, 0x50, 0xc4, 0x40, 0xc4, 0x51, 0x7b, 0xd1,
37911   0x4a, 0xc8, 0x4d, 0xd9, 0xf6, 0x5c, 0xd0, 0x51, 0xd2, 0x5c, 0xe8, 0xf2,
37912   0x62, 0xd8, 0x55, 0xd4, 0x56, 0xe1, 0x7c, 0x59, 0xcf, 0x49, 0xcc, 0x53,
37913   0x7a, 0xd4, 0x46, 0xc4, 0x45, 0xd5, 0xef, 0x49, 0xc0, 0x3d, 0xc5, 0x57,
37914   0x55, 0xc2, 0x3b, 0xbd, 0x47, 0xed, 0xc9, 0x3d, 0xb9, 0x3e, 0xcc, 0xdb,
37915   0x43, 0xb9, 0x3b, 0xc0, 0x61, 0x4f, 0xbd, 0x3b, 0xbc, 0x4b, 0x75, 0xc6,
37916   0x3d, 0xbc, 0x43, 0xd7, 0xd9, 0x45, 0xbf, 0x40, 0xcc, 0x68, 0x54, 0xc9,
37917   0x44, 0xca, 0x53, 0x7d, 0xda, 0x4d, 0xce, 0x4f, 0xdb, 0x6d, 0x68, 0xdd,
37918   0x55, 0xd6, 0x56, 0xdc, 0x67, 0x71, 0xde, 0x53, 0xce, 0x4f, 0xd6, 0x6e,
37919   0x5c, 0xcc, 0x47, 0xc7, 0x4f, 0xef, 0xd0, 0x45, 0xbf, 0x44, 0xcf, 0xe6,
37920   0x48, 0xbe, 0x3d, 0xc3, 0x5a, 0x54, 0xc0, 0x3b, 0xbc, 0x47, 0xfa, 0xc9,
37921   0x3c, 0xba, 0x3e, 0xd0, 0xdc, 0x41, 0xbb, 0x3b, 0xc4, 0x5f, 0x4d, 0xbf,
37922   0x3c, 0xbf, 0x4c, 0x6d, 0xc9, 0x3f, 0xbe, 0x46, 0xda, 0xdc, 0x49, 0xc3,
37923   0x45, 0xce, 0x6b, 0x5b, 0xcd, 0x4a, 0xcd, 0x57, 0xee, 0xe4, 0x58, 0xd4,
37924   0x54, 0xd9, 0x60, 0xf1, 0xed, 0x5f, 0xd7, 0x53, 0xd3, 0x5a, 0xeb, 0xe1,
37925   0x52, 0xca, 0x4b, 0xce, 0x68, 0x5c, 0xc9, 0x44, 0xc4, 0x4e, 0xec, 0xce,
37926   0x43, 0xbe, 0x42, 0xcf, 0xe4, 0x47, 0xbd, 0x3c, 0xc3, 0x5b, 0x50, 0xbf,
37927   0x3b, 0xbd, 0x48, 0x73, 0xc8, 0x3c, 0xbb, 0x3f, 0xd4, 0xda, 0x41, 0xbc,
37928   0x3d, 0xc7, 0x67, 0x4d, 0xc0, 0x3d, 0xc2, 0x4f, 0x68, 0xcb, 0x42, 0xc2,
37929   0x4a, 0xdd, 0xdd, 0x4d, 0xc7, 0x4a, 0xd1, 0x6d, 0x65, 0xd3, 0x52, 0xd1,
37930   0x5b, 0xe3, 0xf8, 0x68, 0xdd, 0x5a, 0xd8, 0x59, 0xde, 0x6d, 0x68, 0xd9,
37931   0x4e, 0xce, 0x4f, 0xe1, 0xeb, 0x4e, 0xc9, 0x45, 0xcd, 0x5d, 0x58, 0xc9,
37932   0x3f, 0xc2, 0x4b, 0xf6, 0xce, 0x3f, 0xbd, 0x40, 0xcf, 0xe0, 0x45, 0xbc,
37933   0x3d, 0xc3, 0x5e, 0x51, 0xbf, 0x3c, 0xbd, 0x4b, 0x7b, 0xc7, 0x3e, 0xbb,
37934   0x42, 0xd4, 0xd6, 0x45, 0xbd, 0x3f, 0xc9, 0x6f, 0x50, 0xc3, 0x40, 0xc5,
37935   0x53, 0x6c, 0xce, 0x46, 0xc7, 0x4c, 0xe0, 0xeb, 0x51, 0xce, 0x4d, 0xd7,
37936   0x5f, 0x6c, 0xe3, 0x57, 0xd9, 0x57, 0xde, 0x64, 0xfd, 0xe9, 0x5b, 0xd5,
37937   0x52, 0xd5, 0x61, 0x78, 0xd6, 0x4d, 0xc9, 0x4e, 0xd8, 0xe5, 0x4e, 0xc4,
37938   0x44, 0xc9, 0x5f, 0x5a, 0xc6, 0x3f, 0xc0, 0x4b, 0xf5, 0xcd, 0x3f, 0xbd,
37939   0x40, 0xd2, 0xdf, 0x43, 0xbd, 0x3c, 0xc6, 0x5e, 0x4e, 0xbf, 0x3b, 0xbf,
37940   0x4c, 0x6b, 0xc9, 0x3e, 0xbd, 0x44, 0xda, 0xd8, 0x45, 0xbf, 0x42, 0xcc,
37941   0x75, 0x52, 0xc6, 0x45, 0xc8, 0x58, 0x76, 0xd2, 0x4c, 0xca, 0x51, 0xdd,
37942   0xed, 0x5d, 0xd3, 0x55, 0xd7, 0x61, 0xec, 0xef, 0x65, 0xdc, 0x58, 0xd7,
37943   0x5a, 0xe4, 0xfd, 0x5c, 0xd2, 0x4c, 0xcf, 0x57, 0x77, 0xd8, 0x49, 0xc7,
37944   0x48, 0xd8, 0xeb, 0x4b, 0xc3, 0x40, 0xc8, 0x5d, 0x57, 0xc4, 0x3e, 0xbf,
37945   0x4b, 0xf8, 0xca, 0x3f, 0xbc, 0x42, 0xd1, 0xd9, 0x45, 0xbc, 0x3e, 0xc6,
37946   0x6a, 0x4f, 0xbf, 0x3d, 0xc0, 0x4f, 0x67, 0xc9, 0x3f, 0xbf, 0x47, 0xdf,
37947   0xdb, 0x47, 0xc4, 0x44, 0xd1, 0x6c, 0x53, 0xcc, 0x48, 0xce, 0x58, 0x74,
37948   0xdc, 0x50, 0xd1, 0x54, 0xdf, 0x74, 0x6a, 0xde, 0x5b, 0xd9, 0x5d, 0xdd,
37949   0x6e, 0xfc, 0xdd, 0x5a, 0xcf, 0x54, 0xd6, 0x7b, 0x60, 0xcd, 0x4b, 0xc9,
37950   0x55, 0xf2, 0xd2, 0x48, 0xc3, 0x47, 0xd5, 0xe6, 0x4a, 0xc1, 0x3f, 0xc8,
37951   0x5d, 0x52, 0xc4, 0x3d, 0xc0, 0x4b, 0x71, 0xcb, 0x3e, 0xbd, 0x41, 0xd7,
37952   0xdc, 0x43, 0xbe, 0x3e, 0xc9, 0x6a, 0x4e, 0xc1, 0x3e, 0xc3, 0x52, 0x6a,
37953   0xca, 0x43, 0xc1, 0x4b, 0xdd, 0xda, 0x4c, 0xc6, 0x4a, 0xd1, 0x77, 0x5d,
37954   0xce, 0x4e, 0xcf, 0x5c, 0xf3, 0xe5, 0x5a, 0xd8, 0x58, 0xdd, 0x62, 0xfb,
37955   0xf4, 0x5e, 0xdc, 0x54, 0xd9, 0x5a, 0xf6, 0xea, 0x52, 0xce, 0x4c, 0xd4,
37956   0x67, 0x5c, 0xcc, 0x46, 0xc8, 0x50, 0xf8, 0xd0, 0x45, 0xc0, 0x46, 0xd3,
37957   0xe1, 0x49, 0xbf, 0x3f, 0xc6, 0x63, 0x54, 0xc1, 0x3e, 0xbf, 0x4d, 0x76,
37958   0xc9, 0x3f, 0xbd, 0x44, 0xd8, 0xda, 0x44, 0xbe, 0x3f, 0xcb, 0x6b, 0x4e,
37959   0xc4, 0x3f, 0xc7, 0x53, 0x66, 0xcd, 0x45, 0xc6, 0x4d, 0xe3, 0xdf, 0x4e,
37960   0xcb, 0x4d, 0xd5, 0x6f, 0x65, 0xd6, 0x55, 0xd4, 0x5e, 0xe5, 0xf1, 0x6b,
37961   0xdc, 0x5d, 0xd8, 0x5e, 0xdf, 0x79, 0x6d, 0xd9, 0x53, 0xcf, 0x56, 0xe3,
37962   0xe8, 0x52, 0xcb, 0x49, 0xcf, 0x61, 0x5a, 0xcb, 0x43, 0xc6, 0x4d, 0x7c,
37963   0xd1, 0x42, 0xc0, 0x43, 0xd6, 0xe3, 0x47, 0xbf, 0x3e, 0xc8, 0x63, 0x51,
37964   0xc1, 0x3e, 0xc0, 0x4e, 0x6f, 0xc9, 0x3f, 0xbe, 0x47, 0xd9, 0xd7, 0x47,
37965   0xbf, 0x43, 0xcc, 0x79, 0x51, 0xc6, 0x44, 0xc9, 0x58, 0x6a, 0xd0, 0x49,
37966   0xca, 0x4f, 0xe6, 0xea, 0x54, 0xd1, 0x50, 0xdb, 0x65, 0x6e, 0xe4, 0x5a,
37967   0xdc, 0x5a, 0xe1, 0x67, 0xfe, 0xea, 0x5d, 0xd7, 0x55, 0xd8, 0x63, 0x74,
37968   0xd8, 0x4f, 0xcb, 0x4f, 0xdc, 0xe5, 0x50, 0xc7, 0x47, 0xcc, 0x65, 0x5b,
37969   0xc8, 0x43, 0xc4, 0x4e, 0xfa, 0xcd, 0x42, 0xbf, 0x44, 0xd6, 0xdf, 0x46,
37970   0xbf, 0x3f, 0xc9, 0x64, 0x4f, 0xc3, 0x3e, 0xc3, 0x4f, 0x68, 0xcb, 0x40,
37971   0xc0, 0x48, 0xde, 0xd9, 0x48, 0xc2, 0x45, 0xcf, 0x7b, 0x55, 0xc9, 0x48,
37972   0xcb, 0x5c, 0x75, 0xd3, 0x4f, 0xcd, 0x56, 0xe0, 0xed, 0x5e, 0xd7, 0x58,
37973   0xdb, 0x63, 0xef, 0xf5, 0x65, 0xdf, 0x5a, 0xdb, 0x5b, 0xea, 0x7d, 0x5d,
37974   0xd6, 0x4e, 0xd3, 0x59, 0x73, 0xd9, 0x4b, 0xca, 0x4b, 0xdc, 0xeb, 0x4d,
37975   0xc6, 0x44, 0xcb, 0x61, 0x59, 0xc7, 0x41, 0xc2, 0x4e, 0xfb, 0xcc, 0x42,
37976   0xbe, 0x46, 0xd5, 0xdb, 0x47, 0xbe, 0x40, 0xc9, 0x6e, 0x50, 0xc2, 0x3f,
37977   0xc4, 0x52, 0x69, 0xcb, 0x42, 0xc3, 0x4a, 0xe2, 0xdc, 0x49, 0xc6, 0x48,
37978   0xd4, 0x71, 0x56, 0xcd, 0x4a, 0xcf, 0x5b, 0x73, 0xdd, 0x53, 0xd3, 0x57,
37979   0xe2, 0x78, 0x6a, 0xdf, 0x5d, 0xdb, 0x5e, 0xe1, 0x6f, 0x7a, 0xe0, 0x5b,
37980   0xd4, 0x57, 0xdb, 0x79, 0x5f, 0xd0, 0x4d, 0xcd, 0x58, 0xfd, 0xd6, 0x4a,
37981   0xc7, 0x4a, 0xd9, 0xe8, 0x4c, 0xc5, 0x42, 0xcb, 0x5f, 0x55, 0xc7, 0x3f,
37982   0xc4, 0x4e, 0x71, 0xcd, 0x41, 0xbf, 0x46, 0xd9, 0xdb, 0x47, 0xbf, 0x41,
37983   0xcb, 0x70, 0x51, 0xc4, 0x42, 0xc5, 0x57, 0x6b, 0xcc, 0x46, 0xc4, 0x4d,
37984   0xe0, 0xdb, 0x4d, 0xc8, 0x4c, 0xd5, 0x78, 0x5d, 0xd1, 0x4f, 0xd3, 0x5d,
37985   0xfb, 0xe6, 0x5a, 0xda, 0x59, 0xe1, 0x67, 0x7c, 0xf1, 0x5f, 0xde, 0x58,
37986   0xdc, 0x5e, 0xf9, 0xe8, 0x56, 0xd1, 0x4f, 0xd7, 0x6d, 0x5e, 0xce, 0x4a,
37987   0xcb, 0x55, 0xf7, 0xd3, 0x49, 0xc4, 0x4a, 0xd7, 0xe3, 0x4c, 0xc2, 0x43,
37988   0xca, 0x66, 0x56, 0xc5, 0x40, 0xc3, 0x4f, 0x74, 0xcc, 0x42, 0xc0, 0x47,
37989   0xdb, 0xdc, 0x47, 0xc1, 0x42, 0xce, 0x6e, 0x50, 0xc7, 0x43, 0xc9, 0x57,
37990   0x67, 0xcf, 0x48, 0xc9, 0x4e, 0xe6, 0xe0, 0x50, 0xcd, 0x4e, 0xd8, 0x6f,
37991   0x65, 0xd7, 0x55, 0xd7, 0x5f, 0xeb, 0xf3, 0x68, 0xde, 0x5e, 0xdc, 0x60,
37992   0xe5, 0x7b, 0x6b, 0xdc, 0x56, 0xd4, 0x59, 0xe8, 0xe8, 0x55, 0xcd, 0x4c,
37993   0xd3, 0x68, 0x5c, 0xcd, 0x47, 0xc9, 0x52, 0xfe, 0xd2, 0x47, 0xc4, 0x48,
37994   0xd8, 0xe2, 0x4a, 0xc2, 0x42, 0xcb, 0x68, 0x54, 0xc5, 0x40, 0xc4, 0x51,
37995   0x6e, 0xcc, 0x42, 0xc1, 0x49, 0xdd, 0xda, 0x49, 0xc3, 0x46, 0xcf, 0x7a,
37996   0x53, 0xc8, 0x46, 0xcb, 0x5b, 0x6a, 0xd2, 0x4b, 0xcc, 0x52, 0xe7, 0xe7,
37997   0x56, 0xd2, 0x53, 0xdc, 0x6a, 0x6d, 0xe2, 0x5b, 0xdc, 0x5e, 0xe5, 0x6d,
37998   0x7a, 0xea, 0x5f, 0xda, 0x59, 0xdc, 0x68, 0x70, 0xdb, 0x52, 0xcf, 0x53,
37999   0xe0, 0xe9, 0x53, 0xcb, 0x4a, 0xcf, 0x66, 0x5c, 0xcb, 0x46, 0xc7, 0x51,
38000   0xfb, 0xcf, 0x46, 0xc2, 0x48, 0xd8, 0xdf, 0x4a, 0xc2, 0x42, 0xcb, 0x69,
38001   0x53, 0xc5, 0x41, 0xc5, 0x53, 0x6b, 0xcc, 0x44, 0xc3, 0x4a, 0xe0, 0xdb,
38002   0x4a, 0xc5, 0x48, 0xd2, 0x78, 0x55, 0xcb, 0x49, 0xce, 0x5c, 0x6e, 0xd7,
38003   0x4f, 0xcf, 0x56, 0xe6, 0xef, 0x5d, 0xd8, 0x59, 0xdc, 0x67, 0xf6, 0xee,
38004   0x65, 0xdf, 0x5d, 0xdd, 0x61, 0xec, 0xf4, 0x5f, 0xd8, 0x54, 0xd6, 0x5f,
38005   0x78, 0xda, 0x4f, 0xcc, 0x4f, 0xde, 0xea, 0x50, 0xc9, 0x48, 0xce, 0x64,
38006   0x5a, 0xca, 0x45, 0xc7, 0x50, 0x7b, 0xcf, 0x45, 0xc3, 0x48, 0xda, 0xde,
38007   0x4a, 0xc2, 0x43, 0xcc, 0x6d, 0x53, 0xc6, 0x43, 0xc7, 0x56, 0x6a, 0xcd,
38008   0x46, 0xc5, 0x4d, 0xe2, 0xdc, 0x4c, 0xc8, 0x4b, 0xd5, 0x7a, 0x59, 0xce,
38009   0x4d, 0xd0, 0x5e, 0x76, 0xdc, 0x55, 0xd4, 0x5a, 0xe5, 0x7d, 0x68, 0xdf,
38010   0x5d, 0xde, 0x60, 0xe9, 0x73, 0x70, 0xe4, 0x5c, 0xd9, 0x59, 0xe1, 0x7a,
38011   0x60, 0xd5, 0x4f, 0xd1, 0x5b, 0x7e, 0xd9, 0x4d, 0xca, 0x4d, 0xdb, 0xe8,
38012   0x4f, 0xc8, 0x47, 0xcd, 0x66, 0x5a, 0xc9, 0x44, 0xc6, 0x51, 0x78, 0xce,
38013   0x45, 0xc3, 0x49, 0xdb, 0xdd, 0x49, 0xc3, 0x44, 0xce, 0x6f, 0x53, 0xc7,
38014   0x44, 0xc9, 0x57, 0x69, 0xce, 0x48, 0xc8, 0x4e, 0xe6, 0xde, 0x4e, 0xcb,
38015   0x4d, 0xd8, 0x78, 0x5d, 0xd2, 0x50, 0xd5, 0x5f, 0xfc, 0xe4, 0x5c, 0xda,
38016   0x5c, 0xe2, 0x6e, 0x7d, 0xeb, 0x63, 0xde, 0x5d, 0xde, 0x65, 0xf9, 0xe7,
38017   0x5a, 0xd5, 0x54, 0xdb, 0x6f, 0x5f, 0xd2, 0x4d, 0xce, 0x58, 0x7d, 0xd7,
38018   0x4b, 0xc9, 0x4c, 0xdb, 0xe7, 0x4e, 0xc6, 0x46, 0xcd, 0x67, 0x58, 0xc8,
38019   0x44, 0xc7, 0x53, 0x72, 0xce, 0x45, 0xc3, 0x4a, 0xdd, 0xdc, 0x4a, 0xc4,
38020   0x46, 0xcf, 0x76, 0x54, 0xc9, 0x46, 0xcb, 0x5a, 0x69, 0xd0, 0x4a, 0xcb,
38021   0x51, 0xe8, 0xe1, 0x52, 0xce, 0x50, 0xdb, 0x72, 0x63, 0xda, 0x56, 0xda,
38022   0x5f, 0xf1, 0xf3, 0x65, 0xe0, 0x5e, 0xe0, 0x63, 0xec, 0x7c, 0x6a, 0xde,
38023   0x59, 0xd8, 0x5c, 0xec, 0xe9, 0x58, 0xd0, 0x4f, 0xd7, 0x6c, 0x5f, 0xcf,
38024   0x4b, 0xcc, 0x56, 0xfc, 0xd5, 0x4a, 0xc7, 0x4b, 0xdb, 0xe4, 0x4d, 0xc6,
38025   0x46, 0xcd, 0x69, 0x57, 0xc8, 0x44, 0xc7, 0x54, 0x6e, 0xce, 0x46, 0xc5,
38026   0x4b, 0xdf, 0xdc, 0x4b, 0xc6, 0x48, 0xd2, 0x79, 0x55, 0xcb, 0x49, 0xcd,
38027   0x5d, 0x6c, 0xd4, 0x4d, 0xcd, 0x55, 0xe8, 0xe6, 0x58, 0xd3, 0x55, 0xdd,
38028   0x6e, 0x6d, 0xe0, 0x5d, 0xdd, 0x5f, 0xe9, 0x73, 0x75, 0xe9, 0x60, 0xdd,
38029   0x5c, 0xe0, 0x6c, 0x6e, 0xde, 0x55, 0xd4, 0x57, 0xe6, 0xeb, 0x56, 0xce,
38030   0x4d, 0xd4, 0x6a, 0x5e, 0xce, 0x49, 0xcb, 0x55, 0xfe, 0xd3, 0x49, 0xc6,
38031   0x4b, 0xdb, 0xe2, 0x4c, 0xc5, 0x46, 0xce, 0x6c, 0x56, 0xc8, 0x45, 0xc8,
38032   0x56, 0x6c, 0xce, 0x47, 0xc6, 0x4d, 0xe3, 0xdd, 0x4c, 0xc8, 0x4a, 0xd5,
38033   0x7a, 0x57, 0xcd, 0x4b, 0xcf, 0x5e, 0x6d, 0xd8, 0x50, 0xd1, 0x58, 0xe9,
38034   0xee, 0x5d, 0xd9, 0x5a, 0xde, 0x6a, 0xfe, 0xec, 0x65, 0xe0, 0x5f, 0xe0,
38035   0x67, 0xf0, 0xf1, 0x63, 0xda, 0x58, 0xda, 0x65, 0x78, 0xdc, 0x53, 0xcf,
38036   0x54, 0xe1, 0xeb, 0x54, 0xcc, 0x4b, 0xd1, 0x68, 0x5d, 0xcd, 0x48, 0xca,
38037   0x54, 0x7b, 0xd2, 0x48, 0xc6, 0x4b, 0xdc, 0xe0, 0x4c, 0xc6, 0x47, 0xcf,
38038   0x6e, 0x55, 0xc9, 0x45, 0xca, 0x58, 0x6b, 0xcf, 0x48, 0xc8, 0x4e, 0xe5,
38039   0xdd, 0x4e, 0xca, 0x4c, 0xd8, 0x7b, 0x5a, 0xcf, 0x4e, 0xd3, 0x60, 0x73,
38040   0xdd, 0x56, 0xd6, 0x5b, 0xe8, 0xfc, 0x67, 0xdf, 0x5e, 0xdf, 0x65, 0xed,
38041   0x7b, 0x6e, 0xe5, 0x5e, 0xdc, 0x5d, 0xe6, 0xff, 0x63, 0xd8, 0x53, 0xd5,
38042   0x5e, 0x7c, 0xdb, 0x4f, 0xcd, 0x50, 0xde, 0xea, 0x52, 0xcb, 0x4a, 0xcf,
38043   0x68, 0x5c, 0xcc, 0x47, 0xc9, 0x54, 0x79, 0xd1, 0x48, 0xc6, 0x4b, 0xdd,
38044   0xdf, 0x4c, 0xc6, 0x47, 0xd0, 0x6f, 0x56, 0xca, 0x47, 0xcb, 0x5a, 0x6b,
38045   0xd1, 0x4a, 0xca, 0x50, 0xe7, 0xdf, 0x50, 0xcd, 0x4f, 0xda, 0x79, 0x5e,
38046   0xd5, 0x52, 0xd7, 0x62, 0xff, 0xe4, 0x5c, 0xdb, 0x5d, 0xe5, 0x73, 0x77,
38047   0xea, 0x64, 0xe0, 0x5f, 0xe2, 0x6b, 0xfe, 0xe8, 0x5c, 0xd8, 0x58, 0xde,
38048   0x76, 0x63, 0xd5, 0x50, 0xd1, 0x5b, 0xff, 0xda, 0x4e, 0xcb, 0x4f, 0xdd,
38049   0xe9, 0x50, 0xca, 0x49, 0xcf, 0x69, 0x5b, 0xcb, 0x47, 0xc9, 0x55, 0x75,
38050   0xd1, 0x48, 0xc7, 0x4c, 0xde, 0xde, 0x4c, 0xc7, 0x49, 0xd2, 0x76, 0x57,
38051   0xcb, 0x49, 0xcd, 0x5c, 0x6b, 0xd3, 0x4c, 0xcd, 0x54, 0xe9, 0xe3, 0x54,
38052   0xcf, 0x52, 0xdc, 0x75, 0x64, 0xda, 0x58, 0xdb, 0x63, 0xf4, 0xee, 0x65,
38053   0xe0, 0x5f, 0xe3, 0x68, 0xf1, 0xf9, 0x6a, 0xe0, 0x5d, 0xdc, 0x60, 0xef,
38054   0xeb, 0x5b, 0xd5, 0x54, 0xda, 0x6d, 0x62, 0xd3, 0x4e, 0xcf, 0x59, 0xfd,
38055   0xd9, 0x4d, 0xca, 0x4e, 0xdd, 0xe8, 0x4f, 0xc9, 0x49, 0xcf, 0x69, 0x5a,
38056   0xcb, 0x47, 0xca, 0x56, 0x73, 0xd1, 0x49, 0xc7, 0x4d, 0xdf, 0xdf, 0x4d,
38057   0xc8, 0x4a, 0xd4, 0x77, 0x58, 0xcd, 0x4b, 0xcf, 0x5d, 0x6d, 0xd6, 0x4e,
38058   0xcf, 0x56, 0xea, 0xe9, 0x59, 0xd5, 0x56, 0xde, 0x6f, 0x6d, 0xdf, 0x5d,
38059   0xdd, 0x62, 0xeb, 0x7c, 0x71, 0xe8, 0x62, 0xdf, 0x60, 0xe5, 0x73, 0x6f,
38060   0xdf, 0x5a, 0xd7, 0x5c, 0xe9, 0xec, 0x5a, 0xd1, 0x50, 0xd7, 0x6c, 0x61,
38061   0xd1, 0x4c, 0xcd, 0x58, 0xfd, 0xd7, 0x4c, 0xc9, 0x4d, 0xdd, 0xe7, 0x4f,
38062   0xc9, 0x49, 0xcf, 0x6b, 0x59, 0xcb, 0x47, 0xcb, 0x57, 0x6f, 0xd1, 0x49,
38063   0xc9, 0x4e, 0xe2, 0xdf, 0x4e, 0xca, 0x4c, 0xd6, 0x78, 0x5a, 0xcf, 0x4d,
38064   0xd1, 0x5f, 0x70, 0xda, 0x52, 0xd3, 0x59, 0xe9, 0xef, 0x5e, 0xda, 0x5a,
38065   0xdf, 0x6b, 0x7b, 0xeb, 0x63, 0xe1, 0x61, 0xe5, 0x6b, 0xfa, 0xf0, 0x64,
38066   0xdd, 0x5b, 0xde, 0x68, 0x75, 0xdf, 0x56, 0xd4, 0x58, 0xe4, 0xed, 0x58,
38067   0xcf, 0x4e, 0xd5, 0x6a, 0x60, 0xcf, 0x4b, 0xcc, 0x57, 0xfd, 0xd6, 0x4b,
38068   0xc9, 0x4d, 0xdd, 0xe5, 0x4f, 0xc9, 0x49, 0xd0, 0x6d, 0x5a, 0xcc, 0x48,
38069   0xcc, 0x59, 0x6f, 0xd3, 0x4b, 0xca, 0x4f, 0xe5, 0xe1, 0x50, 0xcc, 0x4e,
38070   0xd9, 0x77, 0x5d, 0xd2, 0x4f, 0xd5, 0x60, 0x77, 0xde, 0x57, 0xd7, 0x5c,
38071   0xe8, 0xfa, 0x67, 0xdf, 0x5e, 0xe0, 0x67, 0xf0, 0xfc, 0x6d, 0xe5, 0x5f,
38072   0xdf, 0x61, 0xeb, 0xfb, 0x65, 0xdb, 0x57, 0xd9, 0x61, 0x7c, 0xde, 0x54,
38073   0xd0, 0x54, 0xe1, 0xed, 0x56, 0xcd, 0x4d, 0xd3, 0x69, 0x5f, 0xce, 0x4b,
38074   0xcc, 0x57, 0x7d, 0xd5, 0x4b, 0xc9, 0x4e, 0xde, 0xe4, 0x4f, 0xc9, 0x4a,
38075   0xd2, 0x6f, 0x5a, 0xcc, 0x4a, 0xcd, 0x5b, 0x6f, 0xd4, 0x4c, 0xcc, 0x52,
38076   0xe7, 0xe4, 0x53, 0xce, 0x50, 0xdb, 0x76, 0x60, 0xd6, 0x54, 0xd8, 0x62,
38077   0xff, 0xe5, 0x5d, 0xdc, 0x5e, 0xe7, 0x75, 0x73, 0xe9, 0x64, 0xe2, 0x63,
38078   0xe7, 0x6f, 0x7b, 0xe9, 0x5f, 0xdb, 0x5c, 0xe2, 0x78, 0x65, 0xd9, 0x54,
38079   0xd6, 0x5e, 0xfe, 0xdd, 0x51, 0xce, 0x52, 0xdf, 0xec, 0x54, 0xcd, 0x4c,
38080   0xd2, 0x69, 0x5d, 0xce, 0x4a, 0xcc, 0x57, 0x7a, 0xd5, 0x4b, 0xc9, 0x4e,
38081   0xdf, 0xe3, 0x4f, 0xca, 0x4b, 0xd4, 0x70, 0x5a, 0xcd, 0x4b, 0xce, 0x5c,
38082   0x6f, 0xd6, 0x4e, 0xce, 0x55, 0xe8, 0xe7, 0x57, 0xd2, 0x54, 0xdd, 0x73,
38083   0x66, 0xdb, 0x59, 0xdb, 0x63, 0xf5, 0xee, 0x65, 0xe0, 0x60, 0xe5, 0x6b,
38084   0xf7, 0xf6, 0x69, 0xe2, 0x5f, 0xdf, 0x65, 0xf5, 0xeb, 0x5d, 0xd8, 0x58,
38085   0xdd, 0x71, 0x65, 0xd7, 0x51, 0xd2, 0x5c, 0xfd, 0xdb, 0x4f, 0xcd, 0x50,
38086   0xde, 0xea, 0x53, 0xcc, 0x4c, 0xd2, 0x6a, 0x5d, 0xce, 0x4a, 0xcc, 0x58,
38087   0x78, 0xd4, 0x4b, 0xca, 0x4f, 0xe1, 0xe3, 0x4f, 0xcb, 0x4c, 0xd6, 0x74,
38088   0x5b, 0xcf, 0x4d, 0xd0, 0x5e, 0x70, 0xd9, 0x50, 0xd0, 0x58, 0xea, 0xeb,
38089   0x5b, 0xd6, 0x58, 0xdf, 0x6f, 0x6d, 0xe1, 0x5d, 0xde, 0x64, 0xed, 0xff,
38090   0x6e, 0xe8, 0x63, 0xe2, 0x64, 0xe9, 0x77, 0x6e, 0xe2, 0x5c, 0xdb, 0x5e,
38091   0xec, 0xed, 0x5c, 0xd5, 0x54, 0xda, 0x6d, 0x64, 0xd5, 0x4f, 0xd0, 0x5a,
38092   0xfd, 0xda, 0x4e, 0xcc, 0x4f, 0xde, 0xe9, 0x52, 0xcb, 0x4b, 0xd3, 0x6c,
38093   0x5c, 0xce, 0x4a, 0xcd, 0x5a, 0x74, 0xd5, 0x4c, 0xcb, 0x50, 0xe4, 0xe3,
38094   0x51, 0xcc, 0x4e, 0xd8, 0x77, 0x5c, 0xd1, 0x4f, 0xd4, 0x60, 0x72, 0xdc,
38095   0x55, 0xd5, 0x5b, 0xeb, 0xef, 0x5f, 0xdb, 0x5c, 0xe1, 0x6d, 0x7a, 0xeb,
38096   0x65, 0xe3, 0x64, 0xe8, 0x6e, 0xfc, 0xef, 0x66, 0xdf, 0x5e, 0xe0, 0x6b,
38097   0x76, 0xe0, 0x59, 0xd7, 0x5a, 0xe8, 0xee, 0x5a, 0xd2, 0x51, 0xd8, 0x6c,
38098   0x62, 0xd3, 0x4e, 0xcf, 0x5a, 0xff, 0xd9, 0x4e, 0xcc, 0x4f, 0xdf, 0xe7,
38099   0x51, 0xcb, 0x4c, 0xd4, 0x6e, 0x5c, 0xce, 0x4b, 0xce, 0x5b, 0x71, 0xd5,
38100   0x4d, 0xcd, 0x53, 0xe7, 0xe3, 0x53, 0xce, 0x50, 0xdb, 0x78, 0x5e, 0xd5,
38101   0x52, 0xd7, 0x63, 0x78, 0xdf, 0x5a, 0xd9, 0x5e, 0xea, 0xf9, 0x69, 0xe1,
38102   0x60, 0xe3, 0x6a, 0xf2, 0xfa, 0x6e, 0xe7, 0x63, 0xe1, 0x65, 0xed, 0xfa,
38103   0x67, 0xdd, 0x5a, 0xdc, 0x65, 0x7b, 0xdf, 0x57, 0xd4, 0x57, 0xe4, 0xee,
38104   0x59, 0xd0, 0x4f, 0xd6, 0x6b, 0x60, 0xd2, 0x4d, 0xce, 0x59, 0x7d, 0xd8,
38105   0x4d, 0xcc, 0x4f, 0xe0, 0xe7, 0x51, 0xcc, 0x4c, 0xd5, 0x6f, 0x5b, 0xce,
38106   0x4c, 0xcf, 0x5c, 0x70, 0xd7, 0x4e, 0xce, 0x55, 0xe9, 0xe5, 0x56, 0xd1,
38107   0x53, 0xdd, 0x78, 0x62, 0xd9, 0x57, 0xda, 0x66, 0x7e, 0xe6, 0x5e, 0xde,
38108   0x60, 0xe9, 0x78, 0x73, 0xea, 0x66, 0xe4, 0x66, 0xea, 0x71, 0x7a, 0xea,
38109   0x61, 0xde, 0x5e, 0xe5, 0x7a, 0x67, 0xdb, 0x57, 0xd8, 0x60, 0x7e, 0xde,
38110   0x54, 0xd1, 0x55, 0xe2, 0xed, 0x57, 0xcf, 0x4e, 0xd6, 0x6b, 0x5f, 0xd0,
38111   0x4c, 0xce, 0x5a, 0x7a, 0xd8, 0x4d, 0xcc, 0x50, 0xe3, 0xe5, 0x51, 0xcc,
38112   0x4d, 0xd7, 0x74, 0x5c, 0xcf, 0x4d, 0xd1, 0x5e, 0x6f, 0xd9, 0x50, 0xd0,
38113   0x58, 0xea, 0xe7, 0x59, 0xd4, 0x57, 0xde, 0x77, 0x68, 0xdd, 0x5b, 0xdd,
38114   0x66, 0xf7, 0xee, 0x67, 0xe3, 0x64, 0xe7, 0x6d, 0xf9, 0xf5, 0x6b, 0xe5,
38115   0x62, 0xe2, 0x68, 0xf6, 0xed, 0x5f, 0xdb, 0x5a, 0xdf, 0x72, 0x67, 0xd9,
38116   0x54, 0xd5, 0x5e, 0xfd, 0xdd, 0x52, 0xcf, 0x53, 0xe1, 0xed, 0x56, 0xce,
38117   0x4e, 0xd5, 0x6b, 0x5e, 0xd0, 0x4c, 0xce, 0x5a, 0x77, 0xd7, 0x4d, 0xcc,
38118   0x52, 0xe4, 0xe5, 0x53, 0xcd, 0x4e, 0xd8, 0x76, 0x5d, 0xd1, 0x4f, 0xd3,
38119   0x5f, 0x71, 0xdb, 0x53, 0xd4, 0x5a, 0xec, 0xec, 0x5d, 0xd9, 0x5a, 0xe1,
38120   0x72, 0x6e, 0xe3, 0x5f, 0xe0, 0x66, 0xef, 0xfe, 0x6f, 0xe9, 0x66, 0xe5,
38121   0x67, 0xec, 0x79, 0x70, 0xe5, 0x5e, 0xdd, 0x60, 0xee, 0xee, 0x5e, 0xd8,
38122   0x57, 0xdc, 0x6f, 0x67, 0xd8, 0x52, 0xd3, 0x5d, 0xfd, 0xdc, 0x51, 0xce,
38123   0x53, 0xe0, 0xeb, 0x55, 0xce, 0x4e, 0xd6, 0x6d, 0x5e, 0xd0, 0x4c, 0xcf,
38124   0x5b, 0x75, 0xd8, 0x4e, 0xcd, 0x53, 0xe6, 0xe5, 0x54, 0xce, 0x50, 0xda,
38125   0x78, 0x5e, 0xd4, 0x51, 0xd6, 0x63, 0x74, 0xdd, 0x57, 0xd7, 0x5d, 0xec,
38126   0xf0, 0x61, 0xdd, 0x5e, 0xe4, 0x6f, 0x7a, 0xec, 0x67, 0xe5, 0x67, 0xea,
38127   0x70, 0xfe, 0xf0, 0x68, 0xe2, 0x61, 0xe3, 0x6d, 0x77, 0xe4, 0x5c, 0xda,
38128   0x5d, 0xea, 0xef, 0x5d, 0xd6, 0x54, 0xdb, 0x6c, 0x65, 0xd6, 0x50, 0xd2,
38129   0x5c, 0xfe, 0xdc, 0x50, 0xce, 0x52, 0xe1, 0xea, 0x55, 0xcd, 0x4e, 0xd6,
38130   0x6e, 0x5e, 0xd0, 0x4d, 0xcf, 0x5d, 0x74, 0xd8, 0x4f, 0xce, 0x55, 0xe8,
38131   0xe6, 0x56, 0xd0, 0x53, 0xdc, 0x78, 0x60, 0xd7, 0x55, 0xd9, 0x65, 0x78,
38132   0xe2, 0x5b, 0xdb, 0x5f, 0xec, 0xfa, 0x69, 0xe3, 0x62, 0xe6, 0x6b, 0xf6,
38133   0xfa, 0x6e, 0xe9, 0x66, 0xe5, 0x68, 0xee, 0xfb, 0x69, 0xdf, 0x5d, 0xde,
38134   0x68, 0x7c, 0xe3, 0x5a, 0xd7, 0x5a, 0xe6, 0xef, 0x5c, 0xd3, 0x52, 0xd9,
38135   0x6c, 0x64, 0xd5, 0x4f, 0xd1, 0x5b, 0xff, 0xdb, 0x4f, 0xce, 0x53, 0xe2,
38136   0xe9, 0x55, 0xce, 0x4e, 0xd7, 0x70, 0x5e, 0xd1, 0x4e, 0xd1, 0x5e, 0x73,
38137   0xd9, 0x50, 0xd0, 0x58, 0xea, 0xe7, 0x58, 0xd3, 0x56, 0xde, 0x78, 0x64,
38138   0xdb, 0x59, 0xdc, 0x67, 0x7d, 0xe8, 0x5f, 0xdf, 0x62, 0xeb, 0x79, 0x72,
38139   0xeb, 0x67, 0xe7, 0x68, 0xec, 0x74, 0x79, 0xec, 0x64, 0xe0, 0x60, 0xe8,
38140   0x7a, 0x6a, 0xde, 0x5a, 0xdb, 0x63, 0xfe, 0xe1, 0x58, 0xd4, 0x58, 0xe4,
38141   0xef, 0x5a, 0xd2, 0x51, 0xd8, 0x6c, 0x63, 0xd4, 0x4f, 0xd0, 0x5c, 0x7d,
38142   0xda, 0x4f, 0xce, 0x53, 0xe3, 0xe8, 0x55, 0xce, 0x4f, 0xd9, 0x73, 0x5e,
38143   0xd2, 0x4f, 0xd4, 0x5f, 0x72, 0xdb, 0x53, 0xd3, 0x5a, 0xeb, 0xea, 0x5b,
38144   0xd7, 0x59, 0xe0, 0x75, 0x6a, 0xde, 0x5d, 0xde, 0x68, 0xf9, 0xef, 0x67,
38145   0xe5, 0x65, 0xe9, 0x6f, 0xfb, 0xf5, 0x6c, 0xe7, 0x64, 0xe5, 0x6a, 0xf8,
38146   0xee, 0x62, 0xdd, 0x5d, 0xe2, 0x73, 0x6a, 0xdc, 0x57, 0xd8, 0x5f, 0xfb,
38147   0xe0, 0x56, 0xd2, 0x57, 0xe2, 0xee, 0x59, 0xd1, 0x50, 0xd8, 0x6d, 0x62,
38148   0xd3, 0x4e, 0xd0, 0x5c, 0x7a, 0xda, 0x4f, 0xce, 0x54, 0xe5, 0xe8, 0x56,
38149   0xcf, 0x50, 0xda, 0x75, 0x5f, 0xd4, 0x51, 0xd6, 0x62, 0x74, 0xdd, 0x56,
38150   0xd6, 0x5c, 0xec, 0xed, 0x5e, 0xdb, 0x5c, 0xe3, 0x73, 0x6e, 0xe5, 0x60,
38151   0xe3, 0x68, 0xf1, 0xfd, 0x6f, 0xeb, 0x67, 0xe7, 0x69, 0xee, 0x7a, 0x71,
38152   0xe7, 0x61, 0xdf, 0x64, 0xef, 0xef, 0x60, 0xda, 0x5a, 0xde, 0x70, 0x69,
38153   0xda, 0x55, 0xd6, 0x5e, 0xfb, 0xde, 0x55, 0xd1, 0x56, 0xe2, 0xed, 0x59,
38154   0xd0, 0x50, 0xd8, 0x6d, 0x60, 0xd3, 0x4f, 0xd1, 0x5d, 0x79, 0xda, 0x50,
38155   0xcf, 0x56, 0xe7, 0xe8, 0x57, 0xd1, 0x53, 0xdc, 0x77, 0x60, 0xd7, 0x54,
38156   0xd8, 0x64, 0x76, 0xdf, 0x59, 0xd9, 0x5e, 0xed, 0xf2, 0x64, 0xde, 0x5f,
38157   0xe5, 0x6f, 0x79, 0xec, 0x68, 0xe7, 0x68, 0xec, 0x73, 0x7e, 0xf1, 0x6a,
38158   0xe5, 0x63, 0xe7, 0x6f, 0x77, 0xe7, 0x5e, 0xdc, 0x5e, 0xeb, 0xf2, 0x5f,
38159   0xd9, 0x57, 0xdc, 0x6d, 0x68, 0xd9, 0x53, 0xd5, 0x5d, 0xfc, 0xde, 0x53,
38160   0xd0, 0x55, 0xe3, 0xed, 0x58, 0xd0, 0x50, 0xd8, 0x6e, 0x60, 0xd3, 0x4f,
38161   0xd2, 0x5e, 0x77, 0xdb, 0x52, 0xd1, 0x57, 0xe8, 0xe9, 0x59, 0xd3, 0x55,
38162   0xdd, 0x78, 0x64, 0xd9, 0x57, 0xdb, 0x66, 0x7b, 0xe4, 0x5d, 0xdc, 0x61,
38163   0xec, 0xfa, 0x6b, 0xe4, 0x64, 0xe7, 0x6d, 0xf7, 0xf8, 0x6f, 0xea, 0x68,
38164   0xe8, 0x6a, 0xf2, 0xfa, 0x6b, 0xe3, 0x5f, 0xe1, 0x69, 0x7c, 0xe6, 0x5c,
38165   0xda, 0x5c, 0xe9, 0xf3, 0x5e, 0xd7, 0x55, 0xdb, 0x6c, 0x67, 0xd8, 0x52,
38166   0xd4, 0x5d, 0xfd, 0xdd, 0x53, 0xd0, 0x55, 0xe3, 0xec, 0x58, 0xd0, 0x50,
38167   0xd9, 0x6f, 0x61, 0xd4, 0x50, 0xd4, 0x5f, 0x77, 0xdc, 0x54, 0xd3, 0x59,
38168   0xea, 0xea, 0x5b, 0xd6, 0x58, 0xdf, 0x77, 0x67, 0xdc, 0x5a, 0xdd, 0x68,
38169   0xfe, 0xea, 0x62, 0xdf, 0x64, 0xeb, 0x7b, 0x73, 0xeb, 0x68, 0xe8, 0x6a,
38170   0xee, 0x77, 0x79, 0xed, 0x67, 0xe3, 0x64, 0xeb, 0x7c, 0x6b, 0xe0, 0x5c,
38171   0xdd, 0x65, 0xfe, 0xe5, 0x5a, 0xd8, 0x5a, 0xe6, 0xf3, 0x5d, 0xd5, 0x54,
38172   0xda, 0x6d, 0x67, 0xd7, 0x51, 0xd3, 0x5d, 0xfe, 0xdd, 0x53, 0xd0, 0x56,
38173   0xe5, 0xeb, 0x58, 0xd1, 0x52, 0xda, 0x71, 0x61, 0xd6, 0x52, 0xd6, 0x61,
38174   0x77, 0xdd, 0x56, 0xd5, 0x5b, 0xeb, 0xec, 0x5d, 0xd9, 0x5a, 0xe2, 0x75,
38175   0x6b, 0xe0, 0x5e, 0xe0, 0x68, 0xf9, 0xf0, 0x68, 0xe5, 0x66, 0xeb, 0x70,
38176   0xfe, 0xf4, 0x6c, 0xe9, 0x67, 0xe8, 0x6d, 0xfa, 0xef, 0x65, 0xdf, 0x5f,
38177   0xe6, 0x75, 0x6b, 0xde, 0x5a, 0xdb, 0x62, 0xfc, 0xe3, 0x59, 0xd6, 0x59,
38178   0xe5, 0xf2, 0x5c, 0xd4, 0x53, 0xda, 0x6d, 0x65, 0xd7, 0x51, 0xd4, 0x5e,
38179   0x7e, 0xdd, 0x53, 0xd1, 0x57, 0xe6, 0xeb, 0x59, 0xd2, 0x53, 0xdc, 0x75,
38180   0x62, 0xd7, 0x54, 0xd8, 0x64, 0x78, 0xdf, 0x59, 0xd8, 0x5d, 0xec, 0xee,
38181   0x60, 0xdc, 0x5d, 0xe4, 0x74, 0x70, 0xe6, 0x63, 0xe3, 0x6a, 0xf2, 0xfc,
38182   0x70, 0xeb, 0x69, 0xe9, 0x6b, 0xf0, 0x7d, 0x72, 0xe9, 0x64, 0xe3, 0x67,
38183   0xf2, 0xf2, 0x63, 0xdd, 0x5c, 0xe1, 0x70, 0x6b, 0xdd, 0x58, 0xd9, 0x5f,
38184   0xfb, 0xe2, 0x58, 0xd4, 0x58, 0xe5, 0xf1, 0x5b, 0xd4, 0x53, 0xda, 0x6d,
38185   0x64, 0xd6, 0x51, 0xd4, 0x5e, 0x7b, 0xdd, 0x54, 0xd2, 0x58, 0xe8, 0xeb,
38186   0x5a, 0xd4, 0x55, 0xdd, 0x76, 0x64, 0xd9, 0x57, 0xda, 0x65, 0x79, 0xe2,
38187   0x5b, 0xdb, 0x5f, 0xed, 0xf3, 0x66, 0xdf, 0x61, 0xe7, 0x71, 0x7a, 0xed,
38188   0x69, 0xe8, 0x6a, 0xed, 0x76, 0x7e, 0xf1, 0x6b, 0xe7, 0x66, 0xea, 0x71,
38189   0x77, 0xe9, 0x60, 0xde, 0x61, 0xed, 0xf5, 0x61, 0xdb, 0x5a, 0xde, 0x6e,
38190   0x6b, 0xdc, 0x57, 0xd8, 0x5f, 0xfb, 0xe1, 0x57, 0xd4, 0x57, 0xe5, 0xef,
38191   0x5b, 0xd3, 0x53, 0xda, 0x6e, 0x64, 0xd7, 0x52, 0xd5, 0x5f, 0x7b, 0xdd,
38192   0x55, 0xd3, 0x59, 0xe9, 0xeb, 0x5b, 0xd6, 0x58, 0xde, 0x77, 0x67, 0xdb,
38193   0x59, 0xdc, 0x68, 0x7d, 0xe6, 0x5f, 0xde, 0x63, 0xed, 0xfb, 0x6b, 0xe6,
38194   0x65, 0xe8, 0x6e, 0xfa, 0xf8, 0x6e, 0xeb, 0x69, 0xea, 0x6c, 0xf5, 0xfa,
38195   0x6c, 0xe5, 0x61, 0xe4, 0x6c, 0x7c, 0xe8, 0x5e, 0xdc, 0x5e, 0xea, 0xf4,
38196   0x60, 0xd9, 0x58, 0xdd, 0x6e, 0x6a, 0xdb, 0x55, 0xd7, 0x5e, 0xfc, 0xdf,
38197   0x56, 0xd3, 0x58, 0xe5, 0xee, 0x5b, 0xd3, 0x54, 0xdb, 0x6f, 0x64, 0xd7,
38198   0x53, 0xd7, 0x60, 0x79, 0xde, 0x56, 0xd5, 0x5b, 0xeb, 0xed, 0x5d, 0xd8,
38199   0x5a, 0xe1, 0x76, 0x69, 0xde, 0x5c, 0xde, 0x69, 0xfd, 0xeb, 0x64, 0xe2,
38200   0x66, 0xed, 0x7c, 0x74, 0xec, 0x6a, 0xe9, 0x6c, 0xef, 0x7a, 0x78, 0xee,
38201   0x68, 0xe6, 0x67, 0xed, 0x7c, 0x6d, 0xe3, 0x5e, 0xdf, 0x68, 0xfe, 0xe7,
38202   0x5d, 0xda, 0x5d, 0xe8, 0xf4, 0x5f, 0xd8, 0x57, 0xdc, 0x6e, 0x69, 0xda,
38203   0x55, 0xd6, 0x5e, 0xfd, 0xdf, 0x56, 0xd3, 0x58, 0xe6, 0xed, 0x5a, 0xd4,
38204   0x54, 0xdc, 0x72, 0x64, 0xd8, 0x55, 0xd8, 0x63, 0x78, 0xdf, 0x58, 0xd8,
38205   0x5d, 0xed, 0xee, 0x5f, 0xdb, 0x5c, 0xe4, 0x76, 0x6d, 0xe2, 0x5f, 0xe2,
38206   0x6a, 0xfa, 0xf1, 0x6a, 0xe7, 0x68, 0xec, 0x72, 0x7e, 0xf5, 0x6e, 0xea,
38207   0x69, 0xea, 0x6e, 0xfc, 0xf0, 0x68, 0xe2, 0x62, 0xe7, 0x77, 0x6d, 0xe0,
38208   0x5d, 0xdd, 0x65, 0xfb, 0xe6, 0x5b, 0xd9, 0x5b, 0xe7, 0xf4, 0x5e, 0xd7,
38209   0x56, 0xdc, 0x6e, 0x68, 0xd9, 0x54, 0xd6, 0x5f, 0xfe, 0xdf, 0x56, 0xd4,
38210   0x59, 0xe7, 0xed, 0x5b, 0xd5, 0x56, 0xdd, 0x73, 0x65, 0xda, 0x57, 0xda,
38211   0x65, 0x79, 0xe2, 0x5b, 0xda, 0x5f, 0xed, 0xf1, 0x63, 0xde, 0x5f, 0xe6,
38212   0x75, 0x72, 0xe8, 0x64, 0xe6, 0x6b, 0xf4, 0xfb, 0x70, 0xec, 0x6a, 0xeb,
38213   0x6d, 0xf3, 0x7e, 0x72, 0xeb, 0x66, 0xe5, 0x69, 0xf5, 0xf3, 0x66, 0xdf,
38214   0x5f, 0xe4, 0x73, 0x6d, 0xdf, 0x5b, 0xdc, 0x63, 0xfb, 0xe5, 0x5a, 0xd7,
38215   0x5a, 0xe6, 0xf3, 0x5d, 0xd7, 0x56, 0xdc, 0x6e, 0x67, 0xd9, 0x55, 0xd7,
38216   0x5f, 0x7e, 0xdf, 0x57, 0xd5, 0x5a, 0xe9, 0xed, 0x5c, 0xd6, 0x58, 0xde,
38217   0x76, 0x67, 0xdb, 0x59, 0xdc, 0x66, 0x7b, 0xe5, 0x5d, 0xdc, 0x61, 0xee,
38218   0xf6, 0x67, 0xe2, 0x62, 0xe8, 0x71, 0x7a, 0xee, 0x69, 0xe9, 0x6b, 0xef,
38219   0x78, 0x7c, 0xf0, 0x6c, 0xe9, 0x69, 0xec, 0x76, 0x77, 0xea, 0x63, 0xe1,
38220   0x65, 0xee, 0xf4, 0x65, 0xdd, 0x5d, 0xe1, 0x70, 0x6d, 0xde, 0x59, 0xda,
38221   0x61, 0xfb, 0xe4, 0x59, 0xd7, 0x5a, 0xe6, 0xf2, 0x5d, 0xd6, 0x56, 0xdc,
38222   0x6e, 0x67, 0xd9, 0x55, 0xd8, 0x61, 0x7c, 0xdf, 0x58, 0xd6, 0x5b, 0xea,
38223   0xee, 0x5d, 0xd8, 0x59, 0xe0, 0x76, 0x69, 0xdd, 0x5b, 0xde, 0x68, 0x7d,
38224   0xe9, 0x5f, 0xdf, 0x63, 0xee, 0xfc, 0x6c, 0xe7, 0x66, 0xe9, 0x6f, 0xfb,
38225   0xf7, 0x6e, 0xec, 0x6a, 0xec, 0x6e, 0xf8, 0xf9, 0x6d, 0xe7, 0x65, 0xe7,
38226   0x6e, 0x7c, 0xea, 0x61, 0xde, 0x61, 0xec, 0xf6, 0x64, 0xdc, 0x5b, 0xdf,
38227   0x6f, 0x6c, 0xdd, 0x58, 0xd9, 0x61, 0xfb, 0xe3, 0x59, 0xd6, 0x5a, 0xe7,
38228   0xf1, 0x5d, 0xd6, 0x56, 0xdd, 0x6f, 0x67, 0xda, 0x56, 0xd9, 0x62, 0x7c,
38229   0xe0, 0x59, 0xd8, 0x5d, 0xeb, 0xee, 0x5f, 0xda, 0x5b, 0xe2, 0x76, 0x6b,
38230   0xe0, 0x5d, 0xe0, 0x6a, 0xfe, 0xed, 0x65, 0xe4, 0x67, 0xee, 0x7b, 0x73,
38231   0xed, 0x6a, 0xeb, 0x6d, 0xf2, 0x7b, 0x77, 0xee, 0x6a, 0xe9, 0x6a, 0xef,
38232   0x7e, 0x6e, 0xe6, 0x61, 0xe2, 0x6a, 0xfe, 0xe9, 0x5f, 0xdc, 0x5f, 0xea,
38233   0xf7, 0x62, 0xdb, 0x5a, 0xde, 0x6e, 0x6c, 0xdc, 0x58, 0xd9, 0x60, 0xfc,
38234   0xe2, 0x59, 0xd6, 0x5a, 0xe7, 0xef, 0x5d, 0xd7, 0x57, 0xde, 0x72, 0x67,
38235   0xdb, 0x57, 0xda, 0x64, 0x7b, 0xe2, 0x5b, 0xda, 0x5e, 0xed, 0xf0, 0x61,
38236   0xdd, 0x5e, 0xe5, 0x77, 0x6e, 0xe4, 0x61, 0xe3, 0x6c, 0xf9, 0xf1, 0x6b,
38237   0xe8, 0x6a, 0xed, 0x75, 0x7e, 0xf5, 0x6e, 0xec, 0x6b, 0xec, 0x71, 0xfe,
38238   0xf1, 0x69, 0xe5, 0x65, 0xea, 0x78, 0x6e, 0xe4, 0x5e, 0xdf, 0x67, 0xfc,
38239   0xe9, 0x5e, 0xdb, 0x5d, 0xe9, 0xf6, 0x61, 0xda, 0x59, 0xde, 0x6e, 0x6b,
38240   0xdc, 0x57, 0xd9, 0x61, 0xfd, 0xe2, 0x59, 0xd7, 0x5b, 0xe9, 0xef, 0x5d,
38241   0xd8, 0x58, 0xdf, 0x73, 0x68, 0xdc, 0x59, 0xdc, 0x66, 0x7b, 0xe4, 0x5c,
38242   0xdc, 0x60, 0xee, 0xf4, 0x65, 0xdf, 0x60, 0xe7, 0x75, 0x73, 0xe9, 0x66,
38243   0xe7, 0x6c, 0xf5, 0xfa, 0x71, 0xed, 0x6b, 0xec, 0x6e, 0xf6, 0xfe, 0x73,
38244   0xec, 0x68, 0xe9, 0x6b, 0xf7, 0xf5, 0x68, 0xe2, 0x61, 0xe7, 0x73, 0x6e,
38245   0xe2, 0x5d, 0xde, 0x65, 0xfa, 0xe8, 0x5d, 0xda, 0x5d, 0xe8, 0xf6, 0x5f,
38246   0xd9, 0x59, 0xdd, 0x6f, 0x6a, 0xdc, 0x58, 0xd9, 0x62, 0xfe, 0xe2, 0x59,
38247   0xd7, 0x5c, 0xe9, 0xef, 0x5e, 0xd9, 0x5a, 0xdf, 0x75, 0x69, 0xdd, 0x5b,
38248   0xdd, 0x68, 0x7d, 0xe7, 0x5f, 0xde, 0x63, 0xee, 0xf7, 0x69, 0xe4, 0x64,
38249   0xe9, 0x72, 0x7b, 0xee, 0x6b, 0xea, 0x6c, 0xf0, 0x79, 0x7b, 0xf2, 0x6d,
38250   0xeb, 0x6b, 0xee, 0x76, 0x78, 0xec, 0x66, 0xe4, 0x67, 0xf0, 0xf7, 0x67,
38251   0xdf, 0x5e, 0xe4, 0x70, 0x6e, 0xe0, 0x5c, 0xdc, 0x63, 0xfa, 0xe7, 0x5c,
38252   0xd9, 0x5c, 0xe8, 0xf5, 0x5f, 0xd9, 0x58, 0xde, 0x6f, 0x6a, 0xdc, 0x58,
38253   0xda, 0x62, 0x7e, 0xe3, 0x5a, 0xd9, 0x5d, 0xeb, 0xf0, 0x5f, 0xdb, 0x5b,
38254   0xe2, 0x74, 0x6b, 0xdf, 0x5d, 0xdf, 0x69, 0x7e, 0xea, 0x63, 0xe1, 0x65,
38255   0xee, 0xfd, 0x6e, 0xe8, 0x68, 0xea, 0x6f, 0xfc, 0xf8, 0x6f, 0xed, 0x6c,
38256   0xed, 0x70, 0xf9, 0xf9, 0x6e, 0xe9, 0x68, 0xe9, 0x6f, 0x7c, 0xec, 0x64,
38257   0xe1, 0x64, 0xed, 0xf8, 0x66, 0xde, 0x5d, 0xe1, 0x6f, 0x6e, 0xdf, 0x5b,
38258   0xdc, 0x63, 0xfb, 0xe6, 0x5b, 0xd9, 0x5c, 0xe8, 0xf4, 0x5f, 0xd9, 0x59,
38259   0xde, 0x70, 0x6a, 0xdc, 0x59, 0xdb, 0x64, 0x7e, 0xe3, 0x5b, 0xda, 0x5e,
38260   0xec, 0xf0, 0x61, 0xdc, 0x5d, 0xe4, 0x75, 0x6d, 0xe2, 0x5f, 0xe1, 0x6b,
38261   0xfb, 0xee, 0x67, 0xe5, 0x68, 0xee, 0x7c, 0x75, 0xed, 0x6b, 0xec, 0x6e,
38262   0xf4, 0x7d, 0x77, 0xef, 0x6c, 0xea, 0x6b, 0xf1, 0xff, 0x6f, 0xe8, 0x64,
38263   0xe6, 0x6c, 0xff, 0xeb, 0x62, 0xdf, 0x61, 0xec, 0xf8, 0x65, 0xdd, 0x5c,
38264   0xe0, 0x6f, 0x6d, 0xdf, 0x5a, 0xdb, 0x63, 0xfa, 0xe6, 0x5b, 0xd9, 0x5c,
38265   0xe8, 0xf3, 0x5f, 0xda, 0x59, 0xdf, 0x71, 0x6a, 0xdd, 0x59, 0xdc, 0x65,
38266   0x7d, 0xe5, 0x5d, 0xdc, 0x5f, 0xed, 0xf3, 0x64, 0xde, 0x5f, 0xe6, 0x75,
38267   0x70, 0xe6, 0x63, 0xe5, 0x6c, 0xf8, 0xf3, 0x6c, 0xe9, 0x6a, 0xed, 0x76,
38268   0x7e, 0xf5, 0x6e, 0xec, 0x6c, 0xee, 0x74, 0xfe, 0xf2, 0x6b, 0xe8, 0x68,
38269   0xec, 0x7a, 0x6f, 0xe6, 0x61, 0xe2, 0x6a, 0xfc, 0xea, 0x60, 0xdd, 0x5f,
38270   0xea, 0xf8, 0x64, 0xdc, 0x5b, 0xdf, 0x6e, 0x6d, 0xde, 0x5a, 0xdb, 0x63,
38271   0xfb, 0xe5, 0x5b, 0xd9, 0x5d, 0xea, 0xf3, 0x5f, 0xda, 0x5a, 0xe0, 0x72,
38272   0x6b, 0xde, 0x5b, 0xdd, 0x67, 0x7e, 0xe7, 0x5e, 0xdd, 0x62, 0xee, 0xf6,
38273   0x68, 0xe1, 0x62, 0xe8, 0x74, 0x75, 0xeb, 0x68, 0xe8, 0x6c, 0xf6, 0xfb,
38274   0x72, 0xed, 0x6d, 0xed, 0x70, 0xf7, 0xfe, 0x74, 0xed, 0x6a, 0xea, 0x6d,
38275   0xf7, 0xf6, 0x6a, 0xe5, 0x64, 0xe9, 0x75, 0x70, 0xe5, 0x5f, 0xdf, 0x67,
38276   0xfa, 0xea, 0x5f, 0xdc, 0x5e, 0xe9, 0xf8, 0x63, 0xdc, 0x5b, 0xdf, 0x6f,
38277   0x6c, 0xde, 0x5a, 0xdb, 0x63, 0xfc, 0xe6, 0x5c, 0xda, 0x5e, 0xea, 0xf3,
38278   0x61, 0xdb, 0x5c, 0xe2, 0x74, 0x6c, 0xdf, 0x5d, 0xdf, 0x69, 0x7e, 0xe9,
38279   0x61, 0xdf, 0x64, 0xef, 0xfa, 0x6b, 0xe6, 0x65, 0xea, 0x72, 0x7b, 0xef,
38280   0x6c, 0xeb, 0x6d, 0xf1, 0x7a, 0x7a, 0xf3, 0x6e, 0xec, 0x6c, 0xef, 0x78,
38281   0x78, 0xed, 0x68, 0xe7, 0x6a, 0xf2, 0xf7, 0x6a, 0xe2, 0x61, 0xe6, 0x72,
38282   0x70, 0xe3, 0x5e, 0xde, 0x66, 0xfa, 0xe9, 0x5e, 0xdc, 0x5e, 0xe9, 0xf8,
38283   0x62, 0xdb, 0x5b, 0xdf, 0x6f, 0x6c, 0xde, 0x5a, 0xdc, 0x64, 0xfd, 0xe6,
38284   0x5c, 0xdb, 0x5e, 0xeb, 0xf4, 0x62, 0xdd, 0x5d, 0xe3, 0x74, 0x6d, 0xe2,
38285   0x5e, 0xe1, 0x69, 0xfd, 0xed, 0x65, 0xe3, 0x67, 0xee, 0xfe, 0x6f, 0xea,
38286   0x69, 0xeb, 0x70, 0xfb, 0xf7, 0x70, 0xed, 0x6d, 0xee, 0x72, 0xfa, 0xf9,
38287   0x6f, 0xeb, 0x6a, 0xeb, 0x71, 0x7c, 0xed, 0x67, 0xe3, 0x66, 0xee, 0xf9,
38288   0x69, 0xe0, 0x5f, 0xe4, 0x71, 0x71, 0xe2, 0x5d, 0xdd, 0x65, 0xf8, 0xe9,
38289   0x5e, 0xdb, 0x5e, 0xe8, 0xf7, 0x63, 0xdb, 0x5b, 0xdf, 0x70, 0x6d, 0xde,
38290   0x5b, 0xdc, 0x65, 0xfc, 0xe7, 0x5d, 0xdc, 0x5f, 0xec, 0xf5, 0x64, 0xde,
38291   0x5e, 0xe5, 0x73, 0x6f, 0xe5, 0x60, 0xe3, 0x6a, 0xfc, 0xf0, 0x68, 0xe7,
38292   0x69, 0xef, 0x7b, 0x75, 0xee, 0x6c, 0xec, 0x6f, 0xf5, 0x7d, 0x77, 0xef,
38293   0x6d, 0xec, 0x6d, 0xf3, 0xff, 0x70, 0xea, 0x66, 0xe8, 0x6e, 0xfe, 0xed,
38294   0x65, 0xe1, 0x64, 0xed, 0xfa, 0x68, 0xdf, 0x5e, 0xe2, 0x6f, 0x6f, 0xe1,
38295   0x5d, 0xdd, 0x65, 0xf9, 0xe9, 0x5e, 0xdb, 0x5e, 0xe9, 0xf6, 0x63, 0xdc,
38296   0x5b, 0xe0, 0x71, 0x6d, 0xdf, 0x5c, 0xdd, 0x66, 0xfe, 0xe9, 0x5f, 0xdd,
38297   0x61, 0xed, 0xf7, 0x67, 0xe0, 0x60, 0xe7, 0x74, 0x73, 0xe8, 0x64, 0xe6,
38298   0x6c, 0xf8, 0xf5, 0x6c, 0xeb, 0x6b, 0xee, 0x76, 0x7d, 0xf4, 0x6f, 0xed,
38299   0x6d, 0xef, 0x75, 0x7e, 0xf4, 0x6c, 0xe9, 0x6a, 0xee, 0x7a, 0x71, 0xe9,
38300   0x64, 0xe5, 0x6b, 0xfc, 0xed, 0x63, 0xdf, 0x62, 0xeb, 0xfa, 0x67, 0xde,
38301   0x5d, 0xe1, 0x6f, 0x6f, 0xe0, 0x5c, 0xdd, 0x64, 0xf9, 0xe8, 0x5e, 0xdb,
38302   0x5e, 0xea, 0xf6, 0x64, 0xdc, 0x5c, 0xe1, 0x72, 0x6d, 0xe0, 0x5d, 0xde,
38303   0x68, 0xfd, 0xea, 0x61, 0xdf, 0x63, 0xed, 0xf9, 0x6a, 0xe4, 0x63, 0xe9,
38304   0x74, 0x77, 0xec, 0x69, 0xe9, 0x6d, 0xf6, 0xfd, 0x73, 0xee, 0x6d, 0xee,
38305   0x72, 0xf9, 0xfd, 0x74, 0xee, 0x6c, 0xec, 0x6f, 0xf9, 0xf6, 0x6c, 0xe8,
38306   0x66, 0xeb, 0x76, 0x72, 0xe8, 0x62, 0xe2, 0x69, 0xfa, 0xec, 0x62, 0xde,
38307   0x60, 0xea, 0xfb, 0x66, 0xde, 0x5d, 0xe1, 0x6f, 0x6f, 0xe0, 0x5c, 0xdd,
38308   0x65, 0xfa, 0xe9, 0x5e, 0xdc, 0x5f, 0xeb, 0xf7, 0x64, 0xdd, 0x5d, 0xe3,
38309   0x72, 0x6e, 0xe2, 0x5e, 0xe0, 0x69, 0xfc, 0xec, 0x64, 0xe1, 0x65, 0xef,
38310   0xfc, 0x6c, 0xe7, 0x66, 0xeb, 0x72, 0x7c, 0xf1, 0x6c, 0xec, 0x6d, 0xf2,
38311   0x7b, 0x7a, 0xf2, 0x6e, 0xed, 0x6e, 0xf1, 0x7a, 0x79, 0xee, 0x6a, 0xe9,
38312   0x6c, 0xf4, 0xf9, 0x6b, 0xe5, 0x64, 0xe8, 0x73, 0x73, 0xe6, 0x60, 0xe0,
38313   0x68, 0xf9, 0xec, 0x61, 0xde, 0x5f, 0xea, 0xfa, 0x66, 0xde, 0x5d, 0xe1,
38314   0x6f, 0x6f, 0xe1, 0x5c, 0xdd, 0x66, 0xfb, 0xe9, 0x5e, 0xdd, 0x5f, 0xec,
38315   0xf7, 0x65, 0xde, 0x5e, 0xe5, 0x74, 0x6f, 0xe5, 0x60, 0xe2, 0x6a, 0xfc,
38316   0xee, 0x67, 0xe5, 0x68, 0xef, 0xfe, 0x71, 0xeb, 0x6a, 0xec, 0x72, 0xfc,
38317   0xf8, 0x71, 0xee, 0x6e, 0xef, 0x74, 0xfb, 0xf9, 0x70, 0xed, 0x6c, 0xed,
38318   0x73, 0x7d, 0xef, 0x69, 0xe6, 0x68, 0xef, 0xfa, 0x6b, 0xe3, 0x62, 0xe6,
38319   0x72, 0x73, 0xe5, 0x5f, 0xdf, 0x67, 0xf8, 0xeb, 0x60, 0xdd, 0x5f, 0xea,
38320   0xfb, 0x65, 0xde, 0x5d, 0xe2, 0x6f, 0x6e, 0xe1, 0x5d, 0xde, 0x66, 0xfd,
38321   0xea, 0x5f, 0xde, 0x61, 0xed, 0xf8, 0x67, 0xe0, 0x60, 0xe7, 0x74, 0x71,
38322   0xe8, 0x63, 0xe5, 0x6c, 0xfa, 0xf1, 0x6b, 0xe8, 0x6a, 0xef, 0x7c, 0x77,
38323   0xef, 0x6d, 0xed, 0x71, 0xf5, 0x7e, 0x79, 0xf0, 0x6e, 0xed, 0x6f, 0xf4,
38324   0xfe, 0x73, 0xeb, 0x69, 0xe9, 0x6f, 0xfd, 0xee, 0x67, 0xe4, 0x66, 0xed,
38325   0xfb, 0x6a, 0xe2, 0x60, 0xe5, 0x70, 0x72, 0xe5, 0x5e, 0xdf, 0x66, 0xf8,
38326   0xeb, 0x5f, 0xdd, 0x5f, 0xea, 0xfa, 0x65, 0xde, 0x5d, 0xe3, 0x6f, 0x6e,
38327   0xe2, 0x5d, 0xdf, 0x67, 0xfc, 0xeb, 0x60, 0xdf, 0x63, 0xed, 0xf9, 0x69,
38328   0xe3, 0x63, 0xe9, 0x74, 0x75, 0xea, 0x67, 0xe8, 0x6d, 0xf9, 0xf7, 0x6e,
38329   0xec, 0x6c, 0xef, 0x78, 0x7e, 0xf5, 0x71, 0xee, 0x6e, 0xf0, 0x77, 0xfe,
38330   0xf4, 0x6e, 0xeb, 0x6c, 0xef, 0x7b, 0x74, 0xea, 0x67, 0xe7, 0x6d, 0xfb,
38331   0xee, 0x66, 0xe1, 0x64, 0xec, 0xfc, 0x69, 0xe1, 0x5f, 0xe4, 0x6f, 0x72,
38332   0xe4, 0x5e, 0xdf, 0x66, 0xf9, 0xeb, 0x5f, 0xdd, 0x5f, 0xeb, 0xf9, 0x66,
38333   0xde, 0x5e, 0xe3, 0x71, 0x6f, 0xe4, 0x5f, 0xe0, 0x69, 0xfc, 0xec, 0x63,
38334   0xe1, 0x65, 0xef, 0xfb, 0x6b, 0xe6, 0x65, 0xea, 0x74, 0x79, 0xed, 0x6a,
38335   0xea, 0x6e, 0xf6, 0xfc, 0x73, 0xef, 0x6e, 0xef, 0x73, 0xf9, 0xfd, 0x75,
38336   0xef, 0x6d, 0xed, 0x70, 0xfa, 0xf7, 0x6e, 0xe9, 0x69, 0xec, 0x77, 0x74,
38337   0xe9, 0x65, 0xe5, 0x6b, 0xfa, 0xee, 0x64, 0xe0, 0x63, 0xec, 0xfc, 0x69,
38338   0xe0, 0x5f, 0xe3, 0x6f, 0x72, 0xe4, 0x5e, 0xdf, 0x66, 0xfa, 0xeb, 0x60,
38339   0xde, 0x60, 0xeb, 0xf9, 0x67, 0xdf, 0x5f, 0xe5, 0x72, 0x70, 0xe5, 0x60,
38340   0xe2, 0x6a, 0xfc, 0xee, 0x66, 0xe4, 0x67, 0xef, 0xfd, 0x6e, 0xe9, 0x68,
38341   0xec, 0x73, 0x7d, 0xf3, 0x6e, 0xed, 0x6e, 0xf3, 0x7b, 0x7b, 0xf5, 0x70,
38342   0xee, 0x6f, 0xf3, 0x7a, 0x7a, 0xef, 0x6c, 0xeb, 0x6d, 0xf5, 0xf9, 0x6d,
38343   0xe7, 0x67, 0xea, 0x75, 0x75, 0xe8, 0x63, 0xe3, 0x69, 0xf8, 0xed, 0x64,
38344   0xdf, 0x62, 0xeb, 0xfc, 0x69, 0xdf, 0x5f, 0xe3, 0x70, 0x71, 0xe3, 0x5e,
38345   0xdf, 0x67, 0xfa, 0xeb, 0x61, 0xdf, 0x61, 0xed, 0xfa, 0x68, 0xe1, 0x60,
38346   0xe7, 0x73, 0x71, 0xe7, 0x62, 0xe5, 0x6b, 0xfb, 0xf0, 0x69, 0xe7, 0x69,
38347   0xef, 0x7e, 0x72, 0xed, 0x6b, 0xed, 0x72, 0xfc, 0xf9, 0x72, 0xef, 0x6e,
38348   0xf1, 0x74, 0xfc, 0xf9, 0x71, 0xee, 0x6d, 0xee, 0x75, 0x7d, 0xf0, 0x6b,
38349   0xe8, 0x6b, 0xf0, 0xfa, 0x6d, 0xe6, 0x64, 0xe8, 0x72, 0x75, 0xe8, 0x62,
38350   0xe2, 0x69, 0xf8, 0xed, 0x63, 0xdf, 0x61, 0xeb, 0xfc, 0x68, 0xdf, 0x5f,
38351   0xe4, 0x70, 0x71, 0xe4, 0x5f, 0xe0, 0x68, 0xfb, 0xec, 0x62, 0xdf, 0x63,
38352   0xed, 0xfa, 0x69, 0xe3, 0x62, 0xe8, 0x74, 0x74, 0xea, 0x65, 0xe7, 0x6c,
38353   0xfa, 0xf4, 0x6c, 0xea, 0x6b, 0xef, 0x7a, 0x78, 0xf0, 0x6e, 0xee, 0x71,
38354   0xf6, 0xff, 0x79, 0xf2, 0x6f, 0xee, 0x70, 0xf5, 0xfd, 0x74, 0xed, 0x6b,
38355   0xec, 0x70, 0xfe, 0xf0, 0x69, 0xe7, 0x68, 0xef, 0xfd, 0x6c, 0xe5, 0x62,
38356   0xe7, 0x70, 0x74, 0xe7, 0x60, 0xe1, 0x67, 0xf9, 0xee, 0x62, 0xdf, 0x61,
38357   0xeb, 0xfb, 0x68, 0xe0, 0x5f, 0xe4, 0x70, 0x71, 0xe5, 0x5f, 0xe1, 0x69,
38358   0xfb, 0xed, 0x64, 0xe1, 0x65, 0xee, 0xfb, 0x6b, 0xe5, 0x65, 0xe9, 0x74,
38359   0x78, 0xec, 0x69, 0xe9, 0x6e, 0xf8, 0xf8, 0x6f, 0xec, 0x6d, 0xef, 0x77,
38360   0x7e, 0xf6, 0x72, 0xef, 0x70, 0xf2, 0x78, 0x7e, 0xf6, 0x6f, 0xed, 0x6d,
38361   0xf0, 0x7b, 0x75, 0xed, 0x69, 0xe9, 0x6e, 0xfb, 0xf0, 0x68, 0xe5, 0x66,
38362   0xee, 0xfd, 0x6b, 0xe4, 0x61, 0xe6, 0x70, 0x74, 0xe7, 0x60, 0xe1, 0x67,
38363   0xf8, 0xed, 0x63, 0xdf, 0x62, 0xeb, 0xfb, 0x69, 0xe0, 0x5f, 0xe5, 0x71,
38364   0x72, 0xe6, 0x61, 0xe2, 0x6a, 0xfa, 0xee, 0x66, 0xe3, 0x67, 0xee, 0xfc,
38365   0x6e, 0xe8, 0x67, 0xeb, 0x74, 0x7c, 0xef, 0x6c, 0xeb, 0x6e, 0xf6, 0xfd,
38366   0x75, 0xf0, 0x6f, 0xef, 0x74, 0xfa, 0xfd, 0x75, 0xf0, 0x6e, 0xef, 0x73,
38367   0xfb, 0xf8, 0x6e, 0xeb, 0x6a, 0xee, 0x78, 0x76, 0xeb, 0x67, 0xe7, 0x6c,
38368   0xfa, 0xf0, 0x67, 0xe3, 0x65, 0xed, 0xfe, 0x6b, 0xe3, 0x61, 0xe5, 0x6f,
38369   0x74, 0xe7, 0x60, 0xe1, 0x67, 0xf9, 0xee, 0x63, 0xdf, 0x62, 0xec, 0xfc,
38370   0x69, 0xe2, 0x60, 0xe6, 0x72, 0x73, 0xe8, 0x63, 0xe4, 0x6b, 0xfa, 0xef,
38371   0x68, 0xe5, 0x69, 0xef, 0xfe, 0x70, 0xea, 0x6a, 0xec, 0x74, 0x7e, 0xf3,
38372   0x6f, 0xed, 0x6f, 0xf3, 0x7c, 0x7b, 0xf4, 0x71, 0xef, 0x71, 0xf4, 0x7c,
38373   0x7a, 0xf0, 0x6e, 0xec, 0x6f, 0xf6, 0xfa, 0x6f, 0xea, 0x69, 0xeb, 0x76,
38374   0x77, 0xeb, 0x66, 0xe5, 0x6b, 0xf8, 0xef, 0x67, 0xe2, 0x64, 0xed, 0xfe,
38375   0x6b, 0xe3, 0x60, 0xe5, 0x6f, 0x74, 0xe7, 0x60, 0xe1, 0x68, 0xf9, 0xee,
38376   0x63, 0xe1, 0x63, 0xed, 0xfd, 0x6a, 0xe4, 0x62, 0xe8, 0x72, 0x75, 0xe9,
38377   0x65, 0xe6, 0x6c, 0xfa, 0xf2, 0x6b, 0xe8, 0x6a, 0xef, 0x7d, 0x74, 0xed,
38378   0x6d, 0xed, 0x73, 0xfb, 0xf9, 0x74, 0xef, 0x70, 0xf1, 0x77, 0xfd, 0xfa,
38379   0x73, 0xef, 0x6e, 0xef, 0x76, 0x7d, 0xf2, 0x6c, 0xeb, 0x6c, 0xf2, 0xfc,
38380   0x6e, 0xe9, 0x67, 0xea, 0x72, 0x77, 0xea, 0x65, 0xe4, 0x6a, 0xf8, 0xef,
38381   0x66, 0xe2, 0x63, 0xec, 0xff, 0x6b, 0xe3, 0x60, 0xe5, 0x70, 0x75, 0xe7,
38382   0x61, 0xe2, 0x69, 0xf9, 0xee, 0x65, 0xe2, 0x64, 0xed, 0xfd, 0x6c, 0xe5,
38383   0x64, 0xe9, 0x73, 0x77, 0xeb, 0x67, 0xe8, 0x6d, 0xf9, 0xf6, 0x6d, 0xeb,
38384   0x6c, 0xef, 0x7a, 0x7a, 0xf1, 0x6f, 0xee, 0x72, 0xf7, 0xff, 0x78, 0xf3,
38385   0x70, 0xef, 0x72, 0xf7, 0xfe, 0x75, 0xee, 0x6c, 0xed, 0x72, 0xfd, 0xf2,
38386   0x6b, 0xe8, 0x6a, 0xef, 0xfd, 0x6e, 0xe7, 0x65, 0xe9, 0x71, 0x78, 0xea,
38387   0x63, 0xe4, 0x69, 0xf7, 0xef, 0x66, 0xe1, 0x64, 0xec, 0xff, 0x6b, 0xe3,
38388   0x61, 0xe6, 0x70, 0x75, 0xe8, 0x62, 0xe3, 0x6a, 0xf9, 0xef, 0x67, 0xe3,
38389   0x66, 0xee, 0xfe, 0x6d, 0xe7, 0x66, 0xea, 0x74, 0x7a, 0xee, 0x6a, 0xea,
38390   0x6e, 0xf7, 0xfa, 0x70, 0xee, 0x6e, 0xf1, 0x77, 0x7e, 0xf7, 0x72, 0xf0,
38391   0x71, 0xf4, 0x79, 0x7d, 0xf6, 0x71, 0xee, 0x6f, 0xf2, 0x7c, 0x77, 0xee,
38392   0x6b, 0xeb, 0x6f, 0xfb, 0xf2, 0x6b, 0xe7, 0x68, 0xee, 0xff, 0x6e, 0xe6,
38393   0x64, 0xe7, 0x70, 0x78, 0xea, 0x63, 0xe3, 0x69, 0xf7, 0xef, 0x66, 0xe2,
38394   0x64, 0xec, 0xfe, 0x6b, 0xe4, 0x62, 0xe6, 0x71, 0x76, 0xe9, 0x63, 0xe4,
38395   0x6a, 0xf9, 0xf1, 0x68, 0xe5, 0x67, 0xef, 0x7e, 0x6f, 0xea, 0x68, 0xec,
38396   0x74, 0x7c, 0xf1, 0x6c, 0xec, 0x6f, 0xf6, 0xfe, 0x76, 0xf1, 0x6f, 0xf0,
38397   0x75, 0xfb, 0xfd, 0x76, 0xf1, 0x6f, 0xef, 0x74, 0xfb, 0xf9, 0x70, 0xec,
38398   0x6d, 0xee, 0x79, 0x78, 0xed, 0x6a, 0xe9, 0x6d, 0xf9, 0xf2, 0x6a, 0xe6,
38399   0x67, 0xed, 0x7e, 0x6d, 0xe6, 0x63, 0xe7, 0x70, 0x78, 0xe9, 0x63, 0xe3,
38400   0x69, 0xf7, 0xf0, 0x66, 0xe2, 0x64, 0xec, 0xfe, 0x6c, 0xe5, 0x63, 0xe7,
38401   0x71, 0x77, 0xea, 0x65, 0xe6, 0x6b, 0xf8, 0xf3, 0x6a, 0xe8, 0x69, 0xef,
38402   0x7e, 0x72, 0xec, 0x6b, 0xed, 0x74, 0xfe, 0xf5, 0x6f, 0xee, 0x6f, 0xf4,
38403   0x7c, 0x7b, 0xf5, 0x71, 0xf0, 0x72, 0xf6, 0x7b, 0x79, 0xf3, 0x6e, 0xee,
38404   0x6f, 0xf7, 0xfb, 0x6f, 0xec, 0x6b, 0xed, 0x76, 0x79, 0xed, 0x68, 0xe7,
38405   0x6c, 0xf7, 0xf2, 0x69, 0xe5, 0x66, 0xec, 0x7e, 0x6e, 0xe5, 0x63, 0xe7,
38406   0x6f, 0x78, 0xe9, 0x63, 0xe4, 0x69, 0xf7, 0xf0, 0x67, 0xe3, 0x65, 0xed,
38407   0xff, 0x6d, 0xe6, 0x65, 0xe9, 0x73, 0x78, 0xeb, 0x67, 0xe7, 0x6c, 0xf8,
38408   0xf5, 0x6d, 0xea, 0x6b, 0xf0, 0x7c, 0x76, 0xef, 0x6d, 0xee, 0x72, 0xfc,
38409   0xfb, 0x74, 0xf2, 0x70, 0xf3, 0x76, 0xfe, 0xfb, 0x75, 0xf0, 0x6f, 0xf1,
38410   0x77, 0x7d, 0xf4, 0x6e, 0xec, 0x6d, 0xf3, 0xfe, 0x70, 0xeb, 0x69, 0xeb,
38411   0x73, 0x7a, 0xed, 0x67, 0xe7, 0x6b, 0xf7, 0xf4, 0x69, 0xe5, 0x66, 0xec,
38412   0x7d, 0x6d, 0xe5, 0x63, 0xe6, 0x6f, 0x79, 0xea, 0x64, 0xe3, 0x6a, 0xf6,
38413   0xf0, 0x68, 0xe4, 0x66, 0xed, 0xff, 0x6e, 0xe7, 0x66, 0xea, 0x73, 0x7a,
38414   0xed, 0x69, 0xe9, 0x6d, 0xf8, 0xf8, 0x6f, 0xec, 0x6d, 0xf1, 0x7a, 0x7a,
38415   0xf3, 0x6f, 0xf0, 0x72, 0xf8, 0x7e, 0x78, 0xf5, 0x70, 0xf1, 0x72, 0xf9,
38416   0xff, 0x75, 0xf0, 0x6d, 0xef, 0x72, 0xfd, 0xf4, 0x6d, 0xeb, 0x6b, 0xf1,
38417   0xff, 0x70, 0xea, 0x67, 0xea, 0x72, 0x7a, 0xec, 0x66, 0xe5, 0x6a, 0xf6,
38418   0xf3, 0x68, 0xe4, 0x66, 0xec, 0x7d, 0x6e, 0xe6, 0x64, 0xe7, 0x70, 0x79,
38419   0xea, 0x65, 0xe4, 0x6b, 0xf6, 0xf2, 0x69, 0xe5, 0x68, 0xed, 0xff, 0x6f,
38420   0xe9, 0x68, 0xeb, 0x73, 0x7c, 0xef, 0x6c, 0xeb, 0x6e, 0xf6, 0xfc, 0x72,
38421   0xee, 0x6e, 0xf1, 0x77, 0xfe, 0xf8, 0x73, 0xf2, 0x71, 0xf5, 0x79, 0x7d,
38422   0xf7, 0x72, 0xef, 0x6f, 0xf4, 0x7b, 0x77, 0xf0, 0x6c, 0xec, 0x6f, 0xfb,
38423   0xf5, 0x6c, 0xe9, 0x6a, 0xef, 0x7d, 0x6f, 0xe9, 0x66, 0xe9, 0x70, 0x7a,
38424   0xec, 0x66, 0xe5, 0x6a, 0xf6, 0xf3, 0x69, 0xe4, 0x65, 0xec, 0x7d, 0x6e,
38425   0xe7, 0x64, 0xe8, 0x70, 0x79, 0xeb, 0x66, 0xe6, 0x6b, 0xf7, 0xf4, 0x6b,
38426   0xe7, 0x69, 0xee, 0x7d, 0x72, 0xeb, 0x6a, 0xec, 0x73, 0xff, 0xf2, 0x6e,
38427   0xed, 0x6f, 0xf5, 0xfe, 0x78, 0xf2, 0x70, 0xf1, 0x75, 0xfb, 0xfd, 0x77,
38428   0xf3, 0x70, 0xf1, 0x75, 0xfb, 0xfa, 0x73, 0xee, 0x6e, 0xf0, 0x78, 0x79,
38429   0xef, 0x6b, 0xeb, 0x6e, 0xf8, 0xf5, 0x6c, 0xe8, 0x69, 0xee, 0x7c, 0x6f,
38430   0xe9, 0x66, 0xe8, 0x6f, 0x7a, 0xec, 0x66, 0xe5, 0x6a, 0xf6, 0xf4, 0x69,
38431   0xe5, 0x66, 0xed, 0x7c, 0x6e, 0xe7, 0x65, 0xe9, 0x71, 0x7a, 0xec, 0x68,
38432   0xe7, 0x6c, 0xf7, 0xf6, 0x6c, 0xe9, 0x6b, 0xef, 0x7c, 0x75, 0xed, 0x6c,
38433   0xed, 0x74, 0xfd, 0xf7, 0x71, 0xef, 0x70, 0xf4, 0x7c, 0x7c, 0xf6, 0x74,
38434   0xf1, 0x73, 0xf6, 0x7d, 0x7b, 0xf3, 0x70, 0xef, 0x71, 0xf7, 0xfd, 0x72,
38435   0xee, 0x6c, 0xee, 0x75, 0x7a, 0xef, 0x6a, 0xea, 0x6d, 0xf7, 0xf6, 0x6b,
38436   0xe7, 0x68, 0xed, 0x7b, 0x6f, 0xe8, 0x66, 0xe9, 0x6f, 0x7b, 0xec, 0x66,
38437   0xe5, 0x6a, 0xf6, 0xf4, 0x6a, 0xe6, 0x67, 0xed, 0x7c, 0x6f, 0xe9, 0x66,
38438   0xe9, 0x72, 0x7a, 0xee, 0x69, 0xe9, 0x6d, 0xf8, 0xf8, 0x6e, 0xeb, 0x6c,
38439   0xf0, 0x7b, 0x78, 0xf0, 0x6e, 0xef, 0x74, 0xfa, 0xfb, 0x76, 0xf1, 0x71,
38440   0xf3, 0x78, 0xfd, 0xfa, 0x76, 0xf1, 0x71, 0xf3, 0x78, 0x7e, 0xf5, 0x6f,
38441   0xed, 0x6f, 0xf4, 0xfe, 0x72, 0xec, 0x6b, 0xec, 0x74, 0x7c, 0xee, 0x6a,
38442   0xe8, 0x6c, 0xf6, 0xf5, 0x6b, 0xe7, 0x67, 0xed, 0x7c, 0x6f, 0xe9, 0x65,
38443   0xe9, 0x6f, 0x7a, 0xed, 0x66, 0xe6, 0x6a, 0xf6, 0xf5, 0x6a, 0xe7, 0x68,
38444   0xee, 0x7c, 0x70, 0xea, 0x68, 0xeb, 0x72, 0x7c, 0xef, 0x6b, 0xeb, 0x6e,
38445   0xf7, 0xfa, 0x70, 0xee, 0x6d, 0xf1, 0x79, 0x7b, 0xf5, 0x70, 0xf0, 0x74,
38446   0xf7, 0x7e, 0x7a, 0xf4, 0x73, 0xf1, 0x75, 0xf9, 0xfe, 0x77, 0xf1, 0x6f,
38447   0xef, 0x74, 0xfc, 0xf6, 0x6f, 0xec, 0x6d, 0xf1, 0x7e, 0x73, 0xeb, 0x6a,
38448   0xeb, 0x73, 0x7d, 0xee, 0x69, 0xe7, 0x6b, 0xf5, 0xf6, 0x6b, 0xe7, 0x67,
38449   0xed, 0x7b, 0x6f, 0xe9, 0x66, 0xe9, 0x6f, 0x7b, 0xed, 0x67, 0xe7, 0x6b,
38450   0xf7, 0xf6, 0x6b, 0xe8, 0x68, 0xee, 0x7c, 0x72, 0xeb, 0x69, 0xec, 0x73,
38451   0x7d, 0xf2, 0x6d, 0xec, 0x6f, 0xf7, 0xfc, 0x75, 0xef, 0x6f, 0xf1, 0x78,
38452   0xfe, 0xf9, 0x75, 0xf2, 0x73, 0xf5, 0x7a, 0x7e, 0xf8, 0x74, 0xf1, 0x71,
38453   0xf4, 0x7c, 0x79, 0xf1, 0x6e, 0xee, 0x71, 0xfb, 0xf7, 0x6e, 0xeb, 0x6b,
38454   0xf0, 0x7c, 0x72, 0xeb, 0x69, 0xea, 0x71, 0x7d, 0xee, 0x68, 0xe7, 0x6b,
38455   0xf5, 0xf6, 0x6b, 0xe7, 0x68, 0xed, 0x7c, 0x70, 0xe9, 0x67, 0xe9, 0x70,
38456   0x7b, 0xed, 0x68, 0xe8, 0x6c, 0xf7, 0xf6, 0x6c, 0xe9, 0x6a, 0xef, 0x7b,
38457   0x74, 0xed, 0x6b, 0xed, 0x73, 0xff, 0xf5, 0x6f, 0xee, 0x6f, 0xf6, 0x7e,
38458   0x79, 0xf3, 0x71, 0xf2, 0x76, 0xfb, 0xfd, 0x78, 0xf5, 0x72, 0xf3, 0x76,
38459   0xfc, 0xfa, 0x74, 0xef, 0x6f, 0xf2, 0x79, 0x7a, 0xf1, 0x6d, 0xec, 0x6f,
38460   0xf9, 0xf7, 0x6d, 0xea, 0x6b, 0xee, 0x7c, 0x72, 0xeb, 0x68, 0xea, 0x70,
38461   0x7d, 0xee, 0x69, 0xe7, 0x6b, 0xf4, 0xf6, 0x6c, 0xe7, 0x68, 0xed, 0x7b,
38462   0x71, 0xea, 0x67, 0xea, 0x71, 0x7c, 0xee, 0x69, 0xe9, 0x6c, 0xf6, 0xf8,
38463   0x6e, 0xeb, 0x6b, 0xf0, 0x7a, 0x76, 0xef, 0x6d, 0xee, 0x73, 0xfd, 0xf9,
38464   0x72, 0xf0, 0x70, 0xf5, 0x7b, 0x7c, 0xf7, 0x73, 0xf3, 0x74, 0xf8, 0x7c,
38465   0x7b, 0xf5, 0x71, 0xf1, 0x72, 0xf9, 0xfd, 0x74, 0xee, 0x6d, 0xef, 0x77,
38466   0x7c, 0xf1, 0x6c, 0xeb, 0x6e, 0xf7, 0xf7, 0x6d, 0xe9, 0x6a, 0xee, 0x7c,
38467   0x72, 0xea, 0x68, 0xea, 0x70, 0x7d, 0xee, 0x69, 0xe7, 0x6b, 0xf5, 0xf6,
38468   0x6c, 0xe7, 0x69, 0xed, 0x7c, 0x72, 0xea, 0x68, 0xeb, 0x71, 0x7d, 0xef,
38469   0x6b, 0xea, 0x6d, 0xf7, 0xfa, 0x6f, 0xec, 0x6d, 0xf1, 0x7a, 0x7a, 0xf2,
38470   0x6f, 0xef, 0x74, 0xfa, 0xfc, 0x76, 0xf3, 0x72, 0xf4, 0x78, 0xfe, 0xfb,
38471   0x75, 0xf3, 0x72, 0xf4, 0x79, 0x7e, 0xf7, 0x70, 0xef, 0x70, 0xf5, 0xfe,
38472   0x75, 0xee, 0x6c, 0xee, 0x75, 0x7d, 0xf0, 0x6c, 0xea, 0x6d, 0xf7, 0xf8,
38473   0x6d, 0xe9, 0x69, 0xee, 0x7b, 0x73, 0xea, 0x68, 0xea, 0x70, 0x7d, 0xee,
38474   0x69, 0xe8, 0x6b, 0xf6, 0xf7, 0x6c, 0xe8, 0x69, 0xee, 0x7b, 0x73, 0xec,
38475   0x6a, 0xec, 0x71, 0x7d, 0xf2, 0x6c, 0xec, 0x6e, 0xf7, 0xfc, 0x73, 0xee,
38476   0x6e, 0xf1, 0x79, 0x7c, 0xf6, 0x72, 0xf1, 0x74, 0xf9, 0x7e, 0x7a, 0xf6,
38477   0x73, 0xf3, 0x75, 0xfa, 0xfe, 0x78, 0xf3, 0x70, 0xf1, 0x76, 0xfd, 0xf7,
38478   0x70, 0xed, 0x6e, 0xf3, 0x7e, 0x75, 0xed, 0x6c, 0xed, 0x73, 0x7e, 0xf0,
38479   0x6b, 0xea, 0x6c, 0xf6, 0xf8, 0x6d, 0xe9, 0x69, 0xee, 0x7b, 0x72, 0xeb,
38480   0x68, 0xea, 0x70, 0x7d, 0xee, 0x69, 0xe9, 0x6c, 0xf5, 0xf8, 0x6d, 0xea,
38481   0x6a, 0xef, 0x7b, 0x75, 0xed, 0x6b, 0xed, 0x72, 0xff, 0xf4, 0x6e, 0xed,
38482   0x6f, 0xf6, 0xfe, 0x75, 0xf1, 0x70, 0xf3, 0x78, 0xfe, 0xf9, 0x75, 0xf3,
38483   0x73, 0xf6, 0x7b, 0x7d, 0xf9, 0x74, 0xf2, 0x72, 0xf7, 0x7c, 0x7a, 0xf3,
38484   0x6f, 0xef, 0x73, 0xfb, 0xf8, 0x6f, 0xed, 0x6d, 0xf1, 0x7c, 0x75, 0xed,
38485   0x6b, 0xec, 0x73, 0x7d, 0xef, 0x6b, 0xe9, 0x6c, 0xf6, 0xf8, 0x6d, 0xe9,
38486   0x69, 0xee, 0x7a, 0x73, 0xeb, 0x69, 0xeb, 0x71, 0x7e, 0xef, 0x6b, 0xe9,
38487   0x6d, 0xf6, 0xf8, 0x6e, 0xea, 0x6c, 0xef, 0x7c, 0x77, 0xee, 0x6d, 0xee,
38488   0x74, 0xfe, 0xf7, 0x70, 0xef, 0x70, 0xf6, 0x7d, 0x78, 0xf5, 0x71, 0xf4,
38489   0x76, 0xfb, 0xfe, 0x78, 0xf6, 0x73, 0xf5, 0x76, 0xfd, 0xfb, 0x75, 0xf2,
38490   0x70, 0xf3, 0x7a, 0x7b, 0xf3, 0x6e, 0xed, 0x71, 0xf9, 0xf8, 0x6f, 0xec,
38491   0x6c, 0xef, 0x7c, 0x75, 0xec, 0x6a, 0xec, 0x71, 0x7e, 0xf0, 0x6a, 0xe9,
38492   0x6c, 0xf6, 0xf9, 0x6d, 0xe9, 0x69, 0xee, 0x7a, 0x73, 0xec, 0x69, 0xeb,
38493   0x71, 0x7e, 0xf0, 0x6b, 0xea, 0x6d, 0xf6, 0xfa, 0x6f, 0xec, 0x6d, 0xf0,
38494   0x7b, 0x79, 0xf0, 0x6e, 0xef, 0x75, 0xfc, 0xf9, 0x74, 0xf1, 0x72, 0xf6,
38495   0x7b, 0x7c, 0xf8, 0x75, 0xf4, 0x74, 0xf8, 0x7d, 0x7c, 0xf7, 0x73, 0xf2,
38496   0x74, 0xf9, 0xfd, 0x76, 0xf0, 0x6f, 0xf0, 0x77, 0x7d, 0xf3, 0x6d, 0xed,
38497   0x6f, 0xf8, 0xfa, 0x6f, 0xeb, 0x6b, 0xef, 0x7b, 0x75, 0xec, 0x6a, 0xeb,
38498   0x71, 0x7e, 0xf0, 0x6a, 0xe9, 0x6c, 0xf5, 0xf9, 0x6d, 0xea, 0x6a, 0xee,
38499   0x7a, 0x74, 0xed, 0x6a, 0xec, 0x71, 0x7e, 0xf2, 0x6c, 0xec, 0x6e, 0xf5,
38500   0xfc, 0x72, 0xed, 0x6e, 0xf1, 0x79, 0x7b, 0xf3, 0x70, 0xef, 0x74, 0xfa,
38501   0xfc, 0x78, 0xf3, 0x73, 0xf4, 0x79, 0xfc, 0xfa, 0x77, 0xf3, 0x74, 0xf4,
38502   0x7a, 0xfe, 0xf7, 0x73, 0xef, 0x71, 0xf7, 0x7e, 0x76, 0xef, 0x6e, 0xef,
38503   0x75, 0x7d, 0xf3, 0x6d, 0xec, 0x6e, 0xf7, 0xfa, 0x6e, 0xeb, 0x6b, 0xef,
38504   0x79, 0x74, 0xed, 0x69, 0xeb, 0x6f, 0x7e, 0xf1, 0x6a, 0xea, 0x6c, 0xf6,
38505   0xfa, 0x6e, 0xeb, 0x6a, 0xef, 0x7a, 0x76, 0xee, 0x6b, 0xed, 0x72, 0xfe,
38506   0xf4, 0x6e, 0xed, 0x6f, 0xf6, 0xfd, 0x75, 0xef, 0x6f, 0xf1, 0x79, 0x7e,
38507   0xf6, 0x75, 0xf1, 0x76, 0xf8, 0xfd, 0x7a, 0xf5, 0x74, 0xf2, 0x76, 0xf8,
38508   0x7e, 0x7a, 0xf6, 0x71, 0xec, 0x76, 0xfa, 0x7e, 0x7b, 0xf9, 0x72, 0xf5,
38509   0x7d, 0xfb, 0xfb, 0x76, 0xf9, 0x75, 0x7b, 0xf1, 0x77, 0xfe, 0x7a, 0xfb,
38510   0x7e, 0x73, 0xfa, 0x7e, 0xfb, 0x7d, 0x77, 0xf7, 0x7e, 0x7c, 0xfe, 0x78,
38511   0xfa, 0x7e, 0xff, 0x7e, 0x76, 0xf9, 0xfd, 0xf9, 0xfe, 0x75, 0xf1, 0x76,
38512   0x7c, 0xfc, 0x7a, 0xf3, 0x70, 0xfd, 0x7e, 0x7d, 0xf3, 0x70, 0xf7, 0x78,
38513   0x7e, 0xf9, 0x72, 0xef, 0x77, 0xfc, 0xfd, 0x75, 0xee, 0x72, 0xf7, 0xfb
38514 #endif
38515 };
38516 
38517 static short MuLawDecompressTable[256] =
38518 {
38519      -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
38520      -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
38521      -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
38522      -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
38523       -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
38524       -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
38525       -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
38526       -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
38527       -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
38528       -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
38529        -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
38530        -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
38531        -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
38532        -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
38533        -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
38534         -56,   -48,   -40,   -32,   -24,   -16,    -8,     -1,
38535       32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
38536       23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
38537       15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
38538       11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
38539        7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
38540        5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
38541        3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
38542        2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
38543        1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
38544        1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
38545         876,   844,   812,   780,   748,   716,   684,   652,
38546         620,   588,   556,   524,   492,   460,   428,   396,
38547         372,   356,   340,   324,   308,   292,   276,   260,
38548         244,   228,   212,   196,   180,   164,   148,   132,
38549         120,   112,   104,    96,    88,    80,    72,    64,
38550          56,    48,    40,    32,    24,    16,     8,     0
38551 };
38552 
38553 
vt_bell(VT * vt)38554 void vt_bell (VT *vt)
38555 {
38556   if (vt->bell < 2)
38557     return;
38558   for (int i = 0; i < (int)sizeof (vt_bell_audio); i++)
38559   {
38560     int16_t val = MuLawDecompressTable[vt_bell_audio[i]] * vt->bell / 8;
38561     terminal_queue_pcm (val, val);
38562   }
38563 }
38564 
38565 
38566 void terminal_queue_pcm (int16_t sample_left, int16_t sample_right);
38567 
vt_audio(VT * vt,const char * command)38568 void vt_audio (VT *vt, const char *command)
38569 {
38570   AudioState *audio = &vt->audio;
38571   // the simplest form of audio is raw audio
38572   // _As=8000,c=2,b=8,e=u
38573   //
38574   // multiple voices:
38575   //   ids to queue - store samples as images...
38576   //
38577   // reusing samples
38578   //   .. pitch bend and be able to do a mod player?
38579   const char *payload = NULL;
38580   char key = 0;
38581   int  value;
38582   int  pos = 1;
38583 
38584   audio->frames=0;
38585   audio->action='t';
38586 
38587   int configure = 0;
38588   while (command[pos] != ';')
38589   {
38590     pos ++; // G or ,
38591     if (command[pos] == ';') break;
38592     key = command[pos]; pos++;
38593     if (command[pos] == ';') break;
38594     pos ++; // =
38595     if (command[pos] == ';') break;
38596 
38597     if (command[pos] >= '0' && command[pos] <= '9')
38598       value = atoi(&command[pos]);
38599     else
38600       value = command[pos];
38601     while (command[pos] &&
38602            command[pos] != ',' &&
38603            command[pos] != ';') pos++;
38604 
38605     if (value=='?')
38606     {
38607       char buf[256];
38608       const char *range="";
38609       switch (key)
38610       {
38611         case 's':range="8000,16000,24000,48000";break;
38612         case 'b':range="8,16";break;
38613         case 'B':range="512-65536";break;
38614         case 'c':range="1";break;
38615         case 'T':range="u,s,f";break;
38616         case 'e':range="b,a";break;
38617         case 'o':range="z,0";break;
38618         case 'a':range="t,q";break;
38619         default:range="unknown";break;
38620       }
38621       sprintf (buf, "\033_A%c=?;%s\033\\", key, range);
38622       vt_write (vt, buf, strlen(buf));
38623       return;
38624     }
38625 
38626     switch (key)
38627     {
38628       case 's': audio->samplerate = value; configure = 1; break;
38629       case 'b': audio->bits = value; configure = 1; break;
38630       case 'B': audio->buffer_size = value; configure = 1; break;
38631       case 'c': audio->channels = value; configure = 1; break;
38632       case 'a': audio->action = value; configure = 1; break;
38633       case 'T': audio->type = value; configure = 1; break;
38634       case 'f': audio->frames = value; configure = 1; break;
38635       case 'e': audio->encoding = value; configure = 1; break;
38636       case 'o': audio->compression = value; configure = 1; break;
38637       case 'm':
38638         audio->mic = value?1:0;
38639         break;
38640     }
38641 
38642     if (configure)
38643     {
38644       /* these are the specific sample rates supported by opus,
38645        * instead of enabling anything SDL supports, the initial
38646        * implementation limits itself to the opus sample rates
38647        */
38648       if (audio->samplerate <= 8000)
38649       {
38650         audio->samplerate = 8000;
38651       }
38652       else if (audio->samplerate <= 16000)
38653       {
38654         audio->samplerate = 16000;
38655       }
38656       else if (audio->samplerate <= 24000)
38657       {
38658         audio->samplerate = 24000;
38659       }
38660       else
38661       {
38662         audio->samplerate = 48000;
38663       }
38664 
38665       if (audio->bits != 8 && audio->bits != 16)
38666         audio->bits = 8;
38667 
38668       if (audio->buffer_size > 2048)
38669         audio->buffer_size = 2048;
38670       else if (audio->buffer_size < 512)
38671         audio->buffer_size = 512;
38672 
38673       switch (audio->type)
38674       {
38675         case 'u':
38676         case 's':
38677         case 'f':
38678           break;
38679         default:
38680           audio->type = 's';
38681       }
38682 
38683       /* only 1 and 2 channels supported */
38684       if (audio->channels <= 0 || audio->channels > 2)
38685       {
38686         audio->channels = 1;
38687       }
38688     }
38689   }
38690 
38691   if (audio->frames ||  audio->action != 'd')
38692   {
38693   payload = &command[pos+1];
38694 
38695   // accumulate incoming data
38696   {
38697      int chunk_size = strlen (payload);
38698      int old_size = audio->data_size;
38699      if (audio->data == NULL)
38700      {
38701        audio->data_size = chunk_size;
38702        audio->data = malloc (audio->data_size + 1);
38703      }
38704      else
38705      {
38706        audio->data_size += chunk_size;
38707        audio->data = realloc (audio->data, audio->data_size + 1);
38708      }
38709      memcpy (audio->data + old_size, payload, chunk_size);
38710      audio->data[audio->data_size]=0;
38711   }
38712 
38713     if (audio->frames)
38714     switch (audio->encoding)
38715     {
38716       case 'y':
38717         audio->data_size = ydec (audio->data, audio->data, audio->data_size);
38718       break;
38719       case 'a':
38720       {
38721         int bin_length = audio->data_size;
38722         if (bin_length)
38723         {
38724         uint8_t *data2 = malloc ((unsigned int)ctx_a85len ((char*)audio->data, audio->data_size) + 1);
38725         // a85len is inaccurate but gives an upper bound,
38726         // should be fixed.
38727         bin_length = ctx_a85dec ((char*)audio->data,
38728                                  (void*)data2,
38729                                  bin_length);
38730         free (audio->data);
38731         audio->data = data2;
38732         audio->data_size = bin_length;
38733         }
38734       }
38735       break;
38736 
38737       case 'b':
38738       {
38739         int bin_length = audio->data_size;
38740         uint8_t *data2 = malloc (audio->data_size);
38741         bin_length = ctx_base642bin ((char*)audio->data,
38742                                      &bin_length,
38743                                      data2);
38744         memcpy (audio->data, data2, bin_length + 1);
38745         audio->data_size = bin_length;
38746         free (data2);
38747       }
38748       break;
38749     }
38750 
38751     if (audio->frames)
38752     switch (audio->compression)
38753     {
38754       case 'z':
38755     {
38756       unsigned long actual_uncompressed_size = audio->frames * audio->bits/8 * audio->channels + 512;
38757       unsigned char *data2 = malloc (actual_uncompressed_size);
38758       /* if a buf size is set (rather compression, but
38759        * this works first..) then */
38760       int z_result = uncompress (data2, &actual_uncompressed_size,
38761                                  audio->data,
38762                                  audio->data_size);
38763       if (z_result != Z_OK)
38764       {
38765        // fprintf (stderr, "[z error %i %i]", __LINE__, z_result);
38766       }
38767 
38768 #if 0
38769       // XXX : we seem to get buf-error (-5) here, which indicates not enough
38770       //       space in output buffer, which is odd
38771       //
38772       //       it is non fatal though so we ignore it and use the validly
38773       //       decompressed bits.
38774       {
38775         char buf[256];
38776         sprintf (buf, "\e_Ao=z;zlib error1 %i\e\\", z_result);
38777         vt_write (vt, buf, strlen(buf));
38778         //goto cleanup;
38779       }
38780 #endif
38781       free (audio->data);
38782       audio->data = data2;
38783       audio->data_size = actual_uncompressed_size;
38784     }
38785 
38786         break;
38787       case 'o':
38788         break;
38789       default:
38790         break;
38791     }
38792 
38793     if (audio->frames == 0)
38794     {
38795       /* implicit frame count */
38796       audio->frames = audio->data_size /
38797                                 (audio->bits/8) /
38798                                    audio->channels;
38799     }
38800 
38801 
38802 #if 0
38803     if (audio->format == 100/* opus */)
38804     {
38805       int channels;
38806       uint8_t *new_data = NULL;//stbi_load_from_memory (audio->data, audio->data_size, &audio->buf_width, &audio->buf_height, &channels, 4);
38807 
38808       if (!new_data)
38809       {
38810         char buf[256]= "\e_Gf=100;audio decode error\e\\";
38811         vt_write (vt, buf, strlen(buf));
38812         goto cleanup;
38813       }
38814       audio->format = 32;
38815       free (audio->data);
38816       audio->data = new_data;
38817       audio->data_size = audio->buf_width * audio->buf_height * 4;
38818     }
38819 #endif
38820 
38821   switch (audio->action)
38822   {
38823     case 't': // transfer
38824        if (audio->type == 'u') // implied 8bit
38825        {
38826          if (audio->channels == 2)
38827          {
38828            for (int i = 0; i < audio->frames; i++)
38829            {
38830              int val_left = MuLawDecompressTable[audio->data[i*2]];
38831              int val_right = MuLawDecompressTable[audio->data[i*2+1]];
38832              terminal_queue_pcm (val_left, val_right);
38833            }
38834          }
38835          else
38836          {
38837            for (int i = 0; i < audio->frames; i++)
38838            {
38839              int val = MuLawDecompressTable[audio->data[i]];
38840              terminal_queue_pcm (val, val);
38841            }
38842          }
38843        }
38844        else if (audio->type == 's')
38845        {
38846          if (audio->bits == 8)
38847          {
38848            if (audio->channels == 2)
38849            {
38850              for (int i = 0; i < audio->frames; i++)
38851              {
38852                int val_left = 256*((int8_t*)(audio->data))[i*2];
38853                int val_right = 256*((int8_t*)(audio->data))[i*2+1];
38854                terminal_queue_pcm (val_left, val_right);
38855              }
38856            }
38857            else
38858            {
38859              for (int i = 0; i < audio->frames; i++)
38860              {
38861                int val = 256*((int8_t*)(audio->data))[i];
38862                terminal_queue_pcm (val, val);
38863              }
38864            }
38865          }
38866          else
38867          {
38868            if (audio->channels == 2)
38869            {
38870              for (int i = 0; i < audio->frames; i++)
38871              {
38872                int val_left = ((int16_t*)(audio->data))[i*2];
38873                int val_right = ((int16_t*)(audio->data))[i*2+1];
38874                terminal_queue_pcm (val_left, val_right);
38875              }
38876            }
38877            else
38878            {
38879              for (int i = 0; i < audio->frames; i++)
38880              {
38881                int val = ((int16_t*)(audio->data))[i];
38882                terminal_queue_pcm (val, val);
38883              }
38884            }
38885          }
38886        }
38887        free (audio->data);
38888        audio->data = NULL;
38889        audio->data_size=0;
38890        break;
38891     case 'q': // query
38892        {
38893          char buf[512];
38894          sprintf (buf, "\033_As=%i,b=%i,c=%i,T=%c,B=%i,e=%c,o=%c;OK\033\\",
38895       audio->samplerate, audio->bits, audio->channels, audio->type,
38896       audio->buffer_size,
38897       audio->encoding?audio->encoding:'0',
38898       audio->compression?audio->compression:'0'
38899       /*audio->transmission*/);
38900 
38901          vt_write (vt, buf, strlen(buf));
38902        }
38903       break;
38904   }
38905   }
38906 
38907 //cleanup:
38908     if (audio->data)
38909       free (audio->data);
38910     audio->data = NULL;
38911     audio->data_size=0;
38912 }
38913 #endif
38914 /* DEC terminals/xterm family terminal with ANSI, utf8, vector graphics and
38915  * audio.
38916  *
38917  * Copyright (c) 2014, 2016, 2018, 2020 Øyvind Kolås <pippin@gimp.org>
38918  *
38919  * Adhering to the standards with modern extensions.
38920  *
38921  * Features:
38922  *     vt100 - 101 points on scoresheet
38923  *     UTF8, cp437
38924  *     dim, bold, strikethrough, underline, italic, reverse
38925  *     ANSI colors, 256 colors (non-redefineable), 24bit color
38926  *     realtime audio transmission
38927  *     raster sprites (kitty spec)
38928  *     vector graphics
38929  *     vt320 - horizontal margins
38930  *     proportional fonts
38931  *
38932  *     BBS/ANSI-art mode
38933  *
38934  * 8bit clean
38935  *
38936  *
38937  * Todo:
38938  *     DECCIR - cursor state report https://vt100.net/docs/vt510-rm/DECCIR.html
38939  *     make absolute positioning take proportional into account
38940  *     HTML / PNG / SVG / PDF export of scrollback / screen
38941  *     sixels
38942  *
38943  */
38944 
38945 #if !__COSMOPOLITAN__
38946 #include <sys/stat.h>
38947 #include <sys/types.h>
38948 #include <sys/wait.h>
38949 #include <errno.h>
38950 #include <assert.h>
38951 
38952 #include <string.h>
38953 #include <signal.h>
38954 #include <stdlib.h>
38955 #include <stdio.h>
38956 #include <stdarg.h>
38957 #include <ctype.h>
38958 #include <unistd.h>
38959 #include <fcntl.h>
38960 #include <sys/stat.h>
38961 #include <sys/time.h>
38962 #include <sys/ioctl.h>
38963 #include <termios.h>
38964 #include <zlib.h>
38965 #endif
38966 
38967 #include "ctx.h"
38968 
38969 
38970 #define CTX_VT_USE_FRAMEDIFF 0  // is a larger drain than neccesary when everything is per-byte?
38971                                 // is anyways currently disabled also in ctx
38972 
38973 //#define STB_IMAGE_IMPLEMENTATION
38974 //#include "stb_image.h"
38975 
38976 //#include "vt-line.h"
38977 //#include "vt.h"
38978 //#include "ctx-clients.h"
38979 
38980 
38981 
38982 #define VT_LOG_INFO     (1<<0)
38983 #define VT_LOG_CURSOR   (1<<1)
38984 #define VT_LOG_COMMAND  (1<<2)
38985 #define VT_LOG_WARNING  (1<<3)
38986 #define VT_LOG_ERROR    (1<<4)
38987 #define VT_LOG_INPUT    (1<<5)
38988 #define VT_LOG_ALL       0xff
38989 
38990 static int vt_log_mask = VT_LOG_INPUT;
38991 //static int vt_log_mask = VT_LOG_WARNING | VT_LOG_ERROR;// | VT_LOG_COMMAND;// | VT_LOG_INFO | VT_LOG_COMMAND;
38992 //static int vt_log_mask = VT_LOG_WARNING | VT_LOG_ERROR | VT_LOG_INFO | VT_LOG_COMMAND | VT_LOG_INPUT;
38993 //static int vt_log_mask = VT_LOG_ALL;
38994 
38995 #if 0
38996 #define vt_log(domain, fmt, ...)
38997 
38998 #define VT_input(str, ...)
38999 #define VT_info(str, ...)
39000 #define VT_command(str, ...)
39001 #define VT_cursor(str, ...)
39002 #define VT_warning(str, ...)
39003 #define VT_error(str, ...)
39004 #else
39005 #define vt_log(domain, line, a...) \
39006         do {fprintf (stderr, "%i %s ", line, domain);fprintf(stderr, ##a);fprintf(stderr, "\n");}while(0)
39007 #define VT_info(a...) if (vt_log_mask & VT_LOG_INFO) vt_log ("INFO  ", __LINE__, ##a)
39008 #define VT_input(a...) if (vt_log_mask & VT_LOG_INPUT) vt_log ("INPUT ", __LINE__, ##a)
39009 #define VT_command(a...) if (vt_log_mask & VT_LOG_COMMAND) vt_log ("CMD   ", __LINE__, ##a)
39010 #define VT_cursor(a...) if (vt_log_mask & VT_LOG_CURSOR) vt_log ("CURSOR",__LINE__, ##a)
39011 #define VT_warning(a...) if (vt_log_mask & VT_LOG_WARNING) vt_log ("WARN  ",__LINE__, ##a)
39012 #define VT_error(a...) if (vt_log_mask & VT_LOG_ERROR) vt_log ("ERROR",__LINE__, ##a)
39013 
39014 #endif
39015 
39016 #ifndef MIN
39017 #define MIN(a,b)  ((a)<(b)?(a):(b))
39018 #endif
39019 
39020 static void vt_state_neutral      (VT *vt, int byte);
39021 static void vt_state_esc          (VT *vt, int byte);
39022 static void vt_state_osc          (VT *vt, int byte);
39023 static void vt_state_apc          (VT *vt, int byte);
39024 static void vt_state_apc_generic  (VT *vt, int byte);
39025 static void vt_state_sixel        (VT *vt, int byte);
39026 static void vt_state_esc_sequence (VT *vt, int byte);
39027 static void vt_state_esc_foo      (VT *vt, int byte);
39028 static void vt_state_swallow      (VT *vt, int byte);
39029 static void vt_state_ctx          (VT *vt, int byte);
39030 static void vt_state_vt52         (VT *vt, int byte);
39031 
39032 #if 0
39033 /* barebones linked list */
39034 
39035 typedef struct _CtxList CtxList;
39036 struct _CtxList
39037 {
39038   void *data;
39039   CtxList *next;
39040 };
39041 
39042 static inline int ctx_list_length (CtxList *list)
39043 {
39044   int length = 0;
39045   for (CtxList *l = list; l; l = l->next, length++);
39046   return length;
39047 }
39048 
39049 static inline void ctx_list_prepend (CtxList **list, void *data)
39050 {
39051   CtxList *new_=calloc (sizeof (CtxList), 1);
39052   new_->next = *list;
39053   new_->data = data;
39054   *list = new_;
39055 }
39056 
39057 static inline void *ctx_list_last (CtxList *list)
39058 {
39059   if (list)
39060     {
39061       CtxList *last;
39062       for (last = list; last->next; last=last->next);
39063       return last->data;
39064     }
39065   return NULL;
39066 }
39067 
39068 static inline void ctx_list_append (CtxList **list, void *data)
39069 {
39070   CtxList *new_= calloc (sizeof (CtxList), 1);
39071   new_->data=data;
39072   if (*list)
39073     {
39074       CtxList *last;
39075       for (last = *list; last->next; last=last->next);
39076       last->next = new_;
39077       return;
39078     }
39079   *list = new_;
39080   return;
39081 }
39082 
39083 static inline void ctx_list_remove (CtxList **list, void *data)
39084 {
39085   CtxList *iter, *prev = NULL;
39086   if ( (*list)->data == data)
39087     {
39088       prev = (void *) (*list)->next;
39089       free (*list);
39090       *list = prev;
39091       return;
39092     }
39093   for (iter = *list; iter; iter = iter->next)
39094     if (iter->data == data)
39095       {
39096         prev->next = iter->next;
39097         free (iter);
39098         break;
39099       }
39100     else
39101       { prev = iter; }
39102 }
39103 
39104 static inline void
39105 ctx_list_insert_before (CtxList **list, CtxList *sibling,
39106                        void *data)
39107 {
39108   if (*list == NULL || *list == sibling)
39109     {
39110       ctx_list_prepend (list, data);
39111     }
39112   else
39113     {
39114       CtxList *prev = NULL;
39115       for (CtxList *l = *list; l; l=l->next)
39116         {
39117           if (l == sibling)
39118             { break; }
39119           prev = l;
39120         }
39121       if (prev)
39122         {
39123           CtxList *new_=calloc (sizeof (CtxList), 1);
39124           new_->next = sibling;
39125           new_->data = data;
39126           prev->next=new_;
39127         }
39128     }
39129 }
39130 #endif
39131 
39132 
39133 typedef enum
39134 {
39135   STYLE_REVERSE         = 1 << 0,
39136   STYLE_BOLD            = 1 << 1,
39137   STYLE_BLINK           = 1 << 2,
39138   STYLE_UNDERLINE       = 1 << 3,
39139   STYLE_DIM             = 1 << 4,
39140   STYLE_HIDDEN          = 1 << 5,
39141   STYLE_ITALIC          = 1 << 6,
39142   STYLE_UNDERLINE_VAR   = 1 << 7,
39143   STYLE_STRIKETHROUGH   = 1 << 8,
39144   STYLE_OVERLINE        = 1 << 9,
39145   STYLE_BLINK_FAST      = 1 << 10,
39146   STYLE_PROPORTIONAL    = 1 << 11,
39147   STYLE_FG_COLOR_SET    = 1 << 12,
39148   STYLE_BG_COLOR_SET    = 1 << 13,
39149   STYLE_FG24_COLOR_SET  = 1 << 14,
39150   STYLE_BG24_COLOR_SET  = 1 << 15,
39151   //STYLE_NONERASABLE     = 1 << 16  // needed for selective erase
39152 } TerminalStyle;
39153 
39154 typedef struct Image
39155 {
39156   int kitty_format;
39157   int width;
39158   int height;
39159   int id;
39160   int eid_no;
39161   int size;
39162   uint8_t *data;
39163 } Image;
39164 
39165 #define MAX_IMAGES 128
39166 
39167 static Image image_db[MAX_IMAGES]= {{0,},};
39168 
image_query(int id)39169 static Image *image_query (int id)
39170 {
39171   for (int i = 0; i < MAX_IMAGES; i++)
39172     {
39173       Image *image = &image_db[i];
39174       if (image->id == id)
39175         { return image; }
39176     }
39177   return NULL;
39178 }
39179 
39180 static int image_eid_no = 0;
39181 
image_add(int width,int height,int id,int format,int size,uint8_t * data)39182 static Image *image_add (int width,
39183                          int height,
39184                          int id,
39185                          int format,
39186                          int size,
39187                          uint8_t *data)
39188 {
39189   // look for id if id is not 0
39190   Image *image;
39191   for (int i = 0; i < MAX_IMAGES; i++)
39192     {
39193       image = &image_db[i];
39194       if (image->data == NULL)
39195         { break; }
39196     }
39197   if (image->data)
39198     {
39199       // not a good eviction strategy
39200       image = &image_db[random() %MAX_IMAGES];
39201     }
39202   if (image->data)
39203     { free (image->data); }
39204   image->kitty_format = format;
39205   image->width  = width;
39206   image->height = height;
39207   image->id     = id;
39208   image->size   = size;
39209   image->data   = data;
39210   image->eid_no = image_eid_no++;
39211   return image;
39212 }
39213 
vtpty_resize(void * data,int cols,int rows,int px_width,int px_height)39214 void vtpty_resize (void *data, int cols, int rows, int px_width, int px_height)
39215 {
39216   VtPty *vtpty = data;
39217   struct winsize ws;
39218   ws.ws_row = rows;
39219   ws.ws_col = cols;
39220   ws.ws_xpixel = px_width;
39221   ws.ws_ypixel = px_height;
39222   ioctl (vtpty->pty, TIOCSWINSZ, &ws);
39223 }
39224 
vtpty_write(void * data,const void * buf,size_t count)39225 ssize_t vtpty_write (void *data, const void *buf, size_t count)
39226 {
39227   VtPty *vtpty = data;
39228   return write (vtpty->pty, buf, count);
39229 }
39230 
vtpty_read(void * data,void * buf,size_t count)39231 ssize_t vtpty_read (void  *data, void *buf, size_t count)
39232 {
39233   VtPty *vtpty = data;
39234   return read (vtpty->pty, buf, count);
39235 }
39236 
vtpty_waitdata(void * data,int timeout)39237 int vtpty_waitdata (void  *data, int timeout)
39238 {
39239   VtPty *vtpty = data;
39240   struct timeval tv;
39241   fd_set fdset;
39242   FD_ZERO (&fdset);
39243   FD_SET (vtpty->pty, &fdset);
39244   tv.tv_sec = 0;
39245   tv.tv_usec = timeout;
39246   tv.tv_sec  = timeout / 1000000;
39247   tv.tv_usec = timeout % 1000000;
39248   if (select (vtpty->pty+1, &fdset, NULL, NULL, &tv) == -1)
39249     {
39250       perror ("select");
39251       return 0;
39252     }
39253   if (FD_ISSET (vtpty->pty, &fdset) )
39254     {
39255       return 1;
39256     }
39257   return 0;
39258 }
39259 
39260 
39261 /* on current line */
vt_col_to_pos(VT * vt,int col)39262 static int vt_col_to_pos (VT *vt, int col)
39263 {
39264   int pos = col;
39265   if (vt->current_line->contains_proportional)
39266     {
39267       Ctx *ctx = ctx_new ();
39268       ctx_font (ctx, "regular");
39269       ctx_font_size (ctx, vt->font_size);
39270       int x = 0;
39271       pos = 0;
39272       int prev_prop = 0;
39273       while (x <= col * vt->cw)
39274         {
39275           if (vt_line_get_style (vt->current_line, pos) & STYLE_PROPORTIONAL)
39276             {
39277               x += ctx_glyph_width (ctx, vt_line_get_unichar (vt->current_line, pos) );
39278               prev_prop = 1;
39279             }
39280           else
39281             {
39282               if (prev_prop)
39283                 {
39284                   int new_cw = vt->cw - ( (x % vt->cw) );
39285                   if (new_cw < vt->cw*3/2)
39286                     { new_cw += vt->cw; }
39287                   x += new_cw;
39288                 }
39289               else
39290                 {
39291                   x += vt->cw;
39292                 }
39293               prev_prop = 0;
39294             }
39295           pos ++;
39296         }
39297       pos --;
39298       ctx_free (ctx);
39299     }
39300   return pos;
39301 }
39302 
vt_margin_left(VT * vt)39303 static int vt_margin_left (VT *vt)
39304 {
39305   int left = vt->left_right_margin_mode?vt->margin_left:1;
39306   return vt_col_to_pos (vt, left);
39307 }
39308 
39309 #define VT_MARGIN_LEFT vt_margin_left(vt)
39310 
vt_margin_right(VT * vt)39311 static int vt_margin_right (VT *vt)
39312 {
39313   int right = vt->left_right_margin_mode?vt->margin_right:vt->cols;
39314   return vt_col_to_pos (vt, right);
39315 }
39316 
39317 #define VT_MARGIN_RIGHT vt_margin_right(vt)
39318 
39319 
vt_rev_inc(VT * vt)39320 void vt_rev_inc (VT *vt)
39321 {
39322   if (vt)
39323     vt->rev++;
39324 }
39325 
vt_rev(VT * vt)39326 long vt_rev (VT *vt)
39327 {
39328   return vt?vt->rev:0;
39329 }
39330 
39331 static void vtcmd_reset_to_initial_state (VT *vt, const char *sequence);
39332 int vt_set_prop (VT *vt, uint32_t key_hash, const char *val);
39333 uint32_t ctx_strhash (const char *utf8);
39334 
vt_set_title(VT * vt,const char * new_title)39335 static void vt_set_title (VT *vt, const char *new_title)
39336 {
39337   if (vt->inert) return;
39338 
39339   if (vt->title)
39340     { free (vt->title); }
39341   vt->title = strdup (new_title);
39342   vt_set_prop (vt, ctx_strhash ("title"), (char*)new_title);
39343 }
39344 
vt_get_title(VT * vt)39345 const char *vt_get_title (VT *vt)
39346 {
39347   return vt->title;
39348 }
39349 
39350 static void vt_run_command (VT *vt, const char *command, const char *term);
39351 static void vtcmd_set_top_and_bottom_margins (VT *vt, const char *sequence);
39352 static void vtcmd_set_left_and_right_margins (VT *vt, const char *sequence);
39353 static void _vt_move_to (VT *vt, int y, int x);
39354 
vtcmd_clear(VT * vt,const char * sequence)39355 static void vtcmd_clear (VT *vt, const char *sequence)
39356 {
39357   while (vt->lines)
39358     {
39359       vt_line_free (vt->lines->data, 1);
39360       ctx_list_remove (&vt->lines, vt->lines->data);
39361     }
39362   vt->lines = NULL;
39363   vt->line_count = 0;
39364 
39365   if (1)
39366   { /* TODO: detect if this is neccesary.. due to images present
39367              in lines in scrollback */
39368     for (int i=0; i<vt->rows; i++)
39369     {
39370       vt->current_line = vt_line_new_with_size ("", vt->cols);
39371       ctx_list_prepend (&vt->scrollback, vt->current_line);
39372       vt->scrollback_count++;
39373     }
39374   }
39375 
39376   /* populate lines */
39377   for (int i=0; i<vt->rows; i++)
39378     {
39379       vt->current_line = vt_line_new_with_size ("", vt->cols);
39380       ctx_list_prepend (&vt->lines, vt->current_line);
39381       vt->line_count++;
39382     }
39383 }
39384 
39385 #define set_fg_rgb(r, g, b) \
39386     vt->cstyle ^= (vt->cstyle & (((uint64_t)((1l<<24)-1))<<16));\
39387     vt->cstyle |=  ((uint64_t)(r)<<16);\
39388     vt->cstyle |=  ((uint64_t)(g)<<(16+8));\
39389     vt->cstyle |=  ((uint64_t)(b)<<(16+8+8));\
39390     vt->cstyle |= STYLE_FG_COLOR_SET;\
39391     vt->cstyle |= STYLE_FG24_COLOR_SET;\
39392 
39393 #define set_bg_rgb(r, g, b) \
39394     vt->cstyle ^= (vt->cstyle & (((uint64_t)((1l<<24)-1))<<40));\
39395     vt->cstyle |=  ((uint64_t)(r)<<40);\
39396     vt->cstyle |=  ((uint64_t)(g)<<(40+8));\
39397     vt->cstyle |=  ((uint64_t)(b)<<(40+8+8));\
39398     vt->cstyle |= STYLE_BG_COLOR_SET;\
39399     vt->cstyle |= STYLE_BG24_COLOR_SET;\
39400 
39401 #define set_fg_idx(idx) \
39402     vt->cstyle ^= (vt->cstyle & (((uint64_t)((1l<<24)-1))<<16));\
39403     vt->cstyle ^= (vt->cstyle & STYLE_FG24_COLOR_SET);\
39404     vt->cstyle |=  ((idx)<<16);\
39405     vt->cstyle |= STYLE_FG_COLOR_SET;
39406 
39407 #define set_bg_idx(idx) \
39408     vt->cstyle ^= (vt->cstyle & (((uint64_t)((1l<<24)-1))<<40));\
39409     vt->cstyle ^= (vt->cstyle & STYLE_BG24_COLOR_SET);\
39410     vt->cstyle |= ((int64_t)(idx)<<40) ;\
39411     vt->cstyle |= STYLE_BG_COLOR_SET;
39412 
39413 
_vt_compute_cw_ch(VT * vt)39414 static void _vt_compute_cw_ch (VT *vt)
39415 {
39416   vt->cw = (vt->font_size / vt->line_spacing * vt->scale_x) + 0.99;
39417   vt->ch = vt->font_size;
39418 }
39419 
vtcmd_set_132_col(VT * vt,int set)39420 static void vtcmd_set_132_col (VT  *vt, int set)
39421 {
39422   // this should probably force the window as well
39423   if (set == 0 && vt->scale_x == 1.0f) return;
39424   if (set == 1 && vt->scale_x != 1.0f) return;
39425   if (set) // 132 col
39426     {
39427       vt->scale_x = 74.0/132.0; // show all - po
39428       //vt->scale_x = 80.0/132.0;
39429       vt->scale_y = 1.0;
39430       _vt_compute_cw_ch (vt);
39431       vt_set_term_size (vt, vt->cols * 132/80.0, vt->rows);
39432     }
39433   else // 80 col
39434     {
39435       vt->scale_x = 1.0;
39436       vt->scale_y = 1.0;
39437       _vt_compute_cw_ch (vt);
39438       vt_set_term_size (vt, vt->cols * 80/132.0, vt->rows);
39439     }
39440 }
39441 
39442 static void vt_line_feed (VT *vt);
39443 static void vt_carriage_return (VT *vt);
39444 
39445 static int vt_trimlines (VT *vt, int max);
vtcmd_reset_to_initial_state(VT * vt,const char * sequence)39446 static void vtcmd_reset_to_initial_state (VT *vt, const char *sequence)
39447 {
39448   VT_info ("reset %s", sequence);
39449   if (getenv ("VT_DEBUG") )
39450     { vt->debug = 1; }
39451   vtcmd_clear (vt, sequence);
39452   vt->encoding = 0;
39453   vt->bracket_paste = 0;
39454   vt->ctx_events = 0;
39455   vt->cr_on_lf = 0;
39456   vtcmd_set_top_and_bottom_margins (vt, "[r");
39457   vtcmd_set_left_and_right_margins (vt, "[s");
39458   vt->autowrap               = 1;
39459   vt->justify                = 0;
39460   vt->cursor_visible         = 1;
39461   vt->charset[0]             = 0;
39462   vt->charset[1]             = 0;
39463   vt->charset[2]             = 0;
39464   vt->charset[3]             = 0;
39465   vt->bell                   = 3;
39466   vt->scale_x                = 1.0;
39467   vt->scale_y                = 1.0;
39468   vt->saved_x                = 1;
39469   vt->saved_y                = 1;
39470   vt->saved_style            = 1;
39471   vt->reverse_video          = 0;
39472   vt->cstyle                 = 0;
39473   vt->keyrepeat              = 1;
39474   vt->cursor_key_application = 0;
39475   vt->argument_buf_len       = 0;
39476   vt->argument_buf[0]        = 0;
39477   vt->vtpty.done             = 0;
39478   vt->result                 = -1;
39479   vt->state                  = vt_state_neutral;
39480   vt->scroll_on_output       = 0;
39481   vt->scroll_on_input        = 1;
39482   vt->unit_pixels            = 0;
39483   vt->mouse                  = 0;
39484   vt->mouse_drag             = 0;
39485   vt->mouse_all              = 0;
39486   vt->mouse_decimal          = 0;
39487   _vt_compute_cw_ch (vt);
39488   for (int i = 0; i < MAX_COLS; i++)
39489     { vt->tabs[i] = i % 8 == 0? 1 : 0; }
39490   _vt_move_to (vt, vt->margin_top, vt->cursor_x);
39491   vt_carriage_return (vt);
39492   //if (vt->ctx)
39493   //  { ctx_reset (vt->ctx); }
39494   vt->audio.bits = 8;
39495   vt->audio.channels = 1;
39496   vt->audio.type = 'u';
39497   vt->audio.samplerate = 8000;
39498   vt->audio.buffer_size = 1024;
39499   vt->audio.encoding = 'a';
39500   vt->audio.compression = '0';
39501   vt->audio.mic = 0;
39502   while (vt->scrollback)
39503     {
39504       vt_line_free (vt->scrollback->data, 1);
39505       ctx_list_remove (&vt->scrollback, vt->scrollback->data);
39506     }
39507   vt->scrollback_count = 0;
39508 }
39509 
vt_set_font_size(VT * vt,float font_size)39510 void vt_set_font_size (VT *vt, float font_size)
39511 {
39512   vt->font_size = font_size;
39513   _vt_compute_cw_ch (vt);
39514 }
39515 
vt_get_font_size(VT * vt)39516 float       vt_get_font_size      (VT *vt)
39517 {
39518   return vt->font_size;
39519 }
39520 
vt_set_line_spacing(VT * vt,float line_spacing)39521 void vt_set_line_spacing (VT *vt, float line_spacing)
39522 {
39523   vt->line_spacing = line_spacing;
39524   _vt_compute_cw_ch (vt);
39525 }
39526 
vt_new(const char * command,int width,int height,float font_size,float line_spacing,int id,int can_launch)39527 VT *vt_new (const char *command, int width, int height, float font_size, float line_spacing, int id, int can_launch)
39528 {
39529   VT *vt                 = calloc (sizeof (VT), 1);
39530   vt->id                 = id;
39531   vt->lastx              = -1;
39532   vt->lasty              = -1;
39533   vt->state              = vt_state_neutral;
39534   vt->smooth_scroll      = 0;
39535   vt->can_launch         = can_launch;
39536   vt->scroll_offset      = 0.0;
39537   vt->waitdata           = vtpty_waitdata;
39538   vt->read               = vtpty_read;
39539   vt->write              = vtpty_write;
39540   vt->resize             = vtpty_resize;
39541   vt->font_to_cell_scale = 0.98;
39542   vt->cursor_visible     = 1;
39543   vt->lines              = NULL;
39544   vt->line_count         = 0;
39545   vt->current_line       = NULL;
39546   vt->cols               = 0;
39547   vt->rows               = 0;
39548 
39549   vt->scrollback_limit   = DEFAULT_SCROLLBACK;
39550   vt->argument_buf_len   = 0;
39551   vt->argument_buf_cap   = 64;
39552   vt->argument_buf       = malloc (vt->argument_buf_cap);
39553   vt->argument_buf[0]    = 0;
39554   vt->vtpty.done         = 0;
39555   vt->result             = -1;
39556   vt->line_spacing       = 1.0;
39557   vt->scale_x            = 1.0;
39558   vt->scale_y            = 1.0;
39559   vt_set_font_size (vt, font_size);
39560   vt_set_line_spacing (vt, line_spacing);
39561   if (command)
39562     {
39563       vt_run_command (vt, command, NULL);
39564     }
39565   if (width <= 0) width = 640;
39566   if (height <= 0) width = 480;
39567   vt_set_px_size (vt, width, height);
39568 
39569   vt->fg_color[0] = 216;
39570   vt->fg_color[1] = 216;
39571   vt->fg_color[2] = 216;
39572   vt->bg_color[0] = 0;
39573   vt->bg_color[1] = 0;
39574   vt->bg_color[2] = 0;
39575   vtcmd_reset_to_initial_state (vt, NULL);
39576   //vt->ctx = ctx_new ();
39577   ctx_list_prepend (&vts, vt);
39578   return vt;
39579 }
39580 
vt_cw(VT * vt)39581 int vt_cw (VT *vt)
39582 {
39583   return vt->cw;
39584 }
39585 
vt_ch(VT * vt)39586 int vt_ch (VT *vt)
39587 {
39588   return vt->ch;
39589 }
39590 
vt_trimlines(VT * vt,int max)39591 static int vt_trimlines (VT *vt, int max)
39592 {
39593   CtxList *chop_point = NULL;
39594   CtxList *l;
39595   int i;
39596   if (vt->line_count < max)
39597     {
39598       return 0;
39599     }
39600   for (l = vt->lines, i = 0; l && i < max-1; l = l->next, i++);
39601   if (l)
39602     {
39603       chop_point = l->next;
39604       l->next = NULL;
39605     }
39606   while (chop_point)
39607     {
39608       if (vt->in_alt_screen)
39609         {
39610           vt_line_free (chop_point->data, 1);
39611         }
39612       else
39613         {
39614           ctx_list_prepend (&vt->scrollback, chop_point->data);
39615           vt->scrollback_count ++;
39616         }
39617       ctx_list_remove (&chop_point, chop_point->data);
39618       vt->line_count--;
39619     }
39620   if (vt->scrollback_count > vt->scrollback_limit + 1024)
39621     {
39622       CtxList *l = vt->scrollback;
39623       int no = 0;
39624       while (l && no < vt->scrollback_limit)
39625         {
39626           l = l->next;
39627           no++;
39628         }
39629       chop_point = NULL;
39630       if (l)
39631         {
39632           chop_point = l->next;
39633           l->next = NULL;
39634         }
39635       while (chop_point)
39636         {
39637           vt_line_free (chop_point->data, 1);
39638           ctx_list_remove (&chop_point, chop_point->data);
39639           vt->scrollback_count --;
39640         }
39641     }
39642   return 0;
39643 }
39644 
vt_rewrap_pair(VT * vt,VtLine * topline,VtLine * bottomline,int max_col)39645 static void vt_rewrap_pair (VT *vt, VtLine *topline, VtLine *bottomline, int max_col)
39646 {
39647   int toplen = 0;
39648 
39649   while ((toplen = vt_line_get_utf8length (topline)) > max_col)
39650   {
39651      uint32_t unichar = vt_line_get_unichar (topline, toplen-1);
39652      uint32_t style =  vt_line_get_style (topline, toplen-1);
39653      vt_line_insert_unichar (bottomline, 0, unichar);
39654      vt_line_remove (topline, toplen-1);
39655      vt_line_set_style (bottomline, 0, style);
39656   }
39657 
39658   while (vt_line_get_length (bottomline) &&
39659          (toplen = vt_line_get_utf8length (topline)) < max_col)
39660   {
39661      uint32_t unichar = vt_line_get_unichar (bottomline, 0);
39662      uint32_t style =  vt_line_get_style (bottomline, 0);
39663      vt_line_append_unichar (topline, unichar);
39664      vt_line_set_style (topline, toplen, style);
39665      vt_line_remove (bottomline, 0);
39666   }
39667 }
39668 
vt_rewrap(VT * vt,int max_col)39669 static void vt_rewrap (VT *vt, int max_col)
39670 {
39671   if (max_col < 8) max_col = 8;
39672   CtxList *list = NULL;
39673 
39674   for (CtxList *l = vt->lines; l;)
39675   {
39676     CtxList *next = l->next;
39677     ctx_list_prepend (&list, l->data);
39678     ctx_list_remove (&vt->lines, l->data);
39679     l = next;
39680   }
39681   for (CtxList *l = vt->scrollback; l;)
39682   {
39683     CtxList *next = l->next;
39684     ctx_list_prepend (&list, l->data);
39685     ctx_list_remove (&vt->scrollback, l->data);
39686     l = next;
39687   }
39688 
39689   for (CtxList *l = list; l; l = l->next)
39690     {
39691       VtLine *line = l->data;
39692       VtLine *next = l->next ?l->next->data:NULL;
39693 
39694       if (vt_line_get_utf8length (line) >= max_col || (next && next->wrapped))
39695       {
39696         if (!next)
39697         {
39698           ctx_list_append (&list, vt_line_new (""));
39699           next = l->next->data;
39700           next->wrapped = 1;
39701         }
39702         else if (!next->wrapped)
39703         {
39704           ctx_list_insert_before (&list, l->next, vt_line_new (""));
39705           next = l->next->data;
39706           next->wrapped = 1;
39707         }
39708         vt_rewrap_pair (vt, line, next, max_col);
39709         if (vt_line_get_utf8length (next) == 0)
39710           ctx_list_remove (&list, l->next->data);
39711       }
39712     }
39713 
39714   int rows = vt->rows;
39715   int total_rows = ctx_list_length (list);
39716 
39717   int scrollback_rows = total_rows - rows;
39718 
39719   int c = 0;
39720   CtxList *l;
39721   for (l = list; l && c < scrollback_rows;)
39722   {
39723     CtxList *next = l->next;
39724     ctx_list_prepend (&vt->scrollback, l->data);
39725     ctx_list_remove (&list, l->data);
39726     l = next;
39727     c++;
39728   }
39729   for (; l ;)
39730   {
39731     CtxList *next = l->next;
39732     ctx_list_prepend (&vt->lines, l->data);
39733     ctx_list_remove (&list, l->data);
39734     l = next;
39735     c++;
39736   }
39737 }
39738 
vt_set_term_size(VT * vt,int icols,int irows)39739 void vt_set_term_size (VT *vt, int icols, int irows)
39740 {
39741   if (vt->rows == irows && vt->cols == icols)
39742     return;
39743 
39744   if (vt->state == vt_state_ctx)
39745   {
39746     // we should queue a pending resize instead,
39747     // .. or set a flag indicating that the last
39748     // rendered frame is discarded?
39749     return;
39750   }
39751 
39752   if(1)vt_rewrap (vt, icols);
39753 
39754   while (irows > vt->rows)
39755     {
39756       if (vt->scrollback_count && vt->scrollback)
39757         {
39758           vt->scrollback_count--;
39759           ctx_list_append (&vt->lines, vt->scrollback->data);
39760           ctx_list_remove (&vt->scrollback, vt->scrollback->data);
39761           vt->cursor_y++;
39762         }
39763       else
39764         {
39765           ctx_list_prepend (&vt->lines, vt_line_new_with_size ("", vt->cols) );
39766         }
39767       vt->line_count++;
39768       vt->rows++;
39769     }
39770   while (irows < vt->rows)
39771     {
39772       vt->cursor_y--;
39773       vt->rows--;
39774     }
39775   vt->rows = irows;
39776   vt->cols = icols;
39777   vt_resize (vt, vt->cols, vt->rows, vt->width, vt->height);
39778   vt_trimlines (vt, vt->rows);
39779   vt->margin_top     = 1;
39780   vt->margin_left    = 1;
39781   vt->margin_bottom  = vt->rows;
39782   vt->margin_right   = vt->cols;
39783   _vt_move_to (vt, vt->cursor_y, vt->cursor_x);
39784   vt->rev++;
39785   VT_info ("resize %i %i", irows, icols);
39786   if (vt->ctxp)
39787     ctx_parser_free (vt->ctxp);
39788   vt->ctxp = NULL;
39789 }
39790 
vt_set_px_size(VT * vt,int width,int height)39791 void vt_set_px_size (VT *vt, int width, int height)
39792 {
39793   int cols = width / vt->cw;
39794   int rows = height / vt->ch;
39795   vt->width = width;
39796   vt->height = height;
39797   vt_set_term_size (vt, cols, rows);
39798 }
39799 
vt_argument_buf_reset(VT * vt,const char * start)39800 static void vt_argument_buf_reset (VT *vt, const char *start)
39801 {
39802   if (start)
39803     {
39804       strcpy (vt->argument_buf, start);
39805       vt->argument_buf_len = strlen (start);
39806     }
39807   else
39808     { vt->argument_buf[vt->argument_buf_len=0]=0; }
39809 }
39810 
vt_argument_buf_add(VT * vt,int ch)39811 static inline void vt_argument_buf_add (VT *vt, int ch)
39812 {
39813   if (vt->argument_buf_len + 1 >= 1024 * 1024 * 16)
39814     return;
39815   //
39816   if (vt->argument_buf_len + 1 >=
39817       vt->argument_buf_cap)
39818     {
39819       vt->argument_buf_cap = vt->argument_buf_cap * 2;
39820       vt->argument_buf = realloc (vt->argument_buf, vt->argument_buf_cap);
39821     }
39822   vt->argument_buf[vt->argument_buf_len] = ch;
39823   vt->argument_buf[++vt->argument_buf_len] = 0;
39824 }
39825 
39826 static void
_vt_move_to(VT * vt,int y,int x)39827 _vt_move_to (VT *vt, int y, int x)
39828 {
39829   int i;
39830   x = x < 1 ? 1 : (x > vt->cols ? vt->cols : x);
39831   y = y < 1 ? 1 : (y > vt->rows ? vt->rows : y);
39832   vt->at_line_home = 0;
39833   vt->cursor_x = x;
39834   vt->cursor_y = y;
39835   i = vt->rows - y;
39836   CtxList *l;
39837   for (l = vt->lines; l && i >= 1; l = l->next, i--);
39838   if (l)
39839     {
39840       vt->current_line = l->data;
39841     }
39842   else
39843     {
39844       for (; i > 0; i--)
39845         {
39846           vt->current_line = vt_line_new_with_size ("", vt->cols);
39847           ctx_list_append (&vt->lines, vt->current_line);
39848           vt->line_count++;
39849         }
39850     }
39851   VT_cursor ("%i,%i (_vt_move_to)", y, x);
39852   vt->rev++;
39853 }
39854 
39855 static void vt_scroll (VT *vt, int amount);
39856 
_vt_add_str(VT * vt,const char * str)39857 static void _vt_add_str (VT *vt, const char *str)
39858 {
39859   int logical_margin_right = VT_MARGIN_RIGHT;
39860   if (vt->cstyle & STYLE_PROPORTIONAL)
39861     { vt->current_line->contains_proportional = 1; }
39862   if (vt->cursor_x > logical_margin_right)
39863     {
39864       if (vt->autowrap)
39865         {
39866           int chars = 0;
39867           int old_x = vt->cursor_x;
39868           VtLine *old_line = vt->current_line;
39869           if (vt->justify && str[0] != ' ')
39870             {
39871               while (old_x-1-chars >1 && vt_line_get_unichar (vt->current_line,
39872                      old_x-1-chars) !=' ')
39873                 {
39874                   chars++;
39875                 }
39876               chars--;
39877               if (chars > (vt->margin_right - vt->margin_left) * 3 / 2)
39878                 { chars = 0; }
39879             }
39880           if (vt->cursor_y == vt->margin_bottom)
39881             {
39882               vt_scroll (vt, -1);
39883             }
39884           else
39885             {
39886               _vt_move_to (vt, vt->cursor_y+1, 1);
39887             }
39888           vt->current_line->wrapped=1;
39889           vt_carriage_return (vt);
39890           for (int i = 0; i < chars; i++)
39891             {
39892               vt_line_set_style (vt->current_line, vt->cursor_x-1, vt->cstyle);
39893               vt_line_replace_unichar (vt->current_line, vt->cursor_x - 1,
39894                                          vt_line_get_unichar (old_line, old_x-1-chars+i) );
39895               vt->cursor_x++;
39896             }
39897           for (int i = 0; i < chars; i++)
39898             {
39899               vt_line_replace_unichar (old_line, old_x-1-chars+i, ' ');
39900             }
39901           if (str[0] == ' ')
39902             return;
39903         }
39904       else
39905         {
39906           vt->cursor_x = logical_margin_right;
39907         }
39908     }
39909   if (vt->insert_mode)
39910     {
39911       vt_line_insert_utf8 (vt->current_line, vt->cursor_x - 1, str);
39912       while (vt->current_line->string.utf8_length > logical_margin_right)
39913         { vt_line_remove (vt->current_line, logical_margin_right); }
39914     }
39915   else
39916     {
39917       vt_line_replace_utf8 (vt->current_line, vt->cursor_x - 1, str);
39918     }
39919   vt_line_set_style (vt->current_line, vt->cursor_x-1, vt->cstyle);
39920   vt->cursor_x += 1;
39921   vt->at_line_home = 0;
39922   vt->rev++;
39923 }
39924 
_vt_backspace(VT * vt)39925 static void _vt_backspace (VT *vt)
39926 {
39927   if (vt->current_line)
39928     {
39929       vt->cursor_x --;
39930       if (vt->cursor_x == VT_MARGIN_RIGHT) { vt->cursor_x--; }
39931       if (vt->cursor_x < VT_MARGIN_LEFT)
39932         {
39933           vt->cursor_x = VT_MARGIN_LEFT;
39934           vt->at_line_home = 1;
39935         }
39936       VT_cursor ("backspace");
39937     }
39938   vt->rev++;
39939 }
39940 
vtcmd_set_top_and_bottom_margins(VT * vt,const char * sequence)39941 static void vtcmd_set_top_and_bottom_margins (VT *vt, const char *sequence)
39942 {
39943   int top = 1, bottom = vt->rows;
39944   /* w3m issues this; causing reset of cursor position, why it is issued
39945    * is unknown
39946    */
39947   if (!strcmp (sequence, "[?1001r"))
39948     return;
39949   if (strlen (sequence) > 2)
39950     {
39951       sscanf (sequence, "[%i;%ir", &top, &bottom);
39952     }
39953   VT_info ("margins: %i %i", top, bottom);
39954   if (top <1) { top = 1; }
39955   if (top > vt->rows) { top = vt->rows; }
39956   if (bottom > vt->rows) { bottom = vt->rows; }
39957   if (bottom < top) { bottom = top; }
39958   vt->margin_top = top;
39959   vt->margin_bottom = bottom;
39960 #if 0
39961   _vt_move_to (vt, top, 1);
39962 #endif
39963   vt_carriage_return (vt);
39964   VT_cursor ("%i, %i (home)", top, 1);
39965 }
39966 static void vtcmd_save_cursor_position (VT *vt, const char *sequence);
39967 
vtcmd_set_left_and_right_margins(VT * vt,const char * sequence)39968 static void vtcmd_set_left_and_right_margins (VT *vt, const char *sequence)
39969 {
39970   int left = 1, right = vt->cols;
39971   if (!vt->left_right_margin_mode)
39972     {
39973       vtcmd_save_cursor_position (vt, sequence);
39974       return;
39975     }
39976   if (strlen (sequence) > 2)
39977     {
39978       sscanf (sequence, "[%i;%is", &left, &right);
39979     }
39980   VT_info ("hor margins: %i %i", left, right);
39981   if (left <1) { left = 1; }
39982   if (left > vt->cols) { left = vt->cols; }
39983   if (right > vt->cols) { right = vt->cols; }
39984   if (right < left) { right = left; }
39985   vt->margin_left = left;
39986   vt->margin_right = right;
39987   _vt_move_to (vt, vt->cursor_y, vt->cursor_x);
39988   vt_carriage_return (vt);
39989   //VT_cursor ("%i, %i (home)", left, 1);
39990 }
39991 
parse_int(const char * arg,int def_val)39992 static inline int parse_int (const char *arg, int def_val)
39993 {
39994   if (!isdigit (arg[1]) || strlen (arg) == 2)
39995     { return def_val; }
39996   return atoi (arg+1);
39997 }
39998 
39999 
vtcmd_set_line_home(VT * vt,const char * sequence)40000 static void vtcmd_set_line_home (VT *vt, const char *sequence)
40001 {
40002   int val = parse_int (sequence, 1);
40003   char buf[256];
40004   vt->left_right_margin_mode = 1;
40005   sprintf (buf, "[%i;%it", val, vt->margin_right);
40006   vtcmd_set_left_and_right_margins (vt, buf);
40007 }
40008 
vtcmd_set_line_limit(VT * vt,const char * sequence)40009 static void vtcmd_set_line_limit (VT *vt, const char *sequence)
40010 {
40011   int val = parse_int (sequence, 0);
40012   char buf[256];
40013   vt->left_right_margin_mode = 1;
40014   if (val < vt->margin_left) { val = vt->margin_left; }
40015   sprintf (buf, "[%i;%it", vt->margin_left, val);
40016   vtcmd_set_left_and_right_margins (vt, buf);
40017 }
40018 
vt_scroll(VT * vt,int amount)40019 static void vt_scroll (VT *vt, int amount)
40020 {
40021   int remove_no, insert_before;
40022   VtLine *string = NULL;
40023   if (amount == 0) { amount = 1; }
40024   if (amount < 0)
40025     {
40026       remove_no = vt->margin_top;
40027       insert_before = vt->margin_bottom;
40028     }
40029   else
40030     {
40031       remove_no = vt->margin_bottom;
40032       insert_before = vt->margin_top;
40033     }
40034   CtxList *l;
40035   int i;
40036   for (i=vt->rows, l = vt->lines; i > 0 && l; l=l->next, i--)
40037     {
40038       if (i == remove_no)
40039         {
40040           string = l->data;
40041           ctx_list_remove (&vt->lines, string);
40042           break;
40043         }
40044     }
40045   if (string)
40046     {
40047       if (!vt->in_alt_screen &&
40048           (vt->margin_top == 1 && vt->margin_bottom == vt->rows) )
40049         {
40050           ctx_list_prepend (&vt->scrollback, string);
40051           vt->scrollback_count ++;
40052         }
40053       else
40054         {
40055           vt_line_free (string, 1);
40056         }
40057     }
40058   string = vt_line_new_with_size ("", vt->cols/4);
40059   if (amount > 0 && vt->margin_top == 1)
40060     {
40061       ctx_list_append (&vt->lines, string);
40062     }
40063   else
40064     {
40065       for (i=vt->rows, l = vt->lines; l; l=l->next, i--)
40066         {
40067           if (i == insert_before)
40068             {
40069               ctx_list_insert_before (&vt->lines, l, string);
40070               break;
40071             }
40072         }
40073       if (i != insert_before)
40074         {
40075           ctx_list_append (&vt->lines, string);
40076         }
40077     }
40078   vt->current_line = string;
40079   /* not updating line count since we should always remove one and add one */
40080   if (vt->smooth_scroll)
40081     {
40082       if (amount < 0)
40083         {
40084           vt->scroll_offset = -1.0;
40085           vt->in_smooth_scroll = -1;
40086         }
40087       else
40088         {
40089           vt->scroll_offset = 1.0;
40090           vt->in_smooth_scroll = 1;
40091         }
40092     }
40093 
40094   {
40095     vt->select_begin_row += amount;
40096     vt->select_end_row += amount;
40097     vt->select_start_row += amount;
40098   }
40099 }
40100 
40101 typedef struct Sequence
40102 {
40103   const char *prefix;
40104   char        suffix;
40105   void (*vtcmd) (VT *vt, const char *sequence);
40106   uint32_t    compat;
40107 } Sequence;
40108 
vtcmd_cursor_position(VT * vt,const char * sequence)40109 static void vtcmd_cursor_position (VT *vt, const char *sequence)
40110 {
40111   int y = 1, x = 1;
40112   const char *semi;
40113   if (sequence[0] != 'H' && sequence[0] != 'f')
40114     {
40115       y = parse_int (sequence, 1);
40116       if ( (semi = strchr (sequence, ';') ) )
40117         {
40118           x = parse_int (semi, 1);
40119         }
40120     }
40121   if (x == 0) { x = 1; }
40122   if (y == 0) { y = 1; }
40123   if (vt->origin)
40124     {
40125       y += vt->margin_top - 1;
40126       _vt_move_to (vt, y, vt->cursor_x);
40127       x += VT_MARGIN_LEFT - 1;
40128     }
40129   VT_cursor ("%i %i CUP", y, x);
40130   _vt_move_to (vt, y, x);
40131 }
40132 
40133 
vtcmd_horizontal_position_absolute(VT * vt,const char * sequence)40134 static void vtcmd_horizontal_position_absolute (VT *vt, const char *sequence)
40135 {
40136   int x = parse_int (sequence, 1);
40137   if (x<=0) { x = 1; }
40138   _vt_move_to (vt, vt->cursor_y, x);
40139 }
40140 
vtcmd_goto_row(VT * vt,const char * sequence)40141 static void vtcmd_goto_row (VT *vt, const char *sequence)
40142 {
40143   int y = parse_int (sequence, 1);
40144   _vt_move_to (vt, y, vt->cursor_x);
40145 }
40146 
vtcmd_cursor_forward(VT * vt,const char * sequence)40147 static void vtcmd_cursor_forward (VT *vt, const char *sequence)
40148 {
40149   int n = parse_int (sequence, 1);
40150   if (n==0) { n = 1; }
40151   for (int i = 0; i < n; i++)
40152     {
40153       vt->cursor_x++;
40154     }
40155   if (vt->cursor_x > VT_MARGIN_RIGHT)
40156     { vt->cursor_x = VT_MARGIN_RIGHT; }
40157 }
40158 
vtcmd_cursor_backward(VT * vt,const char * sequence)40159 static void vtcmd_cursor_backward (VT *vt, const char *sequence)
40160 {
40161   int n = parse_int (sequence, 1);
40162   if (n==0) { n = 1; }
40163   for (int i = 0; i < n; i++)
40164     {
40165       vt->cursor_x--;
40166     }
40167   if (vt->cursor_x < VT_MARGIN_LEFT)
40168     {
40169       vt->cursor_x = VT_MARGIN_LEFT; // should this wrap??
40170       vt->at_line_home = 1;
40171     }
40172 }
40173 
vtcmd_reverse_index(VT * vt,const char * sequence)40174 static void vtcmd_reverse_index (VT *vt, const char *sequence)
40175 {
40176   int n = parse_int (sequence, 1);
40177   if (n==0) { n = 1; }
40178   for (int i = 0; i < n; i++)
40179     {
40180       if (vt->cursor_y == vt->margin_top)
40181         {
40182           vt_scroll (vt, 1);
40183           _vt_move_to (vt, vt->margin_top, vt->cursor_x);
40184         }
40185       else
40186         {
40187           _vt_move_to (vt, vt->cursor_y-1, vt->cursor_x);
40188         }
40189     }
40190 }
40191 
vtcmd_cursor_up(VT * vt,const char * sequence)40192 static void vtcmd_cursor_up (VT *vt, const char *sequence)
40193 {
40194   int n = parse_int (sequence, 1);
40195   if (n==0) { n = 1; }
40196   for (int i = 0; i < n; i++)
40197     {
40198       if (vt->cursor_y == vt->margin_top)
40199         {
40200           //_vt_move_to (vt, 1, vt->cursor_x);
40201         }
40202       else
40203         {
40204           _vt_move_to (vt, vt->cursor_y-1, vt->cursor_x);
40205         }
40206     }
40207 }
40208 
vtcmd_back_index(VT * vt,const char * sequence)40209 static void vtcmd_back_index (VT *vt, const char *sequence)
40210 {
40211   // XXX implement
40212 }
40213 
vtcmd_forward_index(VT * vt,const char * sequence)40214 static void vtcmd_forward_index (VT *vt, const char *sequence)
40215 {
40216   // XXX implement
40217 }
40218 
vtcmd_index(VT * vt,const char * sequence)40219 static void vtcmd_index (VT *vt, const char *sequence)
40220 {
40221   int n = parse_int (sequence, 1);
40222   if (n==0) { n = 1; }
40223   for (int i = 0; i < n; i++)
40224     {
40225       if (vt->cursor_y == vt->margin_bottom)
40226         {
40227           vt_scroll (vt, -1);
40228           _vt_move_to (vt, vt->margin_bottom, vt->cursor_x);
40229         }
40230       else
40231         {
40232           _vt_move_to (vt, vt->cursor_y + 1, vt->cursor_x);
40233         }
40234     }
40235 }
40236 
vtcmd_cursor_down(VT * vt,const char * sequence)40237 static void vtcmd_cursor_down (VT *vt, const char *sequence)
40238 {
40239   int n = parse_int (sequence, 1);
40240   if (n==0) { n = 1; }
40241   for (int i = 0; i < n; i++)
40242     {
40243       if (vt->cursor_y >= vt->margin_bottom)
40244         {
40245           _vt_move_to (vt, vt->margin_bottom, vt->cursor_x);
40246         }
40247       else
40248         {
40249           _vt_move_to (vt, vt->cursor_y + 1, vt->cursor_x);
40250         }
40251     }
40252 }
40253 
vtcmd_next_line(VT * vt,const char * sequence)40254 static void vtcmd_next_line (VT *vt, const char *sequence)
40255 {
40256   vtcmd_index (vt, sequence);
40257   _vt_move_to (vt, vt->cursor_y, vt->cursor_x);
40258   vt_carriage_return (vt);
40259   vt->cursor_x = VT_MARGIN_LEFT;
40260 }
40261 
vtcmd_cursor_preceding_line(VT * vt,const char * sequence)40262 static void vtcmd_cursor_preceding_line (VT *vt, const char *sequence)
40263 {
40264   vtcmd_cursor_up (vt, sequence);
40265   _vt_move_to (vt, vt->cursor_y, vt->cursor_x);
40266   vt->cursor_x = VT_MARGIN_LEFT;
40267 }
40268 
vtcmd_erase_in_line(VT * vt,const char * sequence)40269 static void vtcmd_erase_in_line (VT *vt, const char *sequence)
40270 {
40271   int n = parse_int (sequence, 0);
40272   switch (n)
40273     {
40274       case 0: // clear to end of line
40275         {
40276           char *p = (char *) mrg_utf8_skip (vt->current_line->string.str, vt->cursor_x-1);
40277           if (p) { *p = 0; }
40278           // XXX : this is chopping lines
40279           for (int col = vt->cursor_x; col <= VT_MARGIN_RIGHT; col++)
40280             { vt_line_set_style (vt->current_line, col - 1, vt->cstyle); }
40281           vt->current_line->string.length = strlen (vt->current_line->string.str);
40282           vt->current_line->string.utf8_length = ctx_utf8_strlen (vt->current_line->string.str);
40283         }
40284         break;
40285       case 1: // clear from beginning to cursor
40286         {
40287           for (int col = VT_MARGIN_LEFT; col <= vt->cursor_x; col++)
40288             {
40289               vt_line_replace_utf8 (vt->current_line, col-1, " ");
40290             }
40291           for (int col = VT_MARGIN_LEFT; col <= vt->cursor_x; col++)
40292             { vt_line_set_style (vt->current_line, col-1, vt->cstyle); }
40293           vt->current_line->string.length = strlen (vt->current_line->string.str);
40294           vt->current_line->string.utf8_length = ctx_utf8_strlen (vt->current_line->string.str); // should be a nop
40295         }
40296         break;
40297       case 2: // clear entire line
40298         for (int col = VT_MARGIN_LEFT; col <= VT_MARGIN_RIGHT; col++)
40299           { vt_line_set_style (vt->current_line, col-1, vt->cstyle); }
40300         vt_line_set (vt->current_line, ""); // XXX not all
40301         break;
40302     }
40303 }
40304 
vtcmd_erase_in_display(VT * vt,const char * sequence)40305 static void vtcmd_erase_in_display (VT *vt, const char *sequence)
40306 {
40307   int n = parse_int (sequence, 0);
40308   switch (n)
40309     {
40310       case 0: // clear to end of screen
40311         {
40312           char *p = (char *) mrg_utf8_skip (vt->current_line->string.str, vt->cursor_x-1);
40313           if (p) { *p = 0; }
40314           vt->current_line->string.length = strlen (vt->current_line->string.str);
40315           vt->current_line->string.utf8_length = ctx_utf8_strlen (vt->current_line->string.str);
40316         }
40317         for (int col = vt->cursor_x; col <= VT_MARGIN_RIGHT; col++)
40318           { vt_line_set_style (vt->current_line, col-1, vt->cstyle); }
40319         {
40320           CtxList *l;
40321           int no = vt->rows;
40322           for (l = vt->lines; l->data != vt->current_line; l = l->next, no--)
40323             {
40324               VtLine *buf = l->data;
40325               buf->string.str[0] = 0;
40326               buf->string.length = 0;
40327               buf->string.utf8_length = 0;
40328               for (int col = 1; col <= vt->cols; col++)
40329                 { vt_line_set_style (buf, col-1, vt->cstyle); }
40330             }
40331         }
40332         break;
40333       case 1: // clear from beginning to cursor
40334         {
40335           for (int col = 1; col <= vt->cursor_x; col++)
40336             {
40337               vt_line_replace_utf8 (vt->current_line, col-1, " ");
40338               vt_line_set_style (vt->current_line, col-1, vt->cstyle);
40339             }
40340         }
40341         {
40342           CtxList *l;
40343           int there_yet = 0;
40344           int no = vt->rows;
40345           for (l = vt->lines; l; l = l->next, no--)
40346             {
40347               VtLine *buf = l->data;
40348               if (there_yet)
40349                 {
40350                   buf->string.str[0] = 0;
40351                   buf->string.length = 0;
40352                   buf->string.utf8_length = 0;
40353                   for (int col = 1; col <= vt->cols; col++)
40354                     { vt_line_set_style (buf, col-1, vt->cstyle); }
40355                 }
40356               if (buf == vt->current_line)
40357                 {
40358                   there_yet = 1;
40359                 }
40360             }
40361         }
40362         break;
40363       case 3: // also clear scrollback
40364         while (vt->scrollback)
40365         {
40366            vt_line_free (vt->scrollback->data, 1);
40367            ctx_list_remove (&vt->scrollback, vt->scrollback->data);
40368          }
40369         vt->scrollback_count = 0;
40370         /* FALLTHROUGH */
40371       case 2: // clear entire screen but keep cursor;
40372         {
40373           int tx = vt->cursor_x;
40374           int ty = vt->cursor_y;
40375           vtcmd_clear (vt, "");
40376           _vt_move_to (vt, ty, tx);
40377           for (CtxList *l = vt->lines; l; l = l->next)
40378             {
40379               VtLine *line = l->data;
40380               for (int col = 1; col <= vt->cols; col++)
40381                 { vt_line_set_style (line, col-1, vt->cstyle); }
40382             }
40383         }
40384         break;
40385     }
40386 }
40387 
vtcmd_screen_alignment_display(VT * vt,const char * sequence)40388 static void vtcmd_screen_alignment_display (VT *vt, const char *sequence)
40389 {
40390   for (int y = 1; y <= vt->rows; y++)
40391     {
40392       _vt_move_to (vt, y, 1);
40393       for (int x = 1; x <= vt->cols; x++)
40394         {
40395           _vt_add_str (vt, "E");
40396         }
40397     }
40398 }
40399 
40400 #if 0
40401 static int find_idx (int r, int g, int b)
40402 {
40403   r = r / 255.0 * 5;
40404   g = g / 255.0 * 5;
40405   b = b / 255.0 * 5;
40406   return 16 + r * 6 * 6 + g * 6 + b;
40407 }
40408 #endif
40409 
vtcmd_set_graphics_rendition(VT * vt,const char * sequence)40410 static void vtcmd_set_graphics_rendition (VT *vt, const char *sequence)
40411 {
40412   const char *s = sequence;
40413   if (s[0]) { s++; }
40414   while (s && *s)
40415     {
40416       int n = parse_int (s - 1, 0); // works until color
40417       // both fg and bg could be set in 256 color mode FIXME
40418       //
40419       /* S_GR@38@Set forground color@foo bar baz@ */
40420       if (n == 38) // set foreground
40421         {
40422           s = strchr (s, ';');
40423           if (!s)
40424             {
40425               VT_warning ("incomplete [38m expected ;  %s", sequence);
40426               return;
40427             }
40428           n = parse_int (s, 0);
40429           if (n == 5)
40430             {
40431               s++;
40432               if (strchr (s, ';') )
40433                 { s = strchr (s, ';'); }
40434               else
40435                 { s = strchr (s, ':'); }
40436               if (s)
40437                 {
40438                   n = parse_int (s, 0);
40439                   set_fg_idx (n);
40440                   s++;
40441                   while (*s && *s >= '0' && *s <='9') { s++; }
40442                 }
40443             }
40444           else if (n == 2)
40445             {
40446               int r = 0, g = 0, b = 0;
40447               s++;
40448               if (strchr (s, ';') )
40449                 {
40450                   s = strchr (s, ';');
40451                   if (s)
40452                     { sscanf (s, ";%i;%i;%i", &r, &g, &b); }
40453                 }
40454               else
40455                 {
40456                   s = strchr (s, ':');
40457                   if (s)
40458                     { sscanf (s, ":%i:%i:%i", &r, &g, &b); }
40459                 }
40460               if (s)
40461               for (int i = 0; i < 3; i++)
40462                 {
40463                   if (*s)
40464                     {
40465                       s++;
40466                       while (*s && *s >= '0' && *s <='9') { s++; }
40467                     }
40468                 }
40469               set_fg_rgb (r,g,b);
40470             }
40471           else
40472             {
40473               VT_warning ("unhandled %s %i", sequence, n);
40474               return;
40475             }
40476           //return; // XXX we should continue, and allow further style set after complex color
40477         }
40478       else if (n == 48) // set background
40479         {
40480           s = strchr (s, ';');
40481           if (!s)
40482             {
40483               VT_warning ("incomplete [38m expected ;  %s", sequence);
40484               return;
40485             }
40486           n = parse_int (s, 0);
40487           if (n == 5)
40488             {
40489               s++;
40490               if (strchr (s, ';') )
40491                 { s = strchr (s, ';'); }
40492               else
40493                 { s = strchr (s, ':'); }
40494               if (s)
40495                 { n = parse_int (s, 0); }
40496               set_bg_idx (n);
40497               if (s)
40498                 {
40499                   s++;
40500                   while (*s && *s >= '0' && *s <='9') { s++; }
40501                 }
40502             }
40503           else if (n == 2)
40504             {
40505               int r = 0, g = 0, b = 0;
40506               s++;
40507               if (strchr (s, ';') )
40508                 {
40509                   s = strchr (s, ';');
40510                   if (s)
40511                     { sscanf (s, ";%i;%i;%i", &r, &g, &b); }
40512                 }
40513               else
40514                 {
40515                   s = strchr (s, ':');
40516                   if (s)
40517                     { sscanf (s, ":%i:%i:%i", &r, &g, &b); }
40518                 }
40519               if (s)
40520               for (int i = 0; i < 3; i++)
40521                 {
40522                   s++;
40523                   while (*s >= '0' && *s <='9') { s++; }
40524                 }
40525               set_bg_rgb (r,g,b);
40526             }
40527           else
40528             {
40529               VT_warning ("unhandled %s %i", sequence, n);
40530               return;
40531             }
40532           //return; // we XXX should continue, and allow further style set after complex color
40533         }
40534       else
40535         switch (n)
40536           {
40537             case 0: /* SGR@0@Style reset@@ */
40538               if (vt->cstyle & STYLE_PROPORTIONAL)
40539                 { vt->cstyle = STYLE_PROPORTIONAL; }
40540               else
40541                 { vt->cstyle = 0; }
40542               break;
40543             case 1: /* SGR@@Bold@@ */
40544               vt->cstyle |= STYLE_BOLD;
40545               break;
40546             case 2: /* SGR@@Dim@@ */
40547               vt->cstyle |= STYLE_DIM;
40548               break;
40549             case 3: /* SGR@@Italic@@ */
40550               vt->cstyle |= STYLE_ITALIC;
40551               break;
40552             case 4: /* SGR@@Underscore@@ */
40553                     /* SGR@4:2@Double underscore@@ */
40554                     /* SGR@4:3@Curvy underscore@@ */
40555               if (s[1] == ':')
40556                 {
40557                   switch (s[2])
40558                     {
40559                       case '0':
40560                         break;
40561                       case '1':
40562                         vt->cstyle |= STYLE_UNDERLINE;
40563                         break;
40564                       case '2':
40565                         vt->cstyle |= STYLE_UNDERLINE|
40566                                       STYLE_UNDERLINE_VAR;
40567                         break;
40568                       default:
40569                       case '3':
40570                         vt->cstyle |= STYLE_UNDERLINE_VAR;
40571                         break;
40572                     }
40573                 }
40574               else
40575                 {
40576                   vt->cstyle |= STYLE_UNDERLINE;
40577                 }
40578               break;
40579             case 5: /* SGR@@Blink@@ */
40580               vt->cstyle |= STYLE_BLINK;
40581               break;
40582             case 6: /* SGR@@Blink Fast@@ */
40583               vt->cstyle |= STYLE_BLINK_FAST;
40584               break;
40585             case 7: /* SGR@@Reverse@@ */
40586               vt->cstyle |= STYLE_REVERSE;
40587               break;
40588             case 8: /* SGR@@Hidden@@ */
40589               vt->cstyle |= STYLE_HIDDEN;
40590               break;
40591             case 9: /* SGR@@Strikethrough@@ */
40592               vt->cstyle |= STYLE_STRIKETHROUGH;
40593               break;
40594             case 10: /* SGR@@Font 0@@ */
40595               break;
40596             case 11: /* SGR@@Font 1@@ */
40597               break;
40598             case 12: /* SGR@@Font 2(ignored)@@ */
40599             case 13: /* SGR@@Font 3(ignored)@@ */
40600             case 14: /* SGR@@Font 4(ignored)@@ */
40601               break;
40602             case 22: /* SGR@@Bold off@@ */
40603               vt->cstyle ^= (vt->cstyle & STYLE_BOLD);
40604               vt->cstyle ^= (vt->cstyle & STYLE_DIM);
40605               break;
40606             case 23: /* SGR@@Italic off@@ */
40607               vt->cstyle ^= (vt->cstyle & STYLE_ITALIC);
40608               break;
40609             case 24: /* SGR@@Underscore off@@ */
40610               vt->cstyle ^= (vt->cstyle & (STYLE_UNDERLINE|STYLE_UNDERLINE_VAR) );
40611               break;
40612             case 25: /* SGR@@Blink off@@ */
40613               vt->cstyle ^= (vt->cstyle & STYLE_BLINK);
40614               vt->cstyle ^= (vt->cstyle & STYLE_BLINK_FAST);
40615               break;
40616             case 26: /* SGR@@Proportional spacing @@ */
40617               vt->cstyle |= STYLE_PROPORTIONAL;
40618               break;
40619             case 27: /* SGR@@Reverse off@@ */
40620               vt->cstyle ^= (vt->cstyle & STYLE_REVERSE);
40621               break;
40622             case 28: /* SGR@@Hidden off@@ */
40623               vt->cstyle ^= (vt->cstyle & STYLE_HIDDEN);
40624               break;
40625             case 29: /* SGR@@Strikethrough off@@ */
40626               vt->cstyle ^= (vt->cstyle & STYLE_STRIKETHROUGH);
40627               break;
40628             case 30: /* SGR@@black text color@@ */
40629               set_fg_idx (0);
40630               break;
40631             case 31: /* SGR@@red text color@@ */
40632               set_fg_idx (1);
40633               break;
40634             case 32: /* SGR@@green text color@@ */
40635               set_fg_idx (2);
40636               break;
40637             case 33: /* SGR@@yellow text color@@ */
40638               set_fg_idx (3);
40639               break;
40640             case 34: /* SGR@@blue text color@@ */
40641               set_fg_idx (4);
40642               break;
40643             case 35: /* SGR@@magenta text color@@ */
40644               set_fg_idx (5);
40645               break;
40646             case 36: /* SGR@@cyan text color@@ */
40647               set_fg_idx (6);
40648               break;
40649             case 37: /* SGR@@light gray text color@@ */
40650               set_fg_idx (7);
40651               break;
40652           /* SGR@38;5;Pn@256 color index foreground color@where Pn is 0-15 is system colors 16-(16+6*6*6) is a 6x6x6  RGB cube and in the end a grayscale without white and black.@ */
40653               /* SGR@38;2;Pr;Pg;Pb@24 bit RGB foreground color each of Pr Pg and Pb have 0-255 range@@ */
40654             case 39: /* SGR@@default text color@@ */
40655               set_fg_idx (vt->reverse_video?0:15);
40656               vt->cstyle ^= (vt->cstyle & STYLE_FG_COLOR_SET);
40657               break;
40658             case 40: /* SGR@@black background color@@ */
40659               set_bg_idx (0);
40660               break;
40661             case 41: /* SGR@@red background color@@ */
40662               set_bg_idx (1);
40663               break;
40664             case 42: /* SGR@@green background color@@ */
40665               set_bg_idx (2);
40666               break;
40667             case 43: /* SGR@@yellow background color@@ */
40668               set_bg_idx (3);
40669               break;
40670             case 44: /* SGR@@blue background color@@ */
40671               set_bg_idx (4);
40672               break;
40673             case 45: /* SGR@@magenta background color@@ */
40674               set_bg_idx (5);
40675               break;
40676             case 46: /* SGR@@cyan background color@@ */
40677               set_bg_idx (6);
40678               break;
40679             case 47: /* SGR@@light gray background color@@ */
40680               set_bg_idx (7);
40681               break;
40682 
40683           /* SGR@48;5;Pn@256 color index background color@where Pn is 0-15 is system colors 16-(16+6*6*6) is a 6x6x6  RGB cube and in the end a grayscale without white and black.@ */
40684           /* SGR@48;2;Pr;Pg;Pb@24 bit RGB background color@Where Pr Pg and Pb have 0-255 range@ */
40685 
40686             case 49: /* SGR@@default background color@@ */
40687               set_bg_idx (vt->reverse_video?15:0);
40688               vt->cstyle ^= (vt->cstyle & STYLE_BG_COLOR_SET);
40689               break;
40690             case 50: /* SGR@@Proportional spacing off @@ */
40691               vt->cstyle ^= (vt->cstyle & STYLE_PROPORTIONAL);
40692               break;
40693             // 51 : framed
40694             // 52 : encircled
40695             case 53: /* SGR@@Overlined@@ */
40696               vt->cstyle |= STYLE_OVERLINE;
40697               break;
40698             case 55: /* SGR@@Not Overlined@@ */
40699               vt->cstyle ^= (vt->cstyle&STYLE_OVERLINE);
40700               break;
40701             case 90: /* SGR@@dark gray text color@@ */
40702               set_fg_idx (8);
40703               break;
40704             case 91: /* SGR@@light red text color@@ */
40705               set_fg_idx (9);
40706               break;
40707             case 92: /* SGR@@light green text color@@ */
40708               set_fg_idx (10);
40709               break;
40710             case 93: /* SGR@@light yellow text color@@ */
40711               set_fg_idx (11);
40712               break;
40713             case 94: /* SGR@@light blue text color@@ */
40714               set_fg_idx (12);
40715               break;
40716             case 95: /* SGR@@light magenta text color@@ */
40717               set_fg_idx (13);
40718               break;
40719             case 96: /* SGR@@light cyan text color@@ */
40720               set_fg_idx (14);
40721               break;
40722             case 97: /* SGR@@white text color@@ */
40723               set_fg_idx (15);
40724               break;
40725             case 100: /* SGR@@dark gray background color@@ */
40726               set_bg_idx (8);
40727               break;
40728             case 101: /* SGR@@light red background color@@ */
40729               set_bg_idx (9);
40730               break;
40731             case 102: /* SGR@@light green background color@@ */
40732               set_bg_idx (10);
40733               break;
40734             case 103: /* SGR@@light yellow background color@@ */
40735               set_bg_idx (11);
40736               break;
40737             case 104: /* SGR@@light blue background color@@ */
40738               set_bg_idx (12);
40739               break;
40740             case 105: /* SGR@@light magenta background color@@ */
40741               set_bg_idx (13);
40742               break;
40743             case 106: /* SGR@@light cyan background color@@ */
40744               set_bg_idx (14);
40745               break;
40746             case 107: /* SGR@@white background color@@ */
40747               set_bg_idx (15);
40748               break;
40749             default:
40750               VT_warning ("unhandled style code %i in sequence \\033%s\n", n, sequence);
40751               return;
40752           }
40753       while (s && *s && *s != ';') { s++; }
40754       if (s && *s == ';') { s++; }
40755     }
40756 }
40757 
vtcmd_ignore(VT * vt,const char * sequence)40758 static void vtcmd_ignore (VT *vt, const char *sequence)
40759 {
40760   VT_info ("ignoring sequence %s", sequence);
40761 }
40762 
vtcmd_clear_all_tabs(VT * vt,const char * sequence)40763 static void vtcmd_clear_all_tabs (VT *vt, const char *sequence)
40764 {
40765   memset (vt->tabs, 0, sizeof (vt->tabs) );
40766 }
40767 
vtcmd_clear_current_tab(VT * vt,const char * sequence)40768 static void vtcmd_clear_current_tab (VT *vt, const char *sequence)
40769 {
40770   vt->tabs[ (int) (vt->cursor_x-1)] = 0;
40771 }
40772 
vtcmd_horizontal_tab_set(VT * vt,const char * sequence)40773 static void vtcmd_horizontal_tab_set (VT *vt, const char *sequence)
40774 {
40775   vt->tabs[ (int) vt->cursor_x-1] = 1;
40776 }
40777 
vtcmd_save_cursor_position(VT * vt,const char * sequence)40778 static void vtcmd_save_cursor_position (VT *vt, const char *sequence)
40779 {
40780   vt->saved_x = vt->cursor_x;
40781   vt->saved_y = vt->cursor_y;
40782 }
40783 
vtcmd_restore_cursor_position(VT * vt,const char * sequence)40784 static void vtcmd_restore_cursor_position (VT *vt, const char *sequence)
40785 {
40786   _vt_move_to (vt, vt->saved_y, vt->saved_x);
40787 }
40788 
40789 
vtcmd_save_cursor(VT * vt,const char * sequence)40790 static void vtcmd_save_cursor (VT *vt, const char *sequence)
40791 {
40792   vt->saved_style   = vt->cstyle;
40793   vt->saved_origin  = vt->origin;
40794   vtcmd_save_cursor_position (vt, sequence);
40795   for (int i = 0; i < 4; i++)
40796     { vt->saved_charset[i] = vt->charset[i]; }
40797 }
40798 
vtcmd_restore_cursor(VT * vt,const char * sequence)40799 static void vtcmd_restore_cursor (VT *vt, const char *sequence)
40800 {
40801   vtcmd_restore_cursor_position (vt, sequence);
40802   vt->cstyle  = vt->saved_style;
40803   vt->origin  = vt->saved_origin;
40804   for (int i = 0; i < 4; i++)
40805     { vt->charset[i] = vt->saved_charset[i]; }
40806 }
40807 
vtcmd_erase_n_chars(VT * vt,const char * sequence)40808 static void vtcmd_erase_n_chars (VT *vt, const char *sequence)
40809 {
40810   int n = parse_int (sequence, 1);
40811   while (n--)
40812     {
40813       vt_line_replace_utf8 (vt->current_line, vt->cursor_x - 1 + n, " ");
40814       vt_line_set_style (vt->current_line, vt->cursor_x + n - 1, vt->cstyle);
40815     }
40816 }
40817 
vtcmd_delete_n_chars(VT * vt,const char * sequence)40818 static void vtcmd_delete_n_chars (VT *vt, const char *sequence)
40819 {
40820   int n = parse_int (sequence, 1);
40821   int count = n;
40822   while (count--)
40823     {
40824       vt_line_remove (vt->current_line, vt->cursor_x - 1);
40825     }
40826 }
40827 
vtcmd_delete_n_lines(VT * vt,const char * sequence)40828 static void vtcmd_delete_n_lines (VT *vt, const char *sequence)
40829 {
40830   int n = parse_int (sequence, 1);
40831   for (int a = 0; a < n; a++)
40832     {
40833       int i;
40834       CtxList *l;
40835       VtLine *string = vt->current_line;
40836       vt_line_set (string, "");
40837       ctx_list_remove (&vt->lines, vt->current_line);
40838       for (i=vt->rows, l = vt->lines; l; l=l->next, i--)
40839         {
40840           if (i == vt->margin_bottom)
40841             {
40842               vt->current_line = string;
40843               ctx_list_insert_before (&vt->lines, l, string);
40844               break;
40845             }
40846         }
40847       _vt_move_to (vt, vt->cursor_y, vt->cursor_x); // updates current_line
40848     }
40849 }
40850 
vtcmd_insert_character(VT * vt,const char * sequence)40851 static void vtcmd_insert_character (VT *vt, const char *sequence)
40852 {
40853   int n = parse_int (sequence, 1);
40854   while (n--)
40855     {
40856       vt_line_insert_utf8 (vt->current_line, vt->cursor_x-1, " ");
40857     }
40858   while (vt->current_line->string.utf8_length > vt->cols)
40859     { vt_line_remove (vt->current_line, vt->cols); }
40860   // XXX update style
40861 }
40862 
vtcmd_scroll_up(VT * vt,const char * sequence)40863 static void vtcmd_scroll_up (VT *vt, const char *sequence)
40864 {
40865   int n = parse_int (sequence, 1);
40866   if (n == 0) { n = 1; }
40867   while (n--)
40868     { vt_scroll (vt, -1); }
40869 }
40870 
vtcmd_scroll_down(VT * vt,const char * sequence)40871 static void vtcmd_scroll_down (VT *vt, const char *sequence)
40872 {
40873   int n = parse_int (sequence, 1);
40874   if (n == 0) { n = 1; }
40875   while (n--)
40876     { vt_scroll (vt, 1); }
40877 }
40878 
vtcmd_insert_blank_lines(VT * vt,const char * sequence)40879 static void vtcmd_insert_blank_lines (VT *vt, const char *sequence)
40880 {
40881   int n = parse_int (sequence, 1);
40882   if (n == 0) { n = 1; }
40883   {
40884     int st = vt->margin_top;
40885     int sb = vt->margin_bottom;
40886     vt->margin_top = vt->cursor_y;
40887     while (n--)
40888       {
40889         vt_scroll (vt, 1);
40890       }
40891     vt->margin_top = st;
40892     vt->margin_bottom = sb;
40893   }
40894 }
40895 
vtcmd_set_default_font(VT * vt,const char * sequence)40896 static void vtcmd_set_default_font (VT *vt, const char *sequence)
40897 {
40898   vt->charset[0] = 0;
40899 }
40900 
vtcmd_set_alternate_font(VT * vt,const char * sequence)40901 static void vtcmd_set_alternate_font (VT *vt, const char *sequence)
40902 {
40903   vt->charset[0] = 1;
40904 }
40905 
40906 
vt_ctx_exit(void * data)40907 static void vt_ctx_exit (void *data)
40908 {
40909   VT *vt = data;
40910   vt->state = vt_state_neutral;
40911   vt->rev ++;
40912   if (!vt->current_line)
40913     return;
40914 #if 0
40915   fprintf (stderr, "\n");
40916   if (vt->current_line->prev)
40917   fprintf (stderr, "---prev(%i)----\n%s", (int)strlen(vt->current_line->prev),vt->current_line->prev);
40918   fprintf (stderr, "---new(%i)----\n%s", (int)strlen(vt->current_line->frame->str),vt->current_line->frame->str);
40919   fprintf (stderr, "--------\n");
40920 #endif
40921 
40922 #if CTX_VT_USE_FRAME_DIFF
40923   if (vt->current_line->prev)
40924     free (vt->current_line->prev);
40925   vt->current_line->prev = NULL;
40926   if (vt->current_line->frame)
40927   {
40928     vt->current_line->prev = vt->current_line->frame->str;
40929     vt->current_line->prev_length = vt->current_line->frame->length;
40930 
40931     ctx_string_free (vt->current_line->frame, 0);
40932     vt->current_line->frame = NULL;
40933   }
40934 #endif
40935 
40936   void *tmp = vt->current_line->ctx;
40937   vt->current_line->ctx = vt->current_line->ctx_copy;
40938   vt->current_line->ctx_copy = tmp;
40939 
40940   _ctx_set_frame (vt->current_line->ctx, _ctx_frame (vt->current_line->ctx) + 1);
40941   _ctx_set_frame (vt->current_line->ctx_copy, _ctx_frame (vt->current_line->ctx));
40942 #if 1
40943   if (vt->ctxp) // XXX: ugly hack to aid double buffering
40944     ((void**)vt->ctxp)[0]= vt->current_line->ctx;
40945 #endif
40946 
40947   //ctx_parser_free (vt->ctxp);
40948   //vt->ctxp = NULL;
40949 }
40950 #if 0
40951 #define CTX_x            CTX_STRH('x',0,0,0,0,0,0,0,0,0,0,0,0,0)
40952 #define CTX_y            CTX_STRH('y',0,0,0,0,0,0,0,0,0,0,0,0,0)
40953 #define CTX_lower_bottom CTX_STRH('l','o','w','e','r','-','b','o','t','t','o','m',0,0)
40954 #define CTX_lower        CTX_STRH('l','o','w','e','r',0,0,0,0,0,0,0,0,0)
40955 #define CTX_raise        CTX_STRH('r','a','i','s','e',0,0,0,0,0,0,0,0,0)
40956 #define CTX_raise_top    CTX_STRH('r','a','i','s','e','-','t','o','p',0,0,0,0,0)
40957 #define CTX_terminate    CTX_STRH('t','e','r','m','i','n','a','t','e',0,0,0,0,0)
40958 #define CTX_maximize     CTX_STRH('m','a','x','i','m','i','z','e',0,0,0,0,0,0)
40959 #define CTX_unmaximize   CTX_STRH('u','n','m','a','x','i','m','i','z','e',0,0,0,0)
40960 #define CTX_width        CTX_STRH('w','i','d','t','h',0,0,0,0,0,0,0,0,0)
40961 #define CTX_title        CTX_STRH('t','i','t','l','e',0,0,0,0,0,0,0,0,0)
40962 #define CTX_action       CTX_STRH('a','c','t','i','o','n',0,0,0,0,0,0,0,0)
40963 #define CTX_height       CTX_STRH('h','e','i','g','h','t',0,0,0,0,0,0,0,0)
40964 #endif
40965 
40966 
vt_get_prop(VT * vt,const char * key,const char ** val,int * len)40967 static int vt_get_prop (VT *vt, const char *key, const char **val, int *len)
40968 {
40969 #if 0
40970   uint32_t key_hash = ctx_strhash (key);
40971   char str[4096]="";
40972   fprintf (stderr, "%s: %s %i\n", __FUNCTION__, key, key_hash);
40973   CtxClient *client = ctx_client_by_id (ct->id);
40974   if (!client)
40975     return 0;
40976   switch (key_hash)
40977   {
40978     case CTX_title:
40979       sprintf (str, "setkey %s %s\n", key, client->title);
40980       break;
40981     case CTX_x:
40982       sprintf (str, "setkey %s %i\n", key, client->x);
40983       break;
40984     case CTX_y:
40985       sprintf (str, "setkey %s %i\n", key, client->y);
40986       break;
40987     case CTX_width:
40988       sprintf (str, "setkey %s %i\n", key, client->width);
40989       break;
40990     case CTX_height:
40991       sprintf (str, "setkey %s %i\n", key, client->width);
40992       break;
40993     default:
40994       sprintf (str, "setkey %s undefined\n", key);
40995       break;
40996   }
40997   if (str[0])
40998   {
40999     vtpty_write ((void*)ct, str, strlen (str));
41000     fprintf (stderr, "%s", str);
41001   }
41002 #endif
41003   return 0;
41004 }
41005 
vtcmd_set_mode(VT * vt,const char * sequence)41006 static void vtcmd_set_mode (VT *vt, const char *sequence)
41007 {
41008   int set = 1;
41009   if (sequence[strlen (sequence)-1]=='l')
41010     { set = 0; }
41011   if (sequence[1]=='?')
41012     {
41013       int qval;
41014       sequence++;
41015 qagain:
41016       qval = parse_int (sequence, 1);
41017       switch (qval)
41018         {
41019           case 1: /*MODE;DECCKM;Cursor key mode;Application;Cursor;*/
41020             vt->cursor_key_application = set;
41021             break;
41022           case 2: /*MODE;DECANM;VT52 emulation;on;off; */
41023             if (set==0)
41024               { vt->state = vt_state_vt52; }
41025             break;
41026           case 3: /*MODE;DECCOLM;Column mode;132 columns;80 columns;*/
41027             vtcmd_set_132_col (vt, set);
41028             break; // set 132 col
41029           case 4: /*MODE;DECSCLM;Scrolling mode;smooth;jump;*/
41030             vt->smooth_scroll = set;
41031             break; // set 132 col
41032           case 5: /*MODE;DECSCNM;Screen mode;Reverse;Normal;*/
41033             vt->reverse_video = set;
41034             break;
41035           case 6: /*MODE;DECOM;Origin mode;Relative;Absolute;*/
41036             vt->origin = set;
41037             if (set)
41038               {
41039                 _vt_move_to (vt, vt->margin_top, 1);
41040                 vt_carriage_return (vt);
41041               }
41042             else
41043               { _vt_move_to (vt, 1, 1); }
41044             break;
41045           case 7: /*MODE;DECAWM;Autowrap;on;off;*/
41046             vt->autowrap = set;
41047             break;
41048           case 8: /*MODE;DECARM;Auto repeat;on;off;*/
41049             vt->keyrepeat = set;
41050             break;
41051           // case 9: // send mouse x & y on button press
41052 
41053           // 10 - Block DECEDM
41054           // 18 - Print form feed  DECPFF  default off
41055           // 19 - Print extent fullscreen DECPEX  default on
41056           case 12:
41057             vtcmd_ignore (vt, sequence);
41058             break; // blinking_cursor
41059           case 25:/*MODE;DECTCEM;Cursor visible;on;off; */
41060             vt->cursor_visible = set;
41061             break;
41062           case 30: // from rxvt - show/hide scrollbar
41063             break;
41064           case 34: // DECRLM - right to left mode
41065             break;
41066           case 38: // DECTEK - enter tektronix mode
41067             break;
41068           case 60: // horizontal cursor coupling
41069           case 61: // vertical cursor coupling
41070             break;
41071           case 69:/*MODE;DECVSSM;Left right margin mode;on;off; */
41072             vt->left_right_margin_mode = set;
41073             break;
41074           case 80:/* DECSDM Sixel scrolling */
41075             break;
41076           case 437:/*MODE;;Encoding/cp437mode;cp437;utf8; */
41077             vt->encoding = set ? 1 : 0;
41078             break;
41079           case 1000:/*MODE;;Mouse reporting;on;off;*/
41080             vt->mouse = set;
41081             break;
41082           case 1001:
41083           case 1002:/*MODE;;Mouse drag;on;off;*/
41084             vt->mouse_drag = set;
41085             break;
41086           case 1003:/*MODE;;Mouse all;on;off;*/
41087             vt->mouse_all = set;
41088             break;
41089           case 1006:/*MODE;;Mouse decimal;on;off;*/
41090             vt->mouse_decimal = set;
41091             break;
41092           case 47:
41093           case 1047:
41094           //case 1048:
41095           case 1049:/*MODE;;Alt screen;on;off;*/
41096             if (set)
41097               {
41098                 if (vt->in_alt_screen)
41099                   {
41100                   }
41101                 else
41102                   {
41103                     vtcmd_save_cursor (vt, "");
41104                     vt->saved_lines = vt->lines;
41105                     vt->saved_line_count = vt->line_count;
41106                     vt->line_count = 0;
41107                     vt->lines = NULL;
41108                     for (int i = 0; i <  vt->rows; i++)
41109                       {
41110                         vt->current_line = vt_line_new_with_size ("", vt->cols);
41111                         ctx_list_append (&vt->lines, vt->current_line);
41112                         vt->line_count++;
41113                       }
41114                     vt->in_alt_screen = 1;
41115                     vt->had_alt_screen = 1;
41116                     vt_line_feed (vt);
41117                     _vt_move_to (vt, 1, 1);
41118                     vt_carriage_return (vt);
41119                   }
41120               }
41121             else
41122               {
41123                 if (vt->in_alt_screen)
41124                   {
41125                     while (vt->lines)
41126                       {
41127                         vt_line_free (vt->lines->data, 1);
41128                         ctx_list_remove (&vt->lines, vt->lines->data);
41129                       }
41130                     vt->line_count = vt->saved_line_count;
41131                     vt->lines = vt->saved_lines;
41132                     vtcmd_restore_cursor (vt, "");
41133                     vt->saved_lines = NULL;
41134                     vt->in_alt_screen = 0;
41135                   }
41136                 else
41137                   {
41138                   }
41139               }
41140             break; // alt screen
41141           case 1010: /*MODE;;scroll on output;on;off; */ //rxvt
41142             vt->scroll_on_output = set;
41143             break;
41144           case 1011:/*MODE:;scroll on input;on;off; */ //rxvt)
41145             vt->scroll_on_input = set;
41146             break;
41147           case 2004:/*MODE;;bracketed paste;on;off; */
41148             vt->bracket_paste = set;
41149             break;
41150           case 201:/*MODE;;ctx-events;on;off;*/
41151             vt->ctx_events = set;
41152             break;
41153 
41154           case 200:/*MODE;;ctx vector graphics mode;on;;*/
41155             if (set)
41156               {
41157                 if (!vt->current_line->ctx)
41158                   {
41159                     vt->current_line->ctx = ctx_new ();
41160                     vt->current_line->ctx_copy = ctx_new ();
41161                     ctx_set_texture_cache (vt->current_line->ctx_copy, vt->current_line->ctx);
41162                     _ctx_set_transformation (vt->current_line->ctx, 0);
41163                     _ctx_set_transformation (vt->current_line->ctx_copy, 0);
41164 
41165                     //ctx_set_texture_cache (vt->current_line->ctx, vt->current_line->ctx_copy);
41166                     //ctx_set_texture_cache (vt->current_line->ctx_copy, vt->current_line->ctx);
41167 #if CTX_VT_USE_FRAME_DIFF
41168                     vt->current_line->frame = ctx_string_new ("");
41169 #endif
41170                   }
41171                 if (vt->ctxp)
41172                   ctx_parser_free (vt->ctxp);
41173 
41174                 vt->ctxp = ctx_parser_new (vt->current_line->ctx,
41175                                            vt->cols * vt->cw, vt->rows * vt->ch,
41176                                            vt->cw, vt->ch, vt->cursor_x, vt->cursor_y,
41177                                            (void*)vt_set_prop, (void*)vt_get_prop, vt, vt_ctx_exit, vt);
41178                 vt->utf8_holding[vt->utf8_pos=0]=0; // XXX : needed?
41179                 vt->state = vt_state_ctx;
41180               }
41181             break;
41182           default:
41183             VT_warning ("unhandled CSI ? %i%s", qval, set?"h":"l");
41184             return;
41185         }
41186       if (strchr (sequence + 1, ';') )
41187         {
41188           sequence = strchr (sequence + 1, ';');
41189           goto qagain;
41190         }
41191     }
41192   else
41193     {
41194       int val;
41195 again:
41196       val = parse_int (sequence, 1);
41197       switch (val)
41198         {
41199           case 1:/*GATM - transfer enhanced data */
41200           case 2:/*KAM - keyboard action mode */
41201             break;
41202           case 3:/*CRM - control representation mode */
41203             /* show control chars? */
41204             break;
41205           case 4:/*MODE2;IRM;Insert Mode;Insert;Replace; */
41206             vt->insert_mode = set;
41207             break;
41208           case 9: /* interlace mode */
41209             break;
41210           case 12:/*MODE2;SRM;Local echo;on;off; */
41211             vt->echo = set;
41212             break;
41213           case 20:/*MODE2;LNM;Carriage Return on LF/Newline;on;off;*/
41214             ;
41215             vt->cr_on_lf = set;
41216             break;
41217           case 21: // GRCM - whether SGR accumulates or a reset on each command
41218             break;
41219           case 32: // WYCRTSAVM - screen saver
41220             break;
41221           case 33: // WYSTCURM  - steady cursor
41222             break;
41223           case 34: // WYULCURM  - underline cursor
41224             break;
41225           default:
41226             VT_warning ("unhandled CSI %ih", val);
41227             return;
41228         }
41229       if (strchr (sequence, ';') && sequence[0] != ';')
41230         {
41231           sequence = strchr (sequence, ';');
41232           goto again;
41233         }
41234     }
41235 }
41236 
vtcmd_request_mode(VT * vt,const char * sequence)41237 static void vtcmd_request_mode (VT *vt, const char *sequence)
41238 {
41239   char buf[64]="";
41240   if (sequence[1]=='?')
41241     {
41242       int qval;
41243       sequence++;
41244       qval = parse_int (sequence, 1);
41245       int is_set = -1; // -1 undefiend   0 reset 1 set  1000 perm_reset  1001 perm_set
41246       switch (qval)
41247         {
41248           case 1:
41249             is_set = vt->cursor_key_application;
41250             break;
41251           case 2: /*VT52 emulation;;enable; */
41252           //if (set==0) vt->in_vt52 = 1;
41253             is_set = 1001;
41254             break;
41255           case 3:
41256             is_set = 0;
41257             break;
41258           case 4:
41259             is_set = vt->smooth_scroll;
41260             break;
41261           case 5:
41262             is_set = vt->reverse_video;
41263             break;
41264           case 6:
41265             is_set = vt->origin;
41266             break;
41267           case 7:
41268             is_set = vt->autowrap;
41269             break;
41270           case 8:
41271             is_set = vt->keyrepeat;
41272             break;
41273           case 9: // should be dynamic
41274             is_set = 1000;
41275             break;
41276           case 10:
41277           case 11:
41278           case 12:
41279           case 13:
41280           case 14:
41281           case 16:
41282           case 18:
41283           case 19:
41284             is_set = 1000;
41285             break;
41286           case 25:
41287             is_set = vt->cursor_visible;
41288             break;
41289           case 45:
41290             is_set = 1000;
41291             break;
41292           case 47:
41293             is_set = vt->in_alt_screen;
41294             break;
41295           case 69:
41296             is_set = vt->left_right_margin_mode;
41297             break;
41298           case 437:
41299             is_set = vt->encoding;
41300             break;
41301           case 1000:
41302             is_set = vt->mouse;
41303             break;
41304             // 1001 hilite tracking
41305           case 1002:
41306             is_set = vt->mouse_drag;
41307             break;
41308           case 1003:
41309             is_set = vt->mouse_all;
41310             break;
41311           case 1006:
41312             is_set = vt->mouse_decimal;
41313             break;
41314           case 201:
41315             is_set = vt->ctx_events;
41316             break;
41317           case 2004:
41318             is_set = vt->bracket_paste;
41319             break;
41320           case 1010: // scroll to bottom on tty output (rxvt)
41321             is_set = vt->scroll_on_output;
41322             break;
41323           case 1011: // scroll to bottom on key press (rxvt)
41324             is_set = vt->scroll_on_input;
41325             break;
41326           case 1049:
41327             is_set = vt->in_alt_screen;
41328             break;
41329             break;
41330           case 200:/*ctx protocol;On;;*/
41331             is_set = (vt->state == vt_state_ctx);
41332             break;
41333           case 80:/* DECSDM Sixel scrolling */
41334           case 30: // from rxvt - show/hide scrollbar
41335           case 34: // DECRLM - right to left mode
41336           case 60: // horizontal cursor coupling
41337           case 61: // vertical cursor coupling
41338           default:
41339             break;
41340         }
41341       switch (is_set)
41342       {
41343         case 0:
41344           sprintf (buf, "\033[?%i;%i$y", qval, 2);
41345           break;
41346         case 1:
41347           { sprintf (buf, "\033[?%i;%i$y", qval, 1); }
41348           break;
41349         case 1000:
41350           sprintf (buf, "\033[?%i;%i$y", qval, 4);
41351           break;
41352         case 1001:
41353           sprintf (buf, "\033[?%i;%i$y", qval, 3);
41354           break;
41355         case -1:
41356           { sprintf (buf, "\033[?%i;%i$y", qval, 0); }
41357       }
41358     }
41359   else
41360     {
41361       int val;
41362       val = parse_int (sequence, 1);
41363       switch (val)
41364         {
41365           case 1:
41366             sprintf (buf, "\033[%i;%i$y", val, 0);
41367             break;
41368           case 2:/* AM - keyboard action mode */
41369             sprintf (buf, "\033[%i;%i$y", val, 0);
41370             break;
41371           case 3:/*CRM - control representation mode */
41372             sprintf (buf, "\033[%i;%i$y", val, 0);
41373             break;
41374           case 4:/*Insert Mode;Insert;Replace; */
41375             sprintf (buf, "\033[%i;%i$y", val, vt->insert_mode?1:2);
41376             break;
41377           case 9: /* interlace mode */
41378             sprintf (buf, "\033[%i;%i$y", val, 1);
41379             break;
41380           case 12:
41381             sprintf (buf, "\033[%i;%i$y", val, vt->echo?1:2);
41382             break;
41383           case 20:/*Carriage Return on LF/Newline;on;off;*/
41384             ;
41385             sprintf (buf, "\033[%i;%i$y", val, vt->cr_on_lf?1:2);
41386             break;
41387           case 21: // GRCM - whether SGR accumulates or a reset on each command
41388           default:
41389             sprintf (buf, "\033[%i;%i$y", val, 0);
41390         }
41391     }
41392   if (buf[0])
41393     { vt_write (vt, buf, strlen (buf) ); }
41394 }
41395 
vtcmd_set_t(VT * vt,const char * sequence)41396 static void vtcmd_set_t (VT *vt, const char *sequence)
41397 {
41398   /* \e[21y is request title - allows inserting keychars */
41399   if      (!strcmp (sequence,  "[1t")) { ctx_client_unshade (vt->id); }
41400   else if (!strcmp (sequence,  "[2t")) { ctx_client_shade (vt->id); }
41401   else if (!strncmp (sequence, "[3;", 3)) {
41402     int x=0,y=0;
41403     sscanf (sequence, "[3;%i;%ir", &y, &x);
41404     ctx_client_move (vt->id, x, y);
41405   }
41406   else if (!strncmp (sequence, "[4;", 3))
41407   {
41408     int width = 0, height = 0;
41409     sscanf (sequence, "[4;%i;%ir", &height , &width);
41410     if (width < 0) width = vt->cols * vt->cw;
41411     if (height < 0) height = vt->rows * vt->ch;
41412     if (width == 0) width = ctx_width (vt->root_ctx);
41413     if (height == 0) height = ctx_height (vt->root_ctx);
41414     ctx_client_resize (vt->id, width, height);
41415   }
41416   else if (!strcmp (sequence, "[5t") ) { ctx_client_raise_top (vt->id); }
41417   else if (!strcmp (sequence, "[6t") ) { ctx_client_lower_bottom (vt->id); }
41418   else if (!strcmp (sequence, "[7t") ) { vt->rev++; /* refresh */ }
41419   else if (!strncmp (sequence, "[8;", 3) )
41420   {
41421     int cols = 0, rows = 0;
41422     sscanf (sequence, "[8;%i;%ir", &rows, &cols);
41423     if (cols < 0) cols = vt->cols;
41424     if (rows < 0) rows = vt->rows;
41425     if (cols == 0) cols = ctx_width (vt->root_ctx) / vt->cw;
41426     if (rows == 0) rows = ctx_height (vt->root_ctx) / vt->ch;
41427     ctx_client_resize (vt->id, cols * vt->cw, rows * vt->ch);
41428   }
41429   else if (!strcmp (sequence, "[9;0t") ) { ctx_client_unmaximize (vt->id); }
41430   else if (!strcmp (sequence, "[9;1t") ) { ctx_client_maximize (vt->id);}
41431 
41432   /* should actually be full-screen */
41433   else if (!strcmp (sequence, "[10;0t") ) { ctx_client_unmaximize (vt->id); }
41434   else if (!strcmp (sequence, "[10;1t") ) { ctx_client_maximize (vt->id);}
41435   else if (!strcmp (sequence, "[10;2t") ) { ctx_client_toggle_maximized (vt->id);}
41436 
41437   else if (!strcmp (sequence, "[11t") )  /* report window state  */
41438     {
41439       char buf[128];
41440       if (ctx_client_is_iconified (vt->id))
41441         sprintf (buf, "\033[2t");
41442       else
41443         sprintf (buf, "\033[1t");
41444       vt_write (vt, buf, strlen (buf) );
41445     }
41446   else if (!strcmp (sequence, "[13t") ) /* request terminal position */
41447     {
41448       char buf[128];
41449       sprintf (buf, "\033[3;%i;%it", ctx_client_y (vt->id), ctx_client_x (vt->id));
41450       vt_write (vt, buf, strlen (buf) );
41451     }
41452   else if (!strcmp (sequence, "[14t") ) /* request terminal dimensions in px */
41453     {
41454       char buf[128];
41455       sprintf (buf, "\033[4;%i;%it", vt->rows * vt->ch, vt->cols * vt->cw);
41456       vt_write (vt, buf, strlen (buf) );
41457     }
41458   else if (!strcmp (sequence, "[15t") ) /* request root dimensions in px */
41459     {
41460       char buf[128];
41461       sprintf (buf, "\033[5;%i;%it", ctx_height (vt->root_ctx), ctx_width(vt->root_ctx));
41462       vt_write (vt, buf, strlen (buf) );
41463     }
41464   else if (!strcmp (sequence, "[16t") ) /* request char dimensions in px */
41465     {
41466       char buf[128];
41467       sprintf (buf, "\033[6;%i;%it", vt->ch, vt->cw);
41468       vt_write (vt, buf, strlen (buf) );
41469     }
41470   else if (!strcmp (sequence, "[18t") ) /* request terminal dimensions */
41471     {
41472       char buf[128];
41473       sprintf (buf, "\033[8;%i;%it", vt->rows, vt->cols);
41474       vt_write (vt, buf, strlen (buf) );
41475     }
41476   else if (!strcmp (sequence, "[19t") ) /* request root window size in char */
41477     {
41478       char buf[128];
41479       sprintf (buf, "\033[9;%i;%it", ctx_height(vt->root_ctx)/vt->ch, ctx_width (vt->root_ctx)/vt->cw);
41480       vt_write (vt, buf, strlen (buf) );
41481     }
41482 
41483 #if 0
41484   {"[", 's',  foo, VT100}, /*args:PnSP id:DECSWBV Set warning bell volume */
41485 #endif
41486   else if (sequence[strlen (sequence)-2]==' ') /* DECSWBV */
41487     {
41488       int val = parse_int (sequence, 0);
41489       if (val <= 1) { vt->bell = 0; }
41490       if (val <= 8) { vt->bell = val; }
41491     }
41492   else
41493     {
41494       // XXX: X for ints >=24 resize to that number of lines
41495       VT_info ("unhandled subsequence %s", sequence);
41496     }
41497 }
41498 
_vt_htab(VT * vt)41499 static void _vt_htab (VT *vt)
41500 {
41501   do
41502     {
41503       vt->cursor_x ++;
41504     }
41505   while (vt->cursor_x < VT_MARGIN_RIGHT &&  ! vt->tabs[ (int) vt->cursor_x-1]);
41506   if (vt->cursor_x > VT_MARGIN_RIGHT)
41507     { vt->cursor_x = VT_MARGIN_RIGHT; }
41508 }
41509 
_vt_rev_htab(VT * vt)41510 static void _vt_rev_htab (VT *vt)
41511 {
41512   do
41513     {
41514       vt->cursor_x--;
41515     }
41516   while ( vt->cursor_x > 1 && ! vt->tabs[ (int) vt->cursor_x-1]);
41517   if (vt->cursor_x < VT_MARGIN_LEFT)
41518     { vt_carriage_return (vt); }
41519 }
41520 
vtcmd_insert_n_tabs(VT * vt,const char * sequence)41521 static void vtcmd_insert_n_tabs (VT *vt, const char *sequence)
41522 {
41523   int n = parse_int (sequence, 1);
41524   while (n--)
41525     {
41526       _vt_htab (vt);
41527     }
41528 }
41529 
vtcmd_rev_n_tabs(VT * vt,const char * sequence)41530 static void vtcmd_rev_n_tabs (VT *vt, const char *sequence)
41531 {
41532   int n = parse_int (sequence, 1);
41533   while (n--)
41534     {
41535       _vt_rev_htab (vt);
41536     }
41537 }
41538 
vtcmd_set_double_width_double_height_top_line(VT * vt,const char * sequence)41539 static void vtcmd_set_double_width_double_height_top_line
41540 (VT *vt, const char *sequence)
41541 {
41542   vt->current_line->double_width         = 1;
41543   vt->current_line->double_height_top    = 1;
41544   vt->current_line->double_height_bottom = 0;
41545 }
vtcmd_set_double_width_double_height_bottom_line(VT * vt,const char * sequence)41546 static void vtcmd_set_double_width_double_height_bottom_line
41547 (VT *vt, const char *sequence)
41548 {
41549   vt->current_line->double_width         = 1;
41550   vt->current_line->double_height_top    = 0;
41551   vt->current_line->double_height_bottom = 1;
41552 }
vtcmd_set_single_width_single_height_line(VT * vt,const char * sequence)41553 static void vtcmd_set_single_width_single_height_line
41554 (VT *vt, const char *sequence)
41555 {
41556   vt->current_line->double_width         = 0;
41557   vt->current_line->double_height_top    = 0;
41558   vt->current_line->double_height_bottom = 0;
41559 }
41560 static void
vtcmd_set_double_width_single_height_line(VT * vt,const char * sequence)41561 vtcmd_set_double_width_single_height_line
41562 (VT *vt, const char *sequence)
41563 {
41564   vt->current_line->double_width         = 1;
41565   vt->current_line->double_height_top    = 0;
41566   vt->current_line->double_height_bottom = 0;
41567 }
41568 
vtcmd_set_led(VT * vt,const char * sequence)41569 static void vtcmd_set_led (VT *vt, const char *sequence)
41570 {
41571   int val = 0;
41572   //fprintf (stderr, "%s\n", sequence);
41573   for (const char *s = sequence; *s; s++)
41574     {
41575       switch (*s)
41576         {
41577           case '0': val = 0; break;
41578           case '1': val = 1; break;
41579           case '2': val = 2; break;
41580           case '3': val = 3; break;
41581           case '4': val = 4; break;
41582           case ';':
41583           case 'q':
41584             if (val == 0)
41585               { vt->leds[0] = vt->leds[1] = vt->leds[2] = vt->leds[3] = 0; }
41586             else
41587               { vt->leds[val-1] = 1; }
41588             val = 0;
41589             break;
41590         }
41591     }
41592 }
41593 
vtcmd_char_at_cursor(VT * vt,const char * sequence)41594 static void vtcmd_char_at_cursor (VT *vt, const char *sequence)
41595 {
41596   char *buf="";
41597   vt_write (vt, buf, strlen (buf) );
41598 }
41599 
vtcmd_DECELR(VT * vt,const char * sequence)41600 static void vtcmd_DECELR (VT *vt, const char *sequence)
41601 {
41602   int ps1 = parse_int (sequence, 0);
41603   int ps2 = 0;
41604   const char *s = strchr (sequence, ';');
41605   if (ps1) {/* unused */};
41606   if (s)
41607     { ps2 = parse_int (s, 0); }
41608   if (ps2 == 1)
41609     { vt->unit_pixels = 1; }
41610   else
41611     { vt->unit_pixels = 0; }
41612 }
41613 
vtcmd_graphics(VT * vt,const char * sequence)41614 static void vtcmd_graphics (VT *vt, const char *sequence)
41615 {
41616   fprintf (stderr, "gfx intro [%s]\n",sequence); // maybe implement such as well?
41617 }
41618 
vtcmd_report(VT * vt,const char * sequence)41619 static void vtcmd_report (VT *vt, const char *sequence)
41620 {
41621   char buf[64]="";
41622   if (!strcmp (sequence, "[5n") ) // DSR device status report
41623     {
41624       sprintf (buf, "\033[0n"); // we're always OK :)
41625     }
41626   else if (!strcmp (sequence, "[?15n") ) // printer status
41627     {
41628       sprintf (buf, "\033[?13n"); // no printer
41629     }
41630   else if (!strcmp (sequence, "[?26n") ) // keyboard dialect
41631     {
41632       sprintf (buf, "\033[?27;1n"); // north american/ascii
41633     }
41634   else if (!strcmp (sequence, "[?25n") ) // User Defined Key status
41635     {
41636       sprintf (buf, "\033[?21n"); // locked
41637     }
41638 #if 0
41639   {"[6n", 0, },  /* id:DSR  cursor position report, yields a reply <tt>\e[Pl;PcR</tt> */
41640 #endif
41641   else if (!strcmp (sequence, "[6n") ) // DSR cursor position report
41642     {
41643       sprintf (buf, "\033[%i;%iR", vt->cursor_y - (vt->origin? (vt->margin_top - 1) :0), (int) vt->cursor_x - (vt->origin? (VT_MARGIN_LEFT-1) :0) );
41644     }
41645   else if (!strcmp (sequence, "[?6n") ) // DECXPR extended cursor position report
41646     {
41647 #if 0
41648   {"[?6n", 0, },  /* id:DEXCPR  extended cursor position report, yields a reply <tt>\e[Pl;PcR</tt> */
41649 #endif
41650       sprintf (buf, "\033[?%i;%i;1R", vt->cursor_y - (vt->origin? (vt->margin_top - 1) :0), (int) vt->cursor_x - (vt->origin? (VT_MARGIN_LEFT-1) :0) );
41651     }
41652   else if (!strcmp (sequence, "[>c") )
41653     {
41654       sprintf (buf, "\033[>23;01;1c");
41655     }
41656   else if (sequence[strlen (sequence)-1]=='c') // device attributes
41657     {
41658       //buf = "\033[?1;2c"; // what rxvt reports
41659       //buf = "\033[?1;6c"; // VT100 with AVO ang GPO
41660       //buf = "\033[?2c";     // VT102
41661       sprintf (buf, "\033[?63;14;4;22c");
41662     }
41663   else if (sequence[strlen (sequence)-1]=='x') // terminal parameters
41664     {
41665       if (!strcmp (sequence, "[1x") )
41666         { sprintf (buf, "\033[3;1;1;120;120;1;0x"); }
41667       else
41668         { sprintf (buf, "\033[2;1;1;120;120;1;0x"); }
41669     }
41670   if (buf[0])
41671     { vt_write (vt, buf, strlen (buf) ); }
41672 }
41673 
41674 static char *charmap_cp437[]=
41675 {
41676   " ","☺","☻","♥","♦","♣","♠","•","◘","○","◙","♂","♀","♪","♫","☼",
41677   "►","◄","↕","‼","¶","§","▬","↨","↑","↓","→","←","∟","↔","▲","▼",
41678   " ","!","\"","#","$","%","&","'","(",")","*","+",",","-",".","/",
41679   "0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?",
41680   "@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O",
41681   "P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_",
41682   "`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
41683   "p","q","r","s","t","u","v","w","x","y","z","{","|","}","~","⌂",
41684   "Ç","ü","é","â","ä","à","å","ç","ê","ë","è","ï","î","ì","Ä","Å",
41685   "É","æ","Æ","ô","ö","ò","û","ù","ÿ","Ö","Ü","¢","£","¥","₧","ƒ",
41686   "á","í","ó","ú","ñ","Ñ","ª","º","¿","⌐","¬","½","¼","¡","«","»",
41687   "░","▒","▓","│","┤","╡","╢","╖","╕","╣","║","╗","╝","╜","╛","┐",
41688   "└","┴","┬","├","─","┼","╞","╟","╚","╔","╩","╦","╠","═","╬","╧",
41689   "╨","╤","╥","╙","╘","╒","╓","╫","╪","┘","┌","█","▄","▌","▐","▀",
41690   "α","ß","Γ","π","Σ","σ","µ","τ","Φ","Θ","Ω","δ","∞","φ","ε","∩",
41691   "≡","±","≥","≤","⌠","⌡","÷","≈","°","∙","·","√","ⁿ","²","■"," "
41692 };
41693 
41694 
41695 static char *charmap_graphics[]=
41696 {
41697   " ","!","\"","#","$","%","&","'","(",")","*","+",",","-",".","/","0",
41698   "1","2","3","4","5","6","7","8","9",":",";","<","=",">","?",
41699   "@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
41700   "Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_",
41701   "◆","▒","␉","␌","␍","␊","°","±","␤","␋","┘","┐","┌","└","┼","⎺","⎻",
41702   "─","⎼","⎽","├","┤","┴","┬","│","≤","≥","π","≠","£","·"," "
41703 };
41704 
41705 static char *charmap_uk[]=
41706 {
41707   " ","!","\"","£","$","%","&","'","(",")","*","+",",","-",".","/","0",
41708   "1","2","3","4","5","6","7","8","9",":",";","<","=",">","?",
41709   "@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
41710   "Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_",
41711   "`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p",
41712   "q","r","s","t","u","v","w","x","y","z","{","|","}","~"," "
41713 };
41714 
41715 static char *charmap_ascii[]=
41716 {
41717   " ","!","\"","#","$","%","&","'","(",")","*","+",",","-",".","/","0",
41718   "1","2","3","4","5","6","7","8","9",":",";","<","=",">","?",
41719   "@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
41720   "Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_",
41721   "`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p",
41722   "q","r","s","t","u","v","w","x","y","z","{","|","}","~"," "
41723 };
41724 
vtcmd_justify(VT * vt,const char * sequence)41725 static void vtcmd_justify (VT *vt, const char *sequence)
41726 {
41727   int n = parse_int (vt->argument_buf, 0);
41728   switch (n)
41729     {
41730       case 0:
41731       case 1:
41732       case 2:
41733       case 3:
41734       case 4:
41735       case 5:
41736       case 6:
41737       case 7:
41738       case 8:
41739         vt->justify = n;
41740         break;
41741       default:
41742         vt->justify = 0;
41743     }
41744 }
41745 
vtcmd_sixel_related_req(VT * vt,const char * sequence)41746 static void vtcmd_sixel_related_req (VT *vt, const char *sequence)
41747 {
41748   fprintf (stderr, "it happens!\n");
41749 }
41750 
vtcmd_set_charmap(VT * vt,const char * sequence)41751 static void vtcmd_set_charmap (VT *vt, const char *sequence)
41752 {
41753   int slot = 0;
41754   int set = sequence[1];
41755   if (sequence[0] == ')') { slot = 1; }
41756   if (set == 'G') { set = 'B'; }
41757   vt->charset[slot] = set;
41758 }
41759 #if 0
41760 
41761 CSI Pm ' }    '
41762 Insert Ps Column (s) (default = 1) (DECIC), VT420 and up.
41763 
41764 CSI Pm ' ~    '
41765 Delete Ps Column (s) (default = 1) (DECDC), VT420 and up.
41766 
41767 
41768 in text.  When bracketed paste mode is set, the program will receive:
41769 ESC [ 2 0 0 ~,
41770       followed by the pasted text, followed by
41771       ESC [ 2 0 1 ~ .
41772 
41773 
41774             CSI I
41775             when the terminal gains focus, and CSI O  when it loses focus.
41776 #endif
41777 
41778 #define COMPAT_FLAG_LEVEL_0   (1<<1)
41779 #define COMPAT_FLAG_LEVEL_1   (1<<2)
41780 #define COMPAT_FLAG_LEVEL_2   (1<<3)
41781 #define COMPAT_FLAG_LEVEL_3   (1<<4)
41782 #define COMPAT_FLAG_LEVEL_4   (1<<5)
41783 #define COMPAT_FLAG_LEVEL_5   (1<<6)
41784 
41785 #define COMPAT_FLAG_LEVEL_102 (1<<7)
41786 
41787 #define COMPAT_FLAG_ANSI      (1<<8)
41788 #define COMPAT_FLAG_OBSOLETE  (1<<9)
41789 
41790 #define COMPAT_FLAG_ANSI_COLOR (1<<10)
41791 #define COMPAT_FLAG_256_COLOR  (1<<11)
41792 #define COMPAT_FLAG_24_COLOR   (1<<12)
41793 
41794 #define COMPAT_FLAG_MOUSE_REPORT (1<<13)
41795 
41796 #define COMPAT_FLAG_AUDIO      (1<<14)
41797 #define COMPAT_FLAG_GRAPHICS   (1<<15)
41798 
41799 #define ANSI    COMPAT_FLAG_ANSI
41800 #define OBS     COMPAT_FLAG_OBSOLETE
41801 
41802 #define VT100   (COMPAT_FLAG_LEVEL_0|COMPAT_FLAG_LEVEL_1)
41803 #define VT102   (VT100|COMPAT_FLAG_LEVEL_102)
41804 #define VT200   (VT102|COMPAT_FLAG_LEVEL_2)
41805 #define VT300   (VT200|COMPAT_FLAG_LEVEL_3)
41806 #define VT400   (VT300|COMPAT_FLAG_LEVEL_4)
41807 #define VT220   VT200
41808 #define VT320   VT300
41809 
41810 #define XTERM   (VT400|COMPAT_FLAG_24_COLOR|COMPAT_FLAG_256_COLOR|COMPAT_FLAG_ANSI_COLOR)
41811 
41812 #define VT2020  (XTERM|COMPAT_FLAG_GRAPHICS|COMPAT_FLAG_AUDIO)
41813 
41814 
41815             static Sequence sequences[]=
41816   {
41817     /*
41818       prefix suffix  command */
41819     //{"B",  0,  vtcmd_break_permitted},
41820     //{"C",  0,  vtcmd_nobreak_here},
41821     {"D", 0,    vtcmd_index, VT100}, /* args: id:IND Index  */
41822     {"E",  0,   vtcmd_next_line}, /* ref:none id:  Next line */
41823     {"_", 'G',  vtcmd_graphics},
41824     {"H",   0,  vtcmd_horizontal_tab_set, VT100}, /* id:HTS Horizontal Tab Set */
41825 
41826     //{"I",  0,  vtcmd_char_tabulation_with_justification},
41827     //{"K",  0,  PLD partial line down
41828     //{"L",  0,  PLU partial line up
41829     {"M",  0,   vtcmd_reverse_index, VT100}, /* ref:none id:RI Reverse Index */
41830     //{"N",  0,  vtcmd_ignore}, /* Set Single Shift 2 - SS2*/
41831     //{"O",  0,  vtcmd_ignore}, /* Set Single Shift 3 - SS3*/
41832 
41833 #if 0
41834     {"[0F", 0, vtcmd_justify, ANSI}, /* ref:none id:JFY disable justification and wordwrap  */ // needs special link to ANSI standard
41835     {"[1F", 0, vtcmd_justify, ANSI}, /* ref:none id:JFY enable wordwrap  */
41836 #endif
41837 
41838     /* these need to occur before vtcmd_preceding_line to have precedence */
41839     {"[0 F", 0, vtcmd_justify, ANSI},
41840     {"[1 F", 0, vtcmd_justify, ANSI},
41841     {"[2 F", 0, vtcmd_justify},
41842     {"[3 F", 0, vtcmd_justify},
41843     {"[4 F", 0, vtcmd_justify},
41844     {"[5 F", 0, vtcmd_justify},
41845     {"[6 F", 0, vtcmd_justify},
41846     {"[7 F", 0, vtcmd_justify},
41847     {"[8 F", 0, vtcmd_justify},
41848 // XXX missing DECIC DECDC  insert and delete column
41849     {"[", 'A', vtcmd_cursor_up, VT100},   /* args:Pn    id:CUU Cursor Up */
41850     {"[",  'B', vtcmd_cursor_down, VT100}, /* args:Pn    id:CUD Cursor Down */
41851     {"[",  'C', vtcmd_cursor_forward, VT100}, /* args:Pn id:CUF Cursor Forward */
41852     {"[",  'D', vtcmd_cursor_backward, VT100}, /* args:Pn id:CUB Cursor Backward */
41853     {"[",  'j', vtcmd_cursor_backward, ANSI}, /* args:Pn ref:none id:HPB Horizontal Position Backward */
41854     {"[",  'k', vtcmd_cursor_up, ANSI}, /* args:Pn ref:none id:VPB Vertical Position Backward */
41855     {"[",  'E', vtcmd_next_line, VT100}, /* args:Pn id:CNL Cursor Next Line */
41856     {"[",  'F', vtcmd_cursor_preceding_line, VT100}, /* args:Pn id:CPL Cursor Preceding Line */
41857     {"[",  'G', vtcmd_horizontal_position_absolute}, /* args:Pn id:CHA Cursor Horizontal Absolute */
41858     {"[",  'H', vtcmd_cursor_position, VT100}, /* args:Pl;Pc id:CUP Cursor Position */
41859     {"[",  'I', vtcmd_insert_n_tabs}, /* args:Pn id:CHT Cursor Horizontal Forward Tabulation */
41860     {"[",  'J', vtcmd_erase_in_display, VT100}, /* args:Ps id:ED Erase in Display */
41861     {"[",  'K', vtcmd_erase_in_line, VT100}, /* args:Ps id:EL Erase in Line */
41862     {"[",  'L', vtcmd_insert_blank_lines, VT102}, /* args:Pn id:IL Insert Line */
41863     {"[",  'M', vtcmd_delete_n_lines, VT102}, /* args:Pn id:DL Delete Line   */
41864     // [ N is EA - Erase in field
41865     // [ O is EA - Erase in area
41866     {"[",  'P', vtcmd_delete_n_chars, VT102}, /* args:Pn id:DCH Delete Character */
41867     // [ Q is SEE - Set editing extent
41868     // [ R is CPR - active cursor position report
41869     {"[?", 'S', vtcmd_sixel_related_req},
41870     {"[",  'S', vtcmd_scroll_up, VT100},   /* args:Pn id:SU Scroll Up */
41871     {"[",  'T', vtcmd_scroll_down, VT100}, /* args:Pn id:SD Scroll Down */
41872     {"[",/*SP*/'U', vtcmd_set_line_home, ANSI}, /* args:PnSP id=SLH Set Line Home */
41873     {"[",/*SP*/'V', vtcmd_set_line_limit, ANSI},/* args:PnSP id=SLL Set Line Limit */
41874     // [ W is cursor tabulation control
41875     // [ Pn Y  - cursor line tabulation
41876     //
41877     {"[",  'X', vtcmd_erase_n_chars}, /* args:Pn id:ECH Erase Character */
41878     {"[",  'Z', vtcmd_rev_n_tabs},    /* args:Pn id:CBT Cursor Backward Tabulation */
41879     {"[",  '^', vtcmd_scroll_down}  , /* muphry alternate from ECMA */
41880     {"[",  '@', vtcmd_insert_character, VT102}, /* args:Pn id:ICH Insert Character */
41881 
41882     {"[",  'a', vtcmd_cursor_forward, ANSI}, /* args:Pn id:HPR Horizontal Position Relative */
41883     {"[",  'b', vtcmd_cursor_forward, ANSI}, /* REP previous char XXX incomplete */
41884     {"[",  'c', vtcmd_report}, /* ref:none id:DA args:... Device Attributes */
41885     {"[",  'd', vtcmd_goto_row},       /* args:Pn id:VPA Vertical Position Absolute  */
41886     {"[",  'e', vtcmd_cursor_down},    /* args:Pn id:VPR Vertical Position Relative */
41887     {"[",  'f', vtcmd_cursor_position, VT100}, /* args:Pl;Pc id:HVP Cursor Position */
41888     {"[g", 0,   vtcmd_clear_current_tab, VT100}, /* id:TBC clear current tab */
41889     {"[0g", 0,  vtcmd_clear_current_tab, VT100}, /* id:TBC clear current tab */
41890     {"[3g", 0,  vtcmd_clear_all_tabs, VT100},    /* id:TBC clear all tabs */
41891     {"[",  'm', vtcmd_set_graphics_rendition, VT100}, /* args:Ps;Ps;.. id:SGR Select Graphics Rendition */
41892     {"[",  'n', vtcmd_report, VT200}, /* id:DSR args:... CPR Cursor Position Report  */
41893     {"[",  'r', vtcmd_set_top_and_bottom_margins, VT100}, /* args:Pt;Pb id:DECSTBM Set Top and Bottom Margins */
41894 #if 0
41895     // handled by set_left_and_right_margins - in if 0 to be documented
41896     {"[s",  0,  vtcmd_save_cursor_position, VT100}, /*ref:none id:SCP Save Cursor Position */
41897 #endif
41898     {"[u",  0,  vtcmd_restore_cursor_position, VT100}, /*ref:none id:RCP Restore Cursor Position */
41899     {"[",  's', vtcmd_set_left_and_right_margins, VT400}, /* args:Pl;Pr id:DECSLRM Set Left and Right Margins */
41900     {"[",  '`', vtcmd_horizontal_position_absolute, ANSI},  /* args:Pn id:HPA Horizontal Position Absolute */
41901 
41902     {"[",  'h', vtcmd_set_mode, VT100},   /* args:Pn[;...] id:SM Set Mode */
41903     {"[",  'l', vtcmd_set_mode, VT100}, /* args:Pn[;...]  id:RM Reset Mode */
41904     {"[",  't', vtcmd_set_t},
41905     {"[",  'q', vtcmd_set_led, VT100}, /* args:Ps id:DECLL Load LEDs */
41906     {"[",  'x', vtcmd_report}, /* ref:none id:DECREQTPARM */
41907     {"[",  'z', vtcmd_DECELR}, /* ref:none id:DECELR set locator res  */
41908 
41909     {"5",   0,  vtcmd_char_at_cursor, VT300}, /* ref:none id:DECXMIT */
41910     {"6",   0,  vtcmd_back_index, VT400}, /* id:DECBI Back index (hor. scroll) */
41911     {"7",   0,  vtcmd_save_cursor, VT100}, /* id:DECSC Save Cursor */
41912     {"8",   0,  vtcmd_restore_cursor, VT100}, /* id:DECRC Restore Cursor */
41913     {"9",   0,  vtcmd_forward_index, VT400}, /* id:DECFI Forward index (hor. scroll)*/
41914 
41915     //{"Z", 0,  vtcmd_device_attributes},
41916     //{"%G",0,  vtcmd_set_default_font}, // set_alternate_font
41917 
41918 
41919     {"(0",  0,   vtcmd_set_charmap},
41920     {"(1",  0,   vtcmd_set_charmap},
41921     {"(2",  0,   vtcmd_set_charmap},
41922     {"(A",  0,   vtcmd_set_charmap},
41923     {"(B",  0,   vtcmd_set_charmap},
41924     {")0",  0,   vtcmd_set_charmap},
41925     {")1",  0,   vtcmd_set_charmap},
41926     {")2",  0,   vtcmd_set_charmap},
41927     {")A",  0,   vtcmd_set_charmap},
41928     {")B",  0,   vtcmd_set_charmap},
41929     {"%G",  0,   vtcmd_set_charmap},
41930 
41931     {"#3",  0,   vtcmd_set_double_width_double_height_top_line, VT100}, /*id:DECDHL Top half of double-width, double-height line */
41932     {"#4",  0,   vtcmd_set_double_width_double_height_bottom_line, VT100}, /*id:DECDHL Bottom half of double-width, double-height line */
41933     {"#5",  0,   vtcmd_set_single_width_single_height_line, VT100}, /* id:DECSWL Single-width line */
41934     {"#6",  0,   vtcmd_set_double_width_single_height_line, VT100}, /* id:DECDWL Double-width line */
41935 
41936     {"#8",  0,   vtcmd_screen_alignment_display, VT100}, /* id:DECALN Screen Alignment Pattern */
41937     {"=",   0,   vtcmd_ignore},  // keypad mode change
41938     {">",   0,   vtcmd_ignore},  // keypad mode change
41939     {"c",   0,   vtcmd_reset_to_initial_state, VT100}, /* id:RIS Reset to Initial State */
41940     {"[!", 'p',  vtcmd_ignore},       // soft reset?
41941     {"[",  'p',  vtcmd_request_mode}, /* args:Pa$ id:DECRQM Request ANSI Mode */
41942 #if 0
41943     {"[?",  'p',  vtcmd_request_mode}, /* args:Pd$ id:DECRQM Request DEC Mode */
41944 #endif
41945 
41946     {NULL, 0, NULL}
41947   };
41948 
handle_sequence(VT * vt,const char * sequence)41949   static void handle_sequence (VT *vt, const char *sequence)
41950 {
41951   int i0 = strlen (sequence)-1;
41952   int i;
41953   vt->rev ++;
41954   for (i = 0; sequences[i].prefix; i++)
41955     {
41956       if (!strncmp (sequence, sequences[i].prefix, strlen (sequences[i].prefix) ) )
41957         {
41958           if (! (sequences[i].suffix && (sequence[i0] != sequences[i].suffix) ) )
41959             {
41960               VT_command ("%s", sequence);
41961               sequences[i].vtcmd (vt, sequence);
41962               return;
41963             }
41964         }
41965     }
41966 #ifndef ASANBUILD
41967   VT_warning ("unhandled: %c%c%c%c%c%c%c%c%c\n", sequence[0], sequence[1], sequence[2], sequence[3], sequence[4], sequence[5], sequence[6], sequence[7], sequence[8]);
41968 #endif
41969 }
41970 
vt_line_feed(VT * vt)41971 static void vt_line_feed (VT *vt)
41972 {
41973   int was_home = vt->at_line_home;
41974   if (vt->margin_top == 1 && vt->margin_bottom == vt->rows)
41975     {
41976       if (vt->lines == NULL ||
41977           (vt->lines->data == vt->current_line && vt->cursor_y != vt->rows) )
41978         {
41979           vt->current_line = vt_line_new_with_size ("", vt->cols);
41980           ctx_list_prepend (&vt->lines, vt->current_line);
41981           vt->line_count++;
41982         }
41983       if (vt->cursor_y >= vt->margin_bottom)
41984         {
41985           vt->cursor_y = vt->margin_bottom;
41986           vt_scroll (vt, -1);
41987         }
41988       else
41989         {
41990           vt->cursor_y++;
41991         }
41992     }
41993   else
41994     {
41995       if (vt->lines->data == vt->current_line &&
41996           (vt->cursor_y != vt->margin_bottom) && 0)
41997         {
41998           vt->current_line = vt_line_new_with_size ("", vt->cols);
41999           ctx_list_prepend (&vt->lines, vt->current_line);
42000           vt->line_count++;
42001         }
42002       vt->cursor_y++;
42003       if (vt->cursor_y > vt->margin_bottom)
42004         {
42005           vt->cursor_y = vt->margin_bottom;
42006           vt_scroll (vt, -1);
42007         }
42008     }
42009   _vt_move_to (vt, vt->cursor_y, vt->cursor_x);
42010   if (vt->cr_on_lf)
42011     { vt_carriage_return (vt); }
42012   vt_trimlines (vt, vt->rows);
42013   if (was_home)
42014     { vt_carriage_return (vt); }
42015 }
42016 
42017 //#include "vt-encodings.h"
42018 
42019 #if CTX_SDL
vt_state_apc_audio(VT * vt,int byte)42020 static void vt_state_apc_audio (VT *vt, int byte)
42021 {
42022   if ( (byte < 32) && ( (byte < 8) || (byte > 13) ) )
42023     {
42024       vt_audio (vt, vt->argument_buf);
42025       vt->state = ( (byte == 27) ?  vt_state_swallow : vt_state_neutral);
42026     }
42027   else
42028     {
42029       vt_argument_buf_add (vt, byte);
42030     }
42031 }
42032 
42033 #else
42034 
vt_audio_task(VT * vt,int click)42035 void vt_audio_task (VT *vt, int click)
42036 {
42037 }
42038 
vt_bell(VT * vt)42039 void vt_bell (VT *vt)
42040 {
42041 }
vt_state_apc_audio(VT * vt,int byte)42042 static void vt_state_apc_audio (VT *vt, int byte)
42043 {
42044   vt->state = vt_state_apc_generic;
42045 }
42046 
42047 #endif
42048 
42049 static void
vt_carriage_return(VT * vt)42050 vt_carriage_return (VT *vt)
42051 {
42052   _vt_move_to (vt, vt->cursor_y, vt->cursor_x);
42053   vt->cursor_x = VT_MARGIN_LEFT;
42054   vt->at_line_home = 1;
42055 }
42056 
42057 /* if the byte is a non-print control character, handle it and return 1
42058  * oterhwise return 0*/
_vt_handle_control(VT * vt,int byte)42059 static int _vt_handle_control (VT *vt, int byte)
42060 {
42061   /* the big difference between ANSI-BBS mode and VT100+ mode is that
42062    * most C0 characters are printable
42063    */
42064   if (CTX_UNLIKELY(vt->encoding == 1)) // this codepage is for ansi-bbs use
42065     switch (byte)
42066       {
42067         case '\0':
42068           return 1;
42069         case 1:    /* SOH start of heading */
42070         case 2:    /* STX start of text */
42071         case 3:    /* ETX end of text */
42072         case 4:    /* EOT end of transmission */
42073         case 5:    /* ENQuiry */
42074         case 6:    /* ACKnolwedge */
42075         case '\v': /* VT vertical tab */
42076         case '\f': /* VF form feed */
42077         case 14: /* SO shift in - alternate charset */
42078         case 15: /* SI shift out - (back to normal) */
42079         case 16: /* DLE data link escape */
42080         case 17: /* DC1 device control 1 - XON */
42081         case 18: /* DC2 device control 2 */
42082         case 19: /* DC3 device control 3 - XOFF */
42083         case 20: /* DC4 device control 4 */
42084         case 21: /* NAK negative ack */
42085         case 22: /* SYNchronous idle */
42086         case 23: /* ETB end of trans. blk */
42087         case 24: /* CANcel (vt100 aborts sequence) */
42088         case 25: /* EM  end of medium */
42089         case 26: /* SUB stitute */
42090         case 28: /* FS file separator */
42091         case 29: /* GS group separator */
42092         case 30: /* RS record separator */
42093         case 31: /* US unit separator */
42094           _vt_add_str (vt, charmap_cp437[byte]);
42095           return 1;
42096       }
42097   switch (byte)
42098     {
42099       case '\0':
42100       case 1:    /* SOH start of heading */
42101       case 2:    /* STX start of text */
42102       case 3:    /* ETX end of text */
42103       case 4:    /* EOT end of transmission */
42104       case 6:    /* ACKnolwedge */
42105         return 1;
42106       case 5:    /* ENQuiry */
42107         {
42108           const char *reply = getenv ("TERM_ENQ_REPLY");
42109           if (reply)
42110             {
42111               char *copy = strdup (reply);
42112               for (uint8_t *c = (uint8_t *) copy; *c; c++)
42113                 {
42114                   if (*c < ' ' || * c > 127) { *c = 0; }
42115                 }
42116               vt_write (vt, reply, strlen (reply) );
42117               free (copy);
42118             }
42119         }
42120         return 1;
42121       case '\a': /* BELl */
42122         vt_bell (vt);
42123         return 1;
42124       case '\b': /* BS */
42125         _vt_backspace (vt);
42126         return 1;
42127       case '\t': /* HT tab */
42128         _vt_htab (vt);
42129         return 1;
42130       case '\v': /* VT vertical tab */
42131       case '\f': /* VF form feed */
42132       case '\n': /* LF line ffed */
42133         vt_line_feed (vt);
42134         return 1;
42135       case '\r': /* CR carriage return */
42136         vt_carriage_return (vt);
42137         return 1;
42138       case 14: /* SO shift in - alternate charset */
42139         vt->shifted_in = 1;  // XXX not in vt52
42140         return 1;
42141       case 15: /* SI shift out - (back to normal) */
42142         vt->shifted_in = 0;
42143         return 1;
42144       case 16: /* DLE data link escape */
42145       case 17: /* DC1 device control 1 - XON */
42146       case 18: /* DC2 device control 2 */
42147       case 19: /* DC3 device control 3 - XOFF */
42148       case 20: /* DC4 device control 4 */
42149       case 21: /* NAK negative ack */
42150       case 22: /* SYNchronous idle */
42151       case 23: /* ETB end of trans. blk */
42152       case 24: /* CANcel (vt100 aborts sequence) */
42153       case 25: /* EM  end of medium */
42154       case 26: /* SUB stitute */
42155         _vt_add_str (vt, "¿");  // in vt52? XXX
42156         return 1;
42157       case 27: /* ESCape */
42158         return 0;
42159         break;
42160       case 28: /* FS file separator */
42161       case 29: /* GS group separator */
42162       case 30: /* RS record separator */
42163       case 31: /* US unit separator */
42164       case 127: /* DEL */
42165         return 1;
42166       default:
42167         return 0;
42168     }
42169 }
42170 
vt_open_log(VT * vt,const char * path)42171 void vt_open_log (VT *vt, const char *path)
42172 {
42173   unlink (path);
42174   vt->log = fopen (path, "w");
42175 }
42176 
42177 /* the function shared by sixels, kitty mode and iterm2 mode for
42178  * doing inline images. it attaches an image to the current line
42179  */
display_image(VT * vt,Image * image,int col,float xoffset,float yoffset,int rows,int cols,int subx,int suby,int subw,int subh)42180 static void display_image (VT *vt, Image *image,
42181                            int col,
42182                            float xoffset,
42183                            float yoffset,
42184                            int rows,
42185                            int cols,
42186                            int subx,
42187                            int suby,
42188                            int subw,
42189                            int subh
42190                           )
42191 {
42192   int i = 0;
42193   for (i = 0; vt->current_line->images[i] && i < 4; i++)
42194   {
42195      if (vt->current_line->image_col[i] == vt->cursor_x)
42196        break;
42197   }
42198   //for (i = 0; vt->current_line->images[i] && i < 4; i++);
42199   if (i >= 4) { i = 3; }
42200   /* this needs a struct and dynamic allocation */
42201   vt->current_line->images[i] = image;
42202   vt->current_line->image_col[i] = vt->cursor_x;
42203   vt->current_line->image_X[i] = xoffset;
42204   vt->current_line->image_Y[i] = yoffset;
42205   vt->current_line->image_subx[i] = subx;
42206   vt->current_line->image_suby[i] = suby;
42207   vt->current_line->image_subw[i] = subw;
42208   vt->current_line->image_subh[i] = subh;
42209   vt->current_line->image_rows[i] = rows;
42210   vt->current_line->image_cols[i] = cols;
42211 }
42212 
42213 static int vt_gfx_pending=0;
42214 
vt_gfx(VT * vt,const char * command)42215 void vt_gfx (VT *vt, const char *command)
42216 {
42217   const char *payload = NULL;
42218   char key = 0;
42219   int  value;
42220   int  pos = 1;
42221   if (vt->gfx.multichunk == 0)
42222     {
42223       memset (&vt->gfx, 0, sizeof (GfxState) );
42224       vt->gfx.action='t';
42225       vt->gfx.transmission='d';
42226     }
42227   while (command[pos] != ';')
42228     {
42229       pos ++; // G or ,
42230       if (command[pos] == ';') { break; }
42231       key = command[pos];
42232       pos++;
42233       if (command[pos] == ';') { break; }
42234       pos ++; // =
42235       if (command[pos] == ';') { break; }
42236       if (command[pos] >= '0' && command[pos] <= '9')
42237         { value = atoi (&command[pos]); }
42238       else
42239         { value = command[pos]; }
42240       while (command[pos] &&
42241              command[pos] != ',' &&
42242              command[pos] != ';') { pos++; }
42243       switch (key)
42244         {
42245           case 'a':
42246             vt->gfx.action = value;
42247             break;
42248           case 'd':
42249             vt->gfx.delete = value;
42250             break;
42251           case 'i':
42252             vt->gfx.id = value;
42253             break;
42254           case 'S':
42255             vt->gfx.buf_size = value;
42256             break;
42257           case 's':
42258             vt->gfx.buf_width = value;
42259             break;
42260           case 'v':
42261             vt->gfx.buf_height = value;
42262             break;
42263           case 'f':
42264             vt->gfx.format = value;
42265             break;
42266           case 'm':
42267             vt->gfx.multichunk = value;
42268             break;
42269           case 'o':
42270             vt->gfx.compression = value;
42271             break;
42272           case 't':
42273             vt->gfx.transmission = value;
42274             break;
42275           case 'x':
42276             vt->gfx.x = value;
42277             break;
42278           case 'y':
42279             vt->gfx.y = value;
42280             break;
42281           case 'w':
42282             vt->gfx.w = value;
42283             break;
42284           case 'h':
42285             vt->gfx.h = value;
42286             break;
42287           case 'X':
42288             vt->gfx.x_cell_offset = value;
42289             break;
42290           case 'Y':
42291             vt->gfx.y_cell_offset = value;
42292             break;
42293           case 'c':
42294             vt->gfx.columns = value;
42295             break;
42296           case 'r':
42297             vt->gfx.rows = value;
42298             break;
42299           case 'z':
42300             vt->gfx.z_index = value;
42301             break;
42302         }
42303     }
42304   payload = &command[pos+1];
42305   {
42306     int chunk_size = strlen (payload);
42307     int old_size = vt->gfx.data_size;
42308     // accumulate incoming data
42309     if (vt->gfx.data == NULL)
42310       {
42311         vt->gfx.data_size = chunk_size;
42312         vt->gfx.data = malloc (vt->gfx.data_size + 1);
42313       }
42314     else
42315       {
42316         vt->gfx.data_size += chunk_size;
42317         vt->gfx.data = realloc (vt->gfx.data, vt->gfx.data_size + 1);
42318       }
42319     memcpy (vt->gfx.data + old_size, payload, chunk_size);
42320     vt->gfx.data[vt->gfx.data_size]=0;
42321   }
42322   if (vt->gfx.multichunk == 0)
42323     {
42324       if (vt->gfx.transmission != 'd') /* */
42325         {
42326           char buf[256];
42327           sprintf (buf, "\033_Gi=%i;only direct transmission supported\033\\",
42328                    vt->gfx.id);
42329           vt_write (vt, buf, strlen (buf) );
42330           goto cleanup;
42331         }
42332       {
42333         int bin_length = vt->gfx.data_size;
42334         uint8_t *data2 = malloc (vt->gfx.data_size);
42335         bin_length = ctx_base642bin ( (char *) vt->gfx.data,
42336                                      &bin_length,
42337                                      data2);
42338         memcpy (vt->gfx.data, data2, bin_length + 1);
42339         vt->gfx.data_size = bin_length;
42340         free (data2);
42341       }
42342       if (vt->gfx.buf_width)
42343         {
42344           // implicit buf_size
42345           vt->gfx.buf_size = vt->gfx.buf_width * vt->gfx.buf_height *
42346                              (vt->gfx.format == 24 ? 3 : 4);
42347         }
42348       if (vt->gfx.compression == 'z')
42349         {
42350           //vt->gfx.buf_size)
42351           unsigned char *data2 = malloc (vt->gfx.buf_size + 1);
42352           /* if a buf size is set (rather compression, but
42353            * this works first..) then */
42354           unsigned long actual_uncompressed_size = vt->gfx.buf_size;
42355           int z_result = uncompress (data2, &actual_uncompressed_size,
42356                                      vt->gfx.data,
42357                                      vt->gfx.data_size);
42358           if (z_result != Z_OK)
42359             {
42360               char buf[256]= "\033_Go=z;zlib error\033\\";
42361               vt_write (vt, buf, strlen (buf) );
42362               goto cleanup;
42363             }
42364           free (vt->gfx.data);
42365           vt->gfx.data = data2;
42366           vt->gfx.data_size = actual_uncompressed_size;
42367           vt->gfx.compression = 0;
42368         }
42369       if (vt->gfx.format == 100)
42370         {
42371           int channels;
42372           uint8_t *new_data = stbi_load_from_memory (vt->gfx.data, vt->gfx.data_size, &vt->gfx.buf_width, &vt->gfx.buf_height, &channels, 4);
42373           if (!new_data)
42374             {
42375               char buf[256]= "\033_Gf=100;image decode error\033\\";
42376               vt_write (vt, buf, strlen (buf) );
42377               goto cleanup;
42378             }
42379           vt->gfx.format = 32;
42380           free (vt->gfx.data);
42381           vt->gfx.data = new_data;
42382           vt->gfx.data_size= vt->gfx.buf_width * vt->gfx.buf_height * 4;
42383         }
42384       Image *image = NULL;
42385       switch (vt->gfx.action)
42386         {
42387           case 't': // transfer
42388           case 'T': // transfer and present
42389             switch (vt->gfx.format)
42390               {
42391                 case 24:
42392                 case 32:
42393                   image = image_add (vt->gfx.buf_width, vt->gfx.buf_height, vt->gfx.id,
42394                                      vt->gfx.format, vt->gfx.data_size, vt->gfx.data);
42395                   vt->gfx.data = NULL;
42396                   vt->gfx.data_size=0;
42397                   break;
42398               }
42399             if (vt->gfx.action == 't')
42400               { break; }
42401           // fallthrough
42402           case 'p': // present
42403             if (!image && vt->gfx.id)
42404               { image = image_query (vt->gfx.id); }
42405             if (image)
42406               {
42407                 display_image (vt, image, vt->cursor_x, vt->gfx.rows, vt->gfx.columns,
42408                                vt->gfx.x_cell_offset * 1.0 / vt->cw,
42409                                vt->gfx.y_cell_offset * 1.0 / vt->ch,
42410                                vt->gfx.x,
42411                                vt->gfx.y,
42412                                vt->gfx.w,
42413                                vt->gfx.h);
42414                 int right = (image->width + (vt->cw-1) ) /vt->cw;
42415                 int down = (image->height + (vt->ch-1) ) /vt->ch;
42416                 for (int i = 0; i<down - 1; i++)
42417                   { vtcmd_index (vt, " "); }
42418                 for (int i = 0; i<right; i++)
42419                   { vtcmd_cursor_forward (vt, " "); }
42420               }
42421             break;
42422           case 'q': // query
42423             if (image_query (vt->gfx.id) )
42424               {
42425                 char buf[256];
42426                 sprintf (buf, "\033_Gi=%i;OK\033\\", vt->gfx.id);
42427                 vt_write (vt, buf, strlen (buf) );
42428               }
42429             break;
42430           case 'd': // delete
42431             {
42432               int row = vt->rows; // probably not right at start of session XXX
42433               for (CtxList *l = vt->lines; l; l = l->next, row --)
42434                 {
42435                   VtLine *line = l->data;
42436                   for (int i = 0; i < 4; i ++)
42437                     {
42438                       int free_resource = 0;
42439                       int match = 0;
42440                       if (line->images[i])
42441                         switch (vt->gfx.delete)
42442                           {
42443                             case 'A':
42444                               free_resource = 1;
42445                               /* FALLTHROUGH */
42446                             case 'a': /* all images visible on screen */
42447                               match = 1;
42448                               break;
42449                             case 'I':
42450                               free_resource = 1;
42451                               /* FALLTHROUGH */
42452                             case 'i': /* all images with specified id */
42453                               if ( ( (Image *) (line->images[i]) )->id == vt->gfx.id)
42454                                 { match = 1; }
42455                               break;
42456                             case 'P':
42457                               free_resource = 1;
42458                               /* FALLTHROUGH */
42459                             case 'p': /* all images intersecting cell
42460           specified with x and y */
42461                               if (line->image_col[i] == vt->gfx.x &&
42462                                   row == vt->gfx.y)
42463                                 { match = 1; }
42464                               break;
42465                             case 'Q':
42466                               free_resource = 1;
42467                               /* FALLTHROUGH */
42468                             case 'q': /* all images with specified cell (x), row(y) and z */
42469                               if (line->image_col[i] == vt->gfx.x &&
42470                                   row == vt->gfx.y)
42471                                 { match = 1; }
42472                               break;
42473                             case 'Y':
42474                               free_resource = 1;
42475                               /* FALLTHROUGH */
42476                             case 'y': /* all images with specified row (y) */
42477                               if (row == vt->gfx.y)
42478                                 { match = 1; }
42479                               break;
42480                             case 'X':
42481                               free_resource = 1;
42482                               /* FALLTHROUGH */
42483                             case 'x': /* all images with specified column (x) */
42484                               if (line->image_col[i] == vt->gfx.x)
42485                                 { match = 1; }
42486                               break;
42487                             case 'Z':
42488                               free_resource = 1;
42489                               /* FALLTHROUGH */
42490                             case 'z': /* all images with specified z-index (z) */
42491                               break;
42492                           }
42493                       if (match)
42494                         {
42495                           line->images[i] = NULL;
42496                           if (free_resource)
42497                             {
42498                               // XXX : NYI
42499                             }
42500                         }
42501                     }
42502                 }
42503             }
42504             break;
42505         }
42506 cleanup:
42507       if (vt->gfx.data)
42508         { free (vt->gfx.data); }
42509       vt->gfx.data = NULL;
42510       vt->gfx.data_size=0;
42511       vt->gfx.multichunk=0;
42512       vt_gfx_pending = 0;
42513     }
42514   else
42515      vt_gfx_pending = 1;
42516 }
42517 
vt_state_vt52(VT * vt,int byte)42518 static void vt_state_vt52 (VT *vt, int byte)
42519 {
42520   /* in vt52 mode, utf8_pos being non 0 means we got ESC prior */
42521   switch (vt->utf8_pos)
42522     {
42523       case 0:
42524         if (_vt_handle_control (vt, byte) == 0)
42525           switch (byte)
42526             {
42527               case 27: /* ESC */
42528                 vt->utf8_pos = 1;
42529                 break;
42530               default:
42531                 {
42532                   char str[2] = {byte & 127, 0};
42533                   /* we're not validating utf8, and our utf8 manipulation
42534                    * functions are not robust against malformed utf8,
42535                    * hence we strip to ascii
42536                    */
42537                   _vt_add_str (vt, str);
42538                 }
42539                 break;
42540             }
42541         break;
42542       case 1:
42543         vt->utf8_pos = 0;
42544         switch (byte)
42545           {
42546             case 'A':
42547               vtcmd_cursor_up (vt, " ");
42548               break;
42549             case 'B':
42550               vtcmd_cursor_down (vt, " ");
42551               break;
42552             case 'C':
42553               vtcmd_cursor_forward (vt, " ");
42554               break;
42555             case 'D':
42556               vtcmd_cursor_backward (vt, " ");
42557               break;
42558             case 'F':
42559               vtcmd_set_alternate_font (vt, " ");
42560               break;
42561             case 'G':
42562               vtcmd_set_default_font (vt, " ");
42563               break;
42564             case 'H':
42565               _vt_move_to (vt, 1, 1);
42566               break;
42567             case 'I':
42568               vtcmd_reverse_index (vt, " ");
42569               break;
42570             case 'J':
42571               vtcmd_erase_in_display (vt, "[0J");
42572               break;
42573             case 'K':
42574               vtcmd_erase_in_line (vt, "[0K");
42575               break;
42576             case 'Y':
42577               vt->utf8_pos = 2;
42578               break;
42579             case 'Z':
42580               vt_write (vt, "\033/Z", 3);
42581               break;
42582             case '<':
42583               vt->state = vt_state_neutral;
42584               break;
42585             default:
42586               break;
42587           }
42588         break;
42589       case 2:
42590         _vt_move_to (vt, byte - 31, vt->cursor_x);
42591         vt->utf8_pos = 3;
42592         break;
42593       case 3:
42594         _vt_move_to (vt, vt->cursor_y, byte - 31);
42595         vt->utf8_pos = 0;
42596         break;
42597     }
42598 }
42599 
vt_sixels(VT * vt,const char * sixels)42600 static void vt_sixels (VT *vt, const char *sixels)
42601 {
42602   uint8_t colors[256][3];
42603   int width = 0;
42604   int height = 0;
42605   int x = 0;
42606   int y = 0;
42607   Image *image;
42608   uint8_t *pixels = NULL;
42609   int repeat = 1;
42610   const char *p = sixels;
42611   int pal_no = 0;
42612 #if 0
42613   for (; *p && *p != ';'; p++);
42614   if (*p == ';') { p ++; }
42615   printf ("%i:[%c]%i\n", __LINE__, *p, atoi (p) );
42616   // should be 0
42617   for (; *p && *p != ';'; p++);
42618   if (*p == ';') { p ++; }
42619   printf ("%i:[%c]%i\n", __LINE__, *p, atoi (p) );
42620   // if 1 then transparency is enabled - otherwise use bg color
42621   for (; *p && *p != 'q'; p++);
42622 #endif
42623   //for (; *p && *p != '"'; p++);
42624   while (*p && *p != 'q') { p++; }
42625   if (*p == 'q') { p++; }
42626   if (*p == '"') { p++; }
42627   //printf ("%i:[%c]%i\n", __LINE__, *p, atoi (p));
42628   for (; *p && *p != ';'; p++);
42629   if (*p == ';') { p ++; }
42630   //printf ("%i:[%c]%i\n", __LINE__, *p, atoi (p));
42631   for (; *p && *p != ';'; p++);
42632   if (*p == ';') { p ++; }
42633   width = atoi (p);
42634   for (; *p && *p != ';'; p++);
42635   if (*p == ';') { p ++; }
42636   height = atoi (p);
42637   if (width * height > 2048 * 2048)
42638     return;
42639   if (width <= 0 || height <=0)
42640     {
42641       width = 0;
42642       height = 0;
42643       // XXX  : a copy paste dry-run
42644       for (const char *t=p; *t; t++)
42645         {
42646           if (*t == '#')
42647             {
42648               t++;
42649               while (*t && *t >= '0' && *t <= '9') { t++; }
42650               if (*t == ';')
42651                 {
42652                   for (; *t && *t != ';'; t++);
42653                   if (*t == ';') { t ++; }
42654                   for (; *t && *t != ';'; t++);
42655                   if (*t == ';') { t ++; }
42656                   for (; *t && *t != ';'; t++);
42657                   if (*t == ';') { t ++; }
42658                   for (; *t && *t != ';'; t++);
42659                   if (*t == ';') { t ++; }
42660                   while (*t && *t >= '0' && *t <= '9') { t++; }
42661                   t--;
42662                 }
42663               else
42664                 {
42665                   t--;
42666                 }
42667             }
42668           else if (*t == '$') // carriage return
42669             {
42670               if (x > width) { width = x; }
42671               x = 0;
42672             }
42673           else if (*t == '-') // line feed
42674             {
42675               y += 6;
42676               x = 0;
42677             }
42678           else if (*t == '!') // repeat
42679             {
42680               t++;
42681               repeat = atoi (t);
42682               while (*t && *t >= '0' && *t <= '9') { t++; }
42683               t--;
42684             }
42685           else if (*t >= '?' && *t <= '~') /* sixel data */
42686             {
42687               x += repeat;
42688               repeat = 1;
42689             }
42690         }
42691       height = y;
42692     }
42693   x = 0;
42694   y = 0;
42695   pixels = calloc (width * (height + 6), 4);
42696   image = image_add (width, height, 0,
42697                      32, width*height*4, pixels);
42698   uint8_t *dst = pixels;
42699   for (; *p; p++)
42700     {
42701       if (*p == '#')
42702         {
42703           p++;
42704           pal_no = atoi (p);
42705           if (pal_no < 0 || pal_no > 255) { pal_no = 255; }
42706           while (*p && *p >= '0' && *p <= '9') { p++; }
42707           if (*p == ';')
42708             {
42709               /* define a palette */
42710               for (; *p && *p != ';'; p++);
42711               if (*p == ';') { p ++; }
42712               // color_model , 2 is rgb
42713               for (; *p && *p != ';'; p++);
42714               if (*p == ';') { p ++; }
42715               colors[pal_no][0] = atoi (p) * 255 / 100;
42716               for (; *p && *p != ';'; p++);
42717               if (*p == ';') { p ++; }
42718               colors[pal_no][1] = atoi (p) * 255 / 100;
42719               for (; *p && *p != ';'; p++);
42720               if (*p == ';') { p ++; }
42721               colors[pal_no][2] = atoi (p) * 255 / 100;
42722               while (*p && *p >= '0' && *p <= '9') { p++; }
42723               p--;
42724             }
42725           else
42726             {
42727               p--;
42728             }
42729         }
42730       else if (*p == '$') // carriage return
42731         {
42732           x = 0;
42733           dst = &pixels[ (4 * width * y)];
42734         }
42735       else if (*p == '-') // line feed
42736         {
42737           y += 6;
42738           x = 0;
42739           dst = &pixels[ (4 * width * y)];
42740         }
42741       else if (*p == '!') // repeat
42742         {
42743           p++;
42744           repeat = atoi (p);
42745           while (*p && *p >= '0' && *p <= '9') { p++; }
42746           p--;
42747         }
42748       else if (*p >= '?' && *p <= '~') /* sixel data */
42749         {
42750           int sixel = (*p) - '?';
42751           if (x + repeat <= width && y < height)
42752             {
42753               for (int bit = 0; bit < 6; bit ++)
42754                 {
42755                   if (sixel & (1 << bit) )
42756                     {
42757                       for (int u = 0; u < repeat; u++)
42758                         {
42759                           for (int c = 0; c < 3; c++)
42760                             {
42761                               dst[ (bit * width * 4) + u * 4 + c] = colors[pal_no][c];
42762                               dst[ (bit * width * 4) + u * 4 + 3] = 255;
42763                             }
42764                         }
42765                     }
42766                 }
42767             }
42768           x   += repeat;
42769           dst += (repeat * 4);
42770           repeat = 1;
42771         }
42772     }
42773   if (image)
42774     {
42775       display_image (vt, image, vt->cursor_x, 0,0, 0.0, 0.0, 0,0,0,0);
42776       int right = (image->width + (vt->cw-1) ) /vt->cw;
42777       int down = (image->height + (vt->ch-1) ) /vt->ch;
42778       for (int i = 0; i<down - 1; i++)
42779         { vtcmd_index (vt, " "); }
42780       for (int i = 0; i<right; i++)
42781         { vtcmd_cursor_forward (vt, " "); }
42782       vt_line_feed (vt);
42783       vt_carriage_return (vt);
42784     }
42785   vt->rev++;
42786 }
42787 
vt_ctx_unrled(VT * vt,char byte)42788 static inline void vt_ctx_unrled (VT *vt, char byte)
42789 {
42790 #if CTX_VT_USE_FRAMEDIFF
42791   ctx_string_append_byte (vt->current_line->frame, byte);
42792 #endif
42793   ctx_parser_feed_byte (vt->ctxp, byte);
42794 }
42795 
vt_state_ctx(VT * vt,int byte)42796 static void vt_state_ctx (VT *vt, int byte)
42797 {
42798 #if 0
42799   //fprintf (stderr, "%c", byte);
42800   if (CTX_UNLIKELY(byte == CTX_CODEC_CHAR))
42801   {
42802     if (CTX_UNLIKELY(vt->in_prev_match))
42803     {
42804       char *prev = vt->current_line->prev;
42805       int prev_length = vt->current_line->prev_length;
42806       int start = atoi (vt->reference);
42807       int len = 0;
42808       if (strchr (vt->reference, ' '))
42809         len = atoi (strchr (vt->reference, ' ')+1);
42810 
42811       //fprintf (stderr, "%i-%i:", start, len);
42812 
42813       if (start < 0) start = 0;
42814       if (start >= (prev_length))start = prev_length-1;
42815       if (len + start > prev_length)
42816         len = prev_length - start;
42817 
42818       //fprintf (stderr, "%i-%i\n", start, len);
42819 
42820       if (CTX_UNLIKELY (start == 0 && len == 0))
42821       {
42822         vt_ctx_unrled (vt, CTX_CODEC_CHAR);
42823       }
42824       else
42825       {
42826         if (prev)
42827         for (int i = 0; i < len && start + i < prev_length; i++)
42828         {
42829           vt_ctx_unrled (vt, prev[start + i]);
42830         }
42831       }
42832       vt->ref_len = 0;
42833       vt->reference[0]=0;
42834       vt->in_prev_match = 0;
42835     }
42836     else
42837     {
42838       vt->reference[0]=0;
42839       vt->ref_len = 0;
42840       vt->in_prev_match = 1;
42841     }
42842   }
42843   else
42844   {
42845     if (CTX_UNLIKELY(vt->in_prev_match))
42846     {
42847       if (vt->ref_len < 15)
42848       {
42849         vt->reference[vt->ref_len++]=byte;
42850         vt->reference[vt->ref_len]=0;
42851       }
42852     }
42853     else
42854     {
42855       vt_ctx_unrled (vt, byte);
42856     }
42857   }
42858 #else
42859       vt_ctx_unrled (vt, byte);
42860 #endif
42861 }
42862 
vt_decoder_feed(VT * vt,int byte)42863 static int vt_decoder_feed (VT *vt, int byte)
42864 {
42865   int encoding = vt->encoding;
42866   switch (encoding)
42867     {
42868       case 0: /* utf8 */
42869         if (!vt->utf8_expected_bytes)
42870           {
42871             vt->utf8_expected_bytes = mrg_utf8_len (byte) - 1;
42872             vt->utf8_pos = 0;
42873           }
42874         if (vt->utf8_expected_bytes)
42875           {
42876             vt->utf8_holding[vt->utf8_pos++] = byte;
42877             vt->utf8_holding[vt->utf8_pos] = 0;
42878             if (vt->utf8_pos == vt->utf8_expected_bytes + 1)
42879               {
42880                 vt->utf8_expected_bytes = 0;
42881                 vt->utf8_pos = 0;
42882               }
42883             else
42884               {
42885                 return 1;
42886               }
42887           }
42888         else
42889           {
42890             vt->utf8_holding[0] = byte;
42891             vt->utf8_holding[0] &= 127;
42892             vt->utf8_holding[1] = 0;
42893             if (vt->utf8_holding[0] == 0)
42894               { vt->utf8_holding[0] = 32; }
42895           }
42896         break;
42897       case 1:
42898         if ( ! (byte>=0 && byte < 256) )
42899           { byte = 255; }
42900         strcpy ( (char *) &vt->utf8_holding[0], &charmap_cp437[byte][0]);
42901         vt->utf8_expected_bytes = mrg_utf8_len (byte) - 1; // ?
42902         break;
42903       default:
42904         vt->utf8_holding[0] = byte & 127;
42905         vt->utf8_holding[1] = 0;
42906         break;
42907     }
42908   return 0;
42909 }
42910 
vt_state_swallow(VT * vt,int byte)42911 static void vt_state_swallow (VT *vt, int byte)
42912 {
42913   vt->state = vt_state_neutral;
42914 }
42915 
vt_decode_hex_digit(char digit)42916 static int vt_decode_hex_digit (char digit)
42917 {
42918   if (digit >= '0' && digit <='9')
42919     return digit - '0';
42920   if (digit >= 'a' && digit <='f')
42921     return digit - 'a' + 10;
42922   if (digit >= 'A' && digit <='F')
42923     return digit - 'A' + 10;
42924   return 0;
42925 }
42926 
vt_decode_hex(const char * two_digits)42927 static int vt_decode_hex (const char *two_digits)
42928 {
42929   return vt_decode_hex_digit (two_digits[0]) * 16 +
42930          vt_decode_hex_digit (two_digits[1]);
42931 }
42932 
42933 static uint8_t palettes[][16][3]=
42934 {
42935   {
42936 {0, 0, 0},
42937 {160, 41, 41},
42938 {74, 160, 139},
42939 {135, 132, 83},
42940 {36, 36, 237},
42941 {171, 74, 223},
42942 {59, 107, 177},
42943 {195, 195, 195},
42944 {111, 111, 111},
42945 {237, 172, 130},
42946 {153, 237, 186},
42947 {233, 216, 8},
42948 {130, 180, 237},
42949 {214, 111, 237},
42950 {29, 225, 237},
42951 {255, 255, 255},
42952 
42953   },
42954 
42955   {
42956     {0, 0, 0},
42957     {127, 0, 0},
42958     {90, 209, 88},
42959     {136, 109, 0},
42960     {3, 9, 235},
42961     {90, 4, 150},
42962     {43, 111, 150},
42963     {178, 178, 178},
42964     {87, 87, 87},
42965     {193, 122, 99},
42966     {110, 254, 174},
42967     {255, 200, 0},
42968     {10, 126, 254},
42969     {146, 155, 249},
42970     {184, 208, 254},
42971     {255, 255, 255},
42972 
42973   },{
42974     {0, 0, 0},
42975     {147, 53, 38},
42976     {30, 171, 82},
42977     {188, 153, 0},
42978     {32, 71, 193},
42979     {236, 49, 188},
42980     {42, 182, 253},
42981     {149, 149, 149},
42982     {73, 73, 73},
42983     {210, 36, 0},
42984     {96, 239, 97},
42985     {247, 240, 2},
42986     {93, 11, 249},
42987     {222, 42, 255},
42988     {11, 227, 255},
42989     {233, 235, 235},
42990   },
42991 
42992 
42993   { {0, 0, 0},{97, 27, 0},{129, 180, 0},{127, 100, 0},{44, 15, 255},{135, 10, 167},{20, 133, 164},{174, 174, 174},{71, 71, 71},{167, 114, 90},{162, 214, 127},{255, 251, 83},{118, 77, 253},{192, 121, 255},{14, 217, 255},{255, 255, 255},
42994   },{
42995 
42996 
42997 #if 0
42998     {
42999       {0, 0, 0},
43000       {144, 0, 0},
43001       {9, 154, 9},
43002       {255, 137, 113},
43003       {3, 0, 255},
43004       {56, 0, 132},
43005       {0, 131, 131},
43006       {204, 204, 204},
43007       {127, 127, 127},
43008       {255, 33, 0},
43009       {113, 255, 88},
43010       {255, 236, 8},
43011       {1, 122, 255},
43012       {235, 0, 222},
43013       {0, 217, 255},
43014       {255, 255, 255},
43015     },{
43016 #endif
43017 
43018 
43019     {0, 0, 0},
43020     {139, 0, 0},
43021     {9, 154, 9},
43022     {255, 137, 113},
43023     {3, 0, 255},
43024     {56, 0, 132},
43025     {0, 111, 111},
43026     {204, 204, 204},
43027     {127, 127, 127},
43028     {255, 33, 0},
43029     {118, 255, 92},
43030     {255, 230, 15},
43031     {1, 122, 255},
43032     {232, 0, 220},
43033     {1, 217, 255},
43034     {255, 255, 255},
43035   },
43036   {
43037 
43038     {0, 0, 0},
43039     {191, 0, 0},
43040     {3, 187, 0},
43041     {254, 212, 0},
43042     {0, 0, 255},
43043     {80, 0, 128},
43044     {0, 156, 255},
43045     {166, 166, 166},
43046     {84, 84, 84},
43047     {255, 62, 0},
43048     {85, 255, 143},
43049     {255, 255, 0},
43050     {67, 80, 255},
43051     {243, 70, 255},
43052     {30, 255, 222},
43053     {255, 255, 255},
43054   },
43055   {
43056     /* */
43057     { 32, 32, 32}, // 0 - background (black)
43058     {165, 15, 21}, // 1               red
43059     { 95,130, 10}, // 2               green
43060     {205,145, 60}, // 3               yellow
43061     { 49,130,189}, // 4               blue
43062     {120, 40,160}, // 5               magenta
43063     {120,230,230}, // 6               cyan
43064     {196,196,196},// 7                light-gray
43065     { 85, 85, 85},// 8                dark gray
43066 
43067     {251,106, 74},// 9                light red
43068     {130,215,140},// 10               light green
43069     {255,255,  0},// 11               light yellow
43070     {107,174,214},// 12               light blue
43071     {215,130,160},// 13               light magenta
43072     {225,255,245},// 14               light cyan
43073     {255,255,255},// 15 - foreground (white)
43074   },{
43075     /* */
43076     { 32, 32, 32}, // 0 - background (black)
43077     {160,  0,  0}, // 1               red
43078     {  9,233,  0}, // 2               green
43079     {220,110, 44}, // 3               yellow
43080     {  0,  0,200}, // 4               blue
43081     { 90,  0,130}, // 5               magenta
43082     {  0,156,180}, // 6               cyan
43083     {196,196,196}, // 7                light-gray
43084     { 85, 85, 85}, // 8                dark gray
43085 
43086     {240, 60, 40}, // 9                light red
43087     {170,240, 80}, // 10               light green
43088     {248,248,  0}, // 11               light yellow
43089     {  0, 40,255}, // 12               light blue
43090     {204, 62,214}, // 13               light magenta
43091     { 10,234,254}, // 14               light cyan
43092     {255,255,255}, // 15 - foreground (white)
43093   },
43094   /* inspired by DEC */
43095   { {  0,  0,  0}, // 0 - background  black
43096     {150, 10, 10}, // 1               red
43097     { 21,133,  0}, // 2               green
43098 
43099     {103,103, 24}, // 3               yellow
43100     { 44, 44,153}, // 4               blue
43101     {123, 94,183}, // 5               magenta
43102 
43103     { 20,183,193}, // 6               cyan
43104 
43105     {177,177,177},// 7                light-gray
43106     {100,100,100},// 8                dark gray
43107 
43108     {244, 39, 39},// 9                light red
43109     { 61,224, 81},// 10               light green
43110     {255,255,  0},// 11               light yellow
43111     { 61, 61,244},// 12               light blue
43112     {240, 11,240},// 13               light magenta
43113     { 61,234,234},// 14               light cyan
43114 
43115     {255,255,255},// 15 - foreground  white
43116   },
43117 };
43118 
vt_state_osc(VT * vt,int byte)43119 static void vt_state_osc (VT *vt, int byte)
43120 {
43121   // https://ttssh2.osdn.jp/manual/4/en/about/ctrlseq.html
43122   // and in "\033\" rather than just "\033", this would cause
43123   // a stray char
43124   //if (byte == '\a' || byte == 27 || byte == 0 || byte < 32)
43125   if ( (byte < 32) && ( (byte < 8) || (byte > 13) ) )
43126     {
43127       int n = parse_int (vt->argument_buf, 0);
43128       switch (n)
43129         {
43130           case 0:
43131           case 1:
43132           case 2:
43133 #if 0
43134     {"]0;New_title\e\",  0, , }, /* id: set window title */ "
43135 #endif
43136             vt_set_title (vt, vt->argument_buf + 3);
43137             break;
43138           case 4: // set palette entry
43139             {
43140             int color_no = parse_int (vt->argument_buf + 2, 0);
43141             char *rest = vt->argument_buf + 3;
43142             rest = strchr (rest, ';');
43143 
43144             if (rest++)
43145             if (strlen(rest)>10 &&
43146                 rest[0] == 'r' &&
43147                 rest[1] == 'g' &&
43148                 rest[2] == 'b' &&
43149                 rest[3] == ':' &&
43150                 rest[6] == '/' &&
43151                 rest[9] == '/')
43152             {
43153               int red = vt_decode_hex (&rest[4]);
43154               int green = vt_decode_hex (&rest[7]);
43155               int blue = vt_decode_hex (&rest[10]);
43156           //  fprintf (stderr, "set color:%i  %i %i %i\n", color_no, red, green, blue);
43157               if (color_no >= 0 && color_no <= 15)
43158               {
43159                 palettes[0][color_no][0]=red;
43160                 palettes[0][color_no][1]=green;
43161                 palettes[0][color_no][2]=blue;
43162               }
43163             }
43164             }
43165             break;
43166           case 12: // text cursor color
43167             break;
43168           case 17: // highlight color
43169             break;
43170           case 19: // ??
43171             break;
43172 
43173           case 10: // text fg
43174 #if 0
43175 #if 0
43176     {"]11;",  0, , }, /* id: set foreground color */
43177 #endif
43178             {
43179               /* request current foreground color, xterm does this to
43180                  determine if it can use 256 colors, when this test fails,
43181                  it still mixes in color 130 together with stock colors
43182                */
43183               char buf[128];
43184               sprintf (buf, "\033]10;rgb:%2x/%2x/%2x\033\\",
43185                        vt->fg_color[0], vt->fg_color[1], vt->fg_color[2]);
43186               vt_write (vt, buf, strlen (buf) );
43187             }
43188 #endif
43189             break;
43190           case 11: // text bg
43191 #if 0
43192     {"]11;",  0, , }, /* id: get background color */
43193             {
43194               /* get background color */
43195               char buf[128];
43196               sprintf (buf, "\033]11;rgb:%2x/%2x/%2x\033\\",
43197                        vt->bg_color[0], vt->bg_color[1], vt->bg_color[2]);
43198               vt_write (vt, buf, strlen (buf) );
43199             }
43200 #endif
43201             break;
43202 #if 0
43203     {"]1337;key=value:base64data\b\",  0, vtcmd_erase_in_line, VT100}, /* args:keyvalue id: iterm2 graphics */ "
43204 #endif
43205           case 1337:
43206             if (!strncmp (&vt->argument_buf[6], "File=", 5) )
43207               {
43208                 {
43209                   /* iTerm2 image protocol */
43210                   int width = 0;
43211                   int height = 0;
43212                   int file_size = 0;
43213                   int show_inline = 0;
43214                   int preserve_aspect = 1;
43215                   char *name = NULL;
43216                   char *p = &vt->argument_buf[11];
43217                   char key[128]="";
43218                   char value[128]="";
43219                   int in_key=1;
43220                   if (preserve_aspect) {}; /* XXX : NYI */
43221                   for (; *p && *p!=':'; p++)
43222                     {
43223                       if (in_key)
43224                         {
43225                           if (*p == '=')
43226                             { in_key = 0; }
43227                           else
43228                             {
43229                               if (strlen (key) < 124)
43230                                 {
43231                                   key[strlen (key)+1] = 0;
43232                                   key[strlen (key)] = *p;
43233                                 }
43234                             }
43235                         }
43236                       else
43237                         {
43238                           if (*p == ';')
43239                             {
43240                               if (!strcmp (key, "name") )
43241                                 {
43242                                   name = strdup (value);
43243                                 }
43244                               else if (!strcmp (key, "width") )
43245                                 {
43246                                   width = atoi (value);
43247                                   if (strchr (value, 'x') )
43248                                     { /* pixels */ }
43249                                   else if (strchr (value, '%') )
43250                                     {
43251                                       /* percent */
43252                                       width = width / 100.0 * (vt->cw * vt->cols);
43253                                     }
43254                                   else
43255                                     { /* chars */ width = width * vt->cw; }
43256                                 }
43257                               else if (!strcmp (key, "height") )
43258                                 {
43259                                   height = atoi (value);
43260                                   if (strchr (value, 'x') )
43261                                     { /* pixels */ }
43262                                   else if (strchr (value, '%') )
43263                                     {
43264                                       /* percent */
43265                                       height = height / 100.0 * (vt->ch * vt->rows);
43266                                     }
43267                                   else
43268                                     { /* chars */ height = height * vt->ch; }
43269                                 }
43270                               else if (!strcmp (key, "preserveAspectRatio") )
43271                                 {
43272                                   preserve_aspect = atoi (value);
43273                                 }
43274                               else if (!strcmp (key, "inline") )
43275                                 {
43276                                   show_inline = atoi (value);
43277                                 }
43278                               key[0]=0;
43279                               value[0]=0;
43280                               in_key = 1;
43281                             }
43282                           else
43283                             {
43284                               if (strlen (value) < 124)
43285                                 {
43286                                   value[strlen (value)+1] = 0;
43287                                   value[strlen (value)] = *p;
43288                                 }
43289                             }
43290                         }
43291                     }
43292                   if (key[0])
43293                     {
43294                       // code-dup
43295                       if (!strcmp (key, "name") )
43296                         {
43297                           name = strdup (value);
43298                         }
43299                       else if (!strcmp (key, "width") )
43300                         {
43301                           width = atoi (value);
43302                           if (strchr (value, 'x') )
43303                             { /* pixels */ }
43304                           else if (strchr (value, '%') )
43305                             {
43306                               /* percent */
43307                               width = width / 100.0 * (vt->cw * vt->cols);
43308                             }
43309                           else
43310                             { /* chars */ width = width * vt->cw; }
43311                         }
43312                       else if (!strcmp (key, "height") )
43313                         {
43314                           height = atoi (value);
43315                           if (strchr (value, 'x') )
43316                             { /* pixels */ }
43317                           else if (strchr (value, '%') )
43318                             {
43319                               /* percent */
43320                               height = height / 100.0 * (vt->ch * vt->rows);
43321                             }
43322                           else
43323                             { /* chars */ height = height * vt->ch; }
43324                         }
43325                       else if (!strcmp (key, "preserveAspectRatio") )
43326                         {
43327                           preserve_aspect = atoi (value);
43328                         }
43329                       else if (!strcmp (key, "inline") )
43330                         {
43331                           show_inline = atoi (value);
43332                         }
43333                     }
43334                   if (*p == ':')
43335                     {
43336                       p++;
43337                     }
43338                   if (0)
43339                     fprintf (stderr, "%s %i %i %i %i{%s\n", name?name:"",
43340                              width, height, file_size, show_inline,
43341                              p);
43342                   Image *image = NULL;
43343                   {
43344                     int bin_length = vt->argument_buf_len;
43345                     uint8_t *data2 = malloc (bin_length);
43346                     bin_length = ctx_base642bin ( (char *) p,
43347                                                  &bin_length,
43348                                                  data2);
43349                     int channels = 4;
43350                     int buf_width = 0;
43351                     int buf_height = 0;
43352                     uint8_t *new_data = stbi_load_from_memory (data2, bin_length, &buf_width, &buf_height, &channels, 4);
43353                     free (data2);
43354                     if (new_data)
43355                       {
43356                         image = image_add (buf_width, buf_height, 0,
43357                                            32, buf_width*buf_height*4, new_data);
43358                       }
43359                     else
43360                       {
43361                         fprintf (stderr, "image decoding problem %s\n", stbi_failure_reason());
43362                         fprintf (stderr, "len: %i\n", bin_length);
43363                       }
43364                   }
43365                   if (image)
43366                     {
43367                       display_image (vt, image, vt->cursor_x, 0,0, 0.0, 0.0, 0,0,0,0);
43368                       int right = (image->width + (vt->cw-1) ) /vt->cw;
43369                       int down = (image->height + (vt->ch-1) ) /vt->ch;
43370                       for (int i = 0; i<down - 1; i++)
43371                         { vtcmd_index (vt, " "); }
43372                       for (int i = 0; i<right; i++)
43373                         { vtcmd_cursor_forward (vt, " "); }
43374                     }
43375                 }
43376               }
43377             break;
43378           case 104:
43379             break;
43380           case 8:
43381             fprintf (stderr, "unhandled OSC 8, hyperlink\n");
43382             break;
43383           default:
43384             fprintf (stderr, "unhandled OSC %i\n", n);
43385             break;
43386         }
43387       if (byte == 27)
43388         {
43389           vt->state = vt_state_swallow;
43390         }
43391       else
43392         {
43393           vt->state = vt_state_neutral;
43394         }
43395     }
43396   else
43397     {
43398       vt_argument_buf_add (vt, byte);
43399     }
43400 }
43401 
43402 
43403 static void vt_state_sixel (VT *vt, int byte)
43404 {
43405   // https://ttssh2.osdn.jp/manual/4/en/about/ctrlseq.html
43406   // and in "\033\" rather than just "\033", this would cause
43407   // a stray char
43408   if ( (byte < 32) && ( (byte < 8) || (byte > 13) ) )
43409     {
43410       vt_sixels (vt, vt->argument_buf);
43411       if (byte == 27)
43412         {
43413           vt->state = vt_state_swallow;
43414         }
43415       else
43416         {
43417           vt->state = vt_state_neutral;
43418         }
43419     }
43420   else
43421     {
43422       vt_argument_buf_add (vt, byte);
43423       //fprintf (stderr, "\r%i ", vt->argument_buf_len);
43424     }
43425 }
43426 
43427 //void add_tab (Ctx *ctx, const char *commandline, int can_launch);
43428 //void vt_screenshot (const char *output_path);
43429 
43430 static void vt_state_apc_generic (VT *vt, int byte)
43431 {
43432   if ( (byte < 32) && ( (byte < 8) || (byte > 13) ) )
43433     {
43434       if (vt->argument_buf[1] == 'G') /* graphics - from kitty */
43435         {
43436           vt_gfx (vt, vt->argument_buf);
43437         }
43438       else if (vt->argument_buf[1] == 'C') /* launch command */
43439       {
43440         if (vt->can_launch)
43441         {
43442           int   can_launch = 0;
43443           int   no_title = 0;
43444           int   no_move = 0;
43445           int   no_resize = 0;
43446           int   layer = 0;
43447   // escape subsequent arguments so that we dont have to pass a string?
43448           float x = -1.0;
43449           float y = -1.0;
43450           int   z = 0;
43451           float width = -1.0;
43452           float height = -1.0;
43453 
43454           for (int i=2; vt->argument_buf[i]; i++)
43455           {
43456             if (!strncmp (&vt->argument_buf[i], "can_launch=1", strlen ("can_launch=1")))
43457               can_launch = 1;
43458             if (!strncmp (&vt->argument_buf[i], "no_title=1", strlen("no_title=1")))
43459               no_title = 1;
43460             if (!strncmp (&vt->argument_buf[i], "no_move=1", strlen("no_move=1")))
43461               no_move = 1;
43462             else if (!strncmp (&vt->argument_buf[i], "z=", 2))
43463               z=atoi(&vt->argument_buf[i]+strlen("z="));
43464             else if (!strncmp (&vt->argument_buf[i], "x=", 2))
43465               x=atof(&vt->argument_buf[i]+strlen("x="));
43466             else if (!strncmp (&vt->argument_buf[i], "y=", 2))
43467               y=atof(&vt->argument_buf[i]+strlen("y="));
43468             else if (!strncmp (&vt->argument_buf[i], "width=", 6))
43469               width=atof(&vt->argument_buf[i]+strlen("width="));
43470             else if (!strncmp (&vt->argument_buf[i], "height=", 7))
43471               height=atof(&vt->argument_buf[i]+strlen("height="));
43472           }
43473 
43474           if (width + no_resize + layer + height + x + y + no_title + no_move + z + can_launch) {};
43475 
43476           char *sep = strchr(vt->argument_buf, ';');
43477           if (sep)
43478           {
43479             //fprintf (stderr, "[%s]", sep +  1);
43480             if (!strncmp (sep + 1, "fbsave", 6))
43481             {
43482               // vt_screenshot (sep + 8);
43483             }
43484             else
43485             {
43486           //  add_tab (ctx, sep + 1, can_launch);
43487             }
43488           }
43489         }
43490 
43491       }
43492       vt->state = ( (byte == 27) ?  vt_state_swallow : vt_state_neutral);
43493     }
43494   else
43495     {
43496       vt_argument_buf_add (vt, byte);
43497     }
43498 }
43499 
43500 #if 0
43501     {"_G..\e\", 0, vtcmd_delete_n_chars, VT102}, /* ref:none id: <a href='https://sw.kovidgoyal.net/kitty/graphics-protocol.html'>kitty graphics</a> */ "
43502     {"_A..\e\", 0, vtcmd_delete_n_chars, VT102}, /* id:  <a href='https://github.com/hodefoting/atty/'>atty</a> audio input/output */ "
43503     {"_C..\e\", 0, vtcmd_delete_n_chars, VT102}, /* id:  run command */ "
43504 #endif
43505 static void vt_state_apc (VT *vt, int byte)
43506 {
43507   if (byte == 'A')
43508     {
43509       vt_argument_buf_add (vt, byte);
43510       vt->state = vt_state_apc_audio;
43511     }
43512   else if ( (byte < 32) && ( (byte < 8) || (byte > 13) ) )
43513     {
43514       vt->state = ( (byte == 27) ?  vt_state_swallow : vt_state_neutral);
43515     }
43516   else
43517     {
43518       vt_argument_buf_add (vt, byte);
43519       vt->state = vt_state_apc_generic;
43520     }
43521 }
43522 
43523 static void vt_state_esc_foo (VT *vt, int byte)
43524 {
43525   vt_argument_buf_add (vt, byte);
43526   vt->state = vt_state_neutral;
43527   handle_sequence (vt, vt->argument_buf);
43528 }
43529 
43530 static void vt_state_esc_sequence (VT *vt, int byte)
43531 {
43532   if (_vt_handle_control (vt, byte) == 0)
43533     {
43534       if (byte == 27)
43535         {
43536         }
43537       else if (byte >= '@' && byte <= '~')
43538         {
43539           vt_argument_buf_add (vt, byte);
43540           vt->state = vt_state_neutral;
43541           handle_sequence (vt, vt->argument_buf);
43542         }
43543       else
43544         {
43545           vt_argument_buf_add (vt, byte);
43546         }
43547     }
43548 }
43549 
43550 static void vt_state_esc (VT *vt, int byte)
43551 {
43552   if (_vt_handle_control (vt, byte) == 0)
43553     switch (byte)
43554       {
43555         case 27: /* ESCape */
43556           break;
43557         case ')':
43558         case '#':
43559         case '(':
43560           {
43561             char tmp[]= {byte, '\0'};
43562             vt_argument_buf_reset (vt, tmp);
43563             vt->state = vt_state_esc_foo;
43564           }
43565           break;
43566         case '[':
43567         case '%':
43568         case '+':
43569         case '*':
43570           {
43571             char tmp[]= {byte, '\0'};
43572             vt_argument_buf_reset (vt, tmp);
43573             vt->state = vt_state_esc_sequence;
43574           }
43575           break;
43576 
43577 #if 0
43578     {"Psixel_data\e\",  0, , }, /* id: sixels */ "
43579 #endif
43580 
43581         case 'P':
43582           {
43583             char tmp[]= {byte, '\0'};
43584             vt_argument_buf_reset (vt, tmp);
43585             vt->state = vt_state_sixel;
43586           }
43587           break;
43588         case ']':
43589           {
43590             char tmp[]= {byte, '\0'};
43591             vt_argument_buf_reset (vt, tmp);
43592             vt->state = vt_state_osc;
43593           }
43594           break;
43595         case '^':  // privacy message
43596         case '_':  // APC
43597         case 'X':  // SOS
43598           {
43599             char tmp[]= {byte, '\0'};
43600             vt_argument_buf_reset (vt, tmp);
43601             vt->state = vt_state_apc;
43602           }
43603           break;
43604         default:
43605           {
43606             char tmp[]= {byte, '\0'};
43607             tmp[0]=byte;
43608             vt->state = vt_state_neutral;
43609             handle_sequence (vt, tmp);
43610           }
43611           break;
43612       }
43613 }
43614 
43615 static void vt_state_neutral (VT *vt, int byte)
43616 {
43617   if (CTX_UNLIKELY(_vt_handle_control (vt, byte) != 0))
43618     return;
43619   if (CTX_LIKELY(byte != 27))
43620   {
43621     if (vt_decoder_feed (vt, byte) )
43622       return;
43623     if (vt->charset[vt->shifted_in] != 0 &&
43624         vt->charset[vt->shifted_in] != 'B')
43625       {
43626         char **charmap;
43627         switch (vt->charset[vt->shifted_in])
43628           {
43629             case 'A':
43630               charmap = charmap_uk;
43631               break;
43632             case 'B':
43633               charmap = charmap_ascii;
43634               break;
43635             case '0':
43636               charmap = charmap_graphics;
43637               break;
43638             case '1':
43639               charmap = charmap_cp437;
43640               break;
43641             case '2':
43642               charmap = charmap_graphics;
43643               break;
43644             default:
43645               charmap = charmap_ascii;
43646               break;
43647           }
43648         if ( (vt->utf8_holding[0] >= ' ') && (vt->utf8_holding[0] <= '~') )
43649           {
43650             _vt_add_str (vt, charmap[vt->utf8_holding[0]-' ']);
43651           }
43652       }
43653     else
43654       {
43655         // ensure vt->utf8_holding contains a valid utf8
43656         uint32_t codepoint;
43657         uint32_t state = 0;
43658         for (int i = 0; vt->utf8_holding[i]; i++)
43659           { utf8_decode (&state, &codepoint, vt->utf8_holding[i]); }
43660         if (state != UTF8_ACCEPT)
43661           {
43662             /* otherwise mangle it so that it does */
43663             vt->utf8_holding[0] &= 127;
43664             vt->utf8_holding[1] = 0;
43665             if (vt->utf8_holding[0] == 0)
43666               { vt->utf8_holding[0] = 32; }
43667           }
43668         _vt_add_str (vt, (char *) vt->utf8_holding);
43669       }
43670   }
43671   else // ESCape
43672   {
43673     vt->state = vt_state_esc;
43674   }
43675 }
43676 
43677 int vt_poll (VT *vt, int timeout)
43678 {
43679   if (!vt) return 0;
43680   int read_size = sizeof (vt->buf);
43681   int got_data = 0;
43682 
43683   // read_size 1m1.142s
43684   // read_size*10  52s
43685   // read_size*5   53.8s
43686   // read_size*4   53.78s
43687   // read_size*3   .....s
43688   // read_size*2   56.99s
43689   int remaining_chars = read_size * 3;// * 100;
43690   int len = 0;
43691   vt_audio_task (vt, 0);
43692 #if 1
43693   if (vt->cursor_visible && vt->smooth_scroll)
43694     {
43695       remaining_chars = vt->cols / 2;
43696     }
43697 #endif
43698   read_size = MIN (read_size, remaining_chars);
43699   long start_ticks = ctx_ticks ();
43700   long ticks = start_ticks;
43701   while (remaining_chars > 0 &&
43702          vt_waitdata (vt, 0) &&
43703          ( ticks - start_ticks < timeout ||  vt->state == vt_state_ctx))
43704     {
43705   if (vt->in_smooth_scroll)
43706     {
43707       remaining_chars = 1;
43708       // XXX : need a bail condition -
43709       // /// so that we can stop accepting data until autowrap or similar
43710     }
43711       len = vt_read (vt, vt->buf, read_size);
43712       if (len >0)
43713       {
43714      // fwrite (vt->buf, len, 1, vt->log);
43715      // fwrite (vt->buf, len, 1, stdout);
43716       }
43717       for (int i = 0; i < len; i++)
43718         { vt->state (vt, vt->buf[i]); }
43719       // XXX allow state to break out in ctx mode on flush
43720       got_data+=len;
43721       remaining_chars -= len;
43722       if (vt->state == vt_state_ctx) {
43723          if (remaining_chars < read_size)
43724          {
43725            remaining_chars = read_size * 2;
43726          }
43727       }
43728       vt_audio_task (vt, 0);
43729       ticks = ctx_ticks ();
43730     }
43731   if (got_data < 0)
43732     {
43733       if (kill (vt->vtpty.pid, 0) != 0)
43734         {
43735           vt->vtpty.done = 1;
43736         }
43737     }
43738   return got_data;
43739 }
43740 
43741 /******/
43742 
43743 static const char *keymap_vt52[][2]=
43744 {
43745   {"up",    "\033A" },
43746   {"down",  "\033B" },
43747   {"right", "\033C" },
43748   {"left",  "\033D" },
43749 };
43750 
43751 static const char *keymap_application[][2]=
43752 {
43753   {"up",    "\033OA" },
43754   {"down",  "\033OB" },
43755   {"right", "\033OC" },
43756   {"left",  "\033OD" },
43757 };
43758 
43759 static const char *keymap_general[][2]=
43760 {
43761   {"up",             "\033[A"},
43762   {"down",           "\033[B"},
43763   {"right",          "\033[C"},
43764   {"left",           "\033[D"},
43765   {"end",            "\033[F"},
43766   {"home",           "\033[H"},
43767   {"shift-up",       "\033[1;2A"},
43768   {"shift-down",     "\033[1;2B"},
43769   {"shift-right",    "\033[1;2C"},
43770   {"shift-left",     "\033[1;2D"},
43771   {"alt-a",          "\033a"},
43772   {"alt-b",          "\033b"},
43773   {"alt-c",          "\033c"},
43774   {"alt-d",          "\033d"},
43775   {"alt-e",          "\033e"},
43776   {"alt-f",          "\033f"},
43777   {"alt-g",          "\033g"},
43778   {"alt-h",          "\033h"},
43779   {"alt-i",          "\033i"},
43780   {"alt-j",          "\033j"},
43781   {"alt-k",          "\033k"},
43782   {"alt-l",          "\033l"},
43783   {"alt-m",          "\033m"},
43784   {"alt-n",          "\033n"},
43785   {"alt-o",          "\033o"},
43786   {"alt-p",          "\033p"},
43787   {"alt-q",          "\033q"},
43788   {"alt-r",          "\033r"},
43789   {"alt-s",          "\033s"},
43790   {"alt-t",          "\033t"},
43791   {"alt-u",          "\033u"},
43792   {"alt-v",          "\033v"},
43793   {"alt-w",          "\033w"},
43794   {"alt-x",          "\033x"},
43795   {"alt-y",          "\033y"},
43796   {"alt-z",          "\033z"},
43797   {"alt- ",          "\033 "},
43798   {"alt-space",      "\033 "},
43799   {"alt-0",          "\0330"},
43800   {"alt-1",          "\0331"},
43801   {"alt-2",          "\0332"},
43802   {"alt-3",          "\0333"},
43803   {"alt-4",          "\0334"},
43804   {"alt-5",          "\0335"},
43805   {"alt-6",          "\0336"},
43806   {"alt-7",          "\0337"},
43807   {"alt-8",          "\0338"},
43808   {"alt-9",          "\0339"},
43809   {"alt-return",     "\033\r"},
43810   {"alt-backspace",  "\033\177"},
43811   {"alt-up",         "\033[1;3A"},
43812   {"alt-down",       "\033[1;3B"},
43813   {"alt-right",      "\033[1;3C"},
43814   {"alt-left",       "\033[1;3D"},
43815   {"shift-alt-up",   "\033[1;4A"},
43816   {"shift-alt-down", "\033[1;4B"},
43817   {"shift-alt-right","\033[1;4C"},
43818   {"shift-alt-left", "\033[1;4D"},
43819   {"control-space",  "\000"},
43820   {"control-up",     "\033[1;5A"},
43821   {"control-down",   "\033[1;5B"},
43822   {"control-right",  "\033[1;5C"},
43823   {"control-left",   "\033[1;5D"},
43824   {"shift-control-up",    "\033[1;6A"},
43825   {"shift-control-down",  "\033[1;6B"},
43826   {"shift-control-right", "\033[1;6C"},
43827   {"shift-control-left",  "\033[1;6D"},
43828   {"insert",         "\033[2~"},
43829   {"delete",         "\033[3~"},
43830   {"control-delete", "\033[3,5~"},
43831   {"shift-delete",   "\033[3,2~"},
43832   {"control-shift-delete",  "\033[3,6~"},
43833   {"page-up",        "\033[5~"},
43834   {"page-down",     "\033[6~"},
43835   {"return",         "\r"},
43836   {"shift-tab",      "\033Z"},
43837   {"shift-return",   "\r"},
43838   {"control-return", "\r"},
43839   {"space",          " "},
43840   {"shift-space",    " "},
43841   {"control-a",      "\001"},
43842   {"control-b",      "\002"},
43843   {"control-c",      "\003"},
43844   {"control-d",      "\004"},
43845   {"control-e",      "\005"},
43846   {"control-f",      "\006"},
43847   {"control-g",      "\007"},
43848   {"control-h",      "\010"},
43849   {"control-i",      "\011"},
43850   {"control-j",      "\012"},
43851   {"control-k",      "\013"},
43852   {"control-l",      "\014"},
43853   {"control-m",      "\015"},
43854   {"control-n",      "\016"},
43855   {"control-o",      "\017"},
43856   {"control-p",      "\020"},
43857   {"control-q",      "\021"},
43858   {"control-r",      "\022"},
43859   {"control-s",      "\023"},
43860   {"control-t",      "\024"},
43861   {"control-u",      "\025"},
43862   {"control-v",      "\026"},
43863   {"control-w",      "\027"},
43864   {"control-x",      "\030"},
43865   {"control-y",      "\031"},
43866   {"control-z",      "\032"},
43867   {"escape",         "\033"},
43868   {"tab",            "\t"},
43869   {"backspace",      "\177"},
43870   {"control-backspace", "\177"},
43871   {"shift-backspace","\177"},
43872   {"shift-tab",      "\033[Z"},
43873 
43874   {"control-F1",     "\033[>11~"},
43875   {"control-F2",     "\033[>12~"},
43876   {"control-F3",     "\033[>13~"},
43877   {"control-F4",     "\033[>14~"},
43878   {"control-F5",     "\033[>15~"},
43879 
43880   {"shift-F1",       "\033[?11~"},
43881   {"shift-F2",       "\033[?12~"},
43882   {"shift-F3",       "\033[?13~"},
43883   {"shift-F4",       "\033[?14~"},
43884   {"shift-F5",       "\033[?15~"},
43885 
43886   {"F1",             "\033[11~"},  // hold screen   // ESC O P
43887   {"F2",             "\033[12~"},  // print screen  //       Q
43888   {"F3",             "\033[13~"},  // set-up                 R
43889   {"F4",             "\033[14~"},  // data/talk              S
43890   {"F5",             "\033[15~"},  // break
43891   {"F6",             "\033[17~"},
43892   {"F7",             "\033[18~"},
43893   {"F8",             "\033[19~"},
43894   {"F9",             "\033[20~"},
43895   {"F10",            "\033[21~"},
43896   {"F11",            "\033[22~"},
43897   {"F12",            "\033[23~"},
43898   {"control-/",       "\037"},
43899   {"shift-control-/", "\037"},
43900   {"control-[",       "\033"},
43901   {"control-]",       "\035"},
43902   {"shift-control-[", "\033"},
43903   {"shift-control-]", "\031"},
43904   {"shift-control-`", "\036"},
43905   {"control-'",       "'"},
43906   {"shift-control-'", "'"},
43907   {"control-;",       ";"},
43908   {"shift-control-;", ";"},
43909   {"control-.",       "."},
43910   {"shift-control-.", "."},
43911   {"control-,",       ","},
43912   {"shift-control-,", ","},
43913   {"control-\\",      "\034"},
43914   {"control-1",       "1"},
43915   {"control-3",       "\033"},
43916   {"control-4",       "\034"},
43917   {"control-5",       "\035"},
43918   {"control-6",       "\036"},
43919   {"shift-control-6", "\036"},
43920   {"control-7",       "\037"},
43921   {"shift-control-7", "\036"},
43922   {"control-8",       "\177"},
43923   {"control-9",       "9"},
43924 
43925 
43926 };
43927 
43928 void ctx_client_lock (CtxClient *client);
43929 void ctx_client_unlock (CtxClient *client);
43930 
43931 void vt_feed_keystring (VT *vt, CtxEvent *event, const char *str)
43932 {
43933   if (vt->ctx_events)
43934   {
43935     if (!strcmp (str, "control-l") )
43936     {
43937       vt->ctx_events = 0;
43938       return;
43939     }
43940     vt_write (vt, str, strlen (str) );
43941     vt_write (vt, "\n", 1);
43942     return;
43943   }
43944   if (!strncmp (str, "keyup",   5)) return;
43945   if (!strncmp (str, "keydown", 7)) return;
43946 
43947   if (!strcmp (str, "capslock")) return;
43948 
43949 #if 0
43950   if (!strstr (str, "-page"))
43951     vt_set_scroll (vt, 0);
43952 #endif
43953 
43954   if (!strcmp (str, "idle") )
43955      return;
43956   else if (!strcmp (str, "shift-control-home"))
43957     {
43958       vt_set_scroll (vt, vt->scrollback_count);
43959       vt_rev_inc (vt);
43960       return;
43961     }
43962   else if (!strcmp (str, "shift-control-end"))
43963     {
43964       int new_scroll = 0;
43965       vt_set_scroll (vt, new_scroll);
43966       vt_rev_inc (vt);
43967       return;
43968     }
43969   else if (!strcmp (str, "shift-control-down"))
43970     {
43971       int new_scroll = vt_get_scroll (vt) - 1;
43972       vt_set_scroll (vt, new_scroll);
43973       vt_rev_inc (vt);
43974       return;
43975     }
43976   else if (!strcmp (str, "shift-control-up"))
43977     {
43978       int new_scroll = vt_get_scroll (vt) + 1;
43979       vt_set_scroll (vt, new_scroll);
43980       vt_rev_inc (vt);
43981       return;
43982     }
43983   else if (!strcmp (str, "shift-page-up") ||
43984            !strcmp (str, "shift-control-page-up"))
43985     {
43986       int new_scroll = vt_get_scroll (vt) + vt_get_rows (vt) /2;
43987       vt_set_scroll (vt, new_scroll);
43988       vt_rev_inc (vt);
43989       return;
43990     }
43991   else if (!strcmp (str, "shift-page-down") ||
43992            !strcmp (str, "shift-control-page-down"))
43993     {
43994       int new_scroll = vt_get_scroll (vt) - vt_get_rows (vt) /2;
43995       if (new_scroll < 0) { new_scroll = 0; }
43996       vt_set_scroll (vt, new_scroll);
43997       vt_rev_inc (vt);
43998       return;
43999     }
44000   else if (!strcmp (str, "shift-control--") ||
44001            !strcmp (str, "control--") )
44002     {
44003       float font_size = vt_get_font_size (vt);
44004       //font_size /= 1.15;
44005       font_size -=2;//= roundf (font_size);
44006       if (font_size < 2) { font_size = 2; }
44007       vt_set_font_size (vt, font_size);
44008       vt_set_px_size (vt, vt->width, vt->height);
44009       return;
44010     }
44011   else if (!strcmp (str, "shift-control-=") ||
44012            !strcmp (str, "control-=") )
44013     {
44014       float font_size = vt_get_font_size (vt);
44015       float old = font_size;
44016       //font_size *= 1.15;
44017       //
44018       //font_size = roundf (font_size);
44019       font_size+=2;
44020 
44021       if (old == font_size) { font_size = old+1; }
44022       if (font_size > 200) { font_size = 200; }
44023       vt_set_font_size (vt, font_size);
44024       vt_set_px_size (vt, vt->width, vt->height);
44025 
44026       return;
44027     }
44028   else if (!strcmp (str, "shift-control-r") )
44029     {
44030       vt_open_log (vt, "/tmp/ctx-vt");
44031       return;
44032     }
44033   else if (!strcmp (str, "shift-control-l") )
44034     {
44035       vt_set_local (vt, !vt_get_local (vt) );
44036       return;
44037     }
44038   else if (!strncmp (str, "mouse-", 5) )
44039     {
44040       int cw = vt_cw (vt);
44041       int ch = vt_ch (vt);
44042       if (!strncmp (str + 6, "motion", 6) )
44043         {
44044           int x = 0, y = 0;
44045           char *s = strchr (str, ' ');
44046           if (s)
44047             {
44048               x = atoi (s);
44049               s = strchr (s + 1, ' ');
44050               if (s)
44051                 {
44052                   y = atoi (s);
44053                   vt_mouse (vt, event, VT_MOUSE_MOTION, 1, x/cw + 1, y/ch + 1, x, y);
44054                 }
44055             }
44056         }
44057       else if (!strncmp (str + 6, "press", 5) )
44058         {
44059           int x = 0, y = 0, b = 0;
44060           char *s = strchr (str, ' ');
44061           if (s)
44062             {
44063               x = atoi (s);
44064               s = strchr (s + 1, ' ');
44065               if (s)
44066                 {
44067                   y = atoi (s);
44068                   s = strchr (s + 1, ' ');
44069                   if (s)
44070                   {
44071                     b = atoi (s);
44072                   }
44073                   vt_mouse (vt, event, VT_MOUSE_PRESS, b, x/cw + 1, y/ch + 1, x, y);
44074                 }
44075             }
44076           //clients[active].drawn_rev = 0;
44077         }
44078       else if (!strncmp (str + 6, "drag", 4) )
44079         {
44080           int x = 0, y = 0, b = 0; // XXX initialize B
44081           char *s = strchr (str, ' ');
44082           if (s)
44083             {
44084               x = atoi (s);
44085               s = strchr (s + 1, ' ');
44086               if (s)
44087                 {
44088                   y = atoi (s);
44089                   if (s)
44090                   {
44091                     b = atoi (s);
44092                   }
44093                   vt_mouse (vt, event, VT_MOUSE_DRAG, b, x/cw + 1, y/ch + 1, x, y);
44094                 }
44095             }
44096           //clients[active].drawn_rev = 0;
44097         }
44098       else if (!strncmp (str + 6, "release", 7) )
44099         {
44100           int x = 0, y = 0, b = 0;
44101           char *s = strchr (str, ' ');
44102           if (s)
44103             {
44104               x = atoi (s);
44105               s = strchr (s + 1, ' ');
44106               if (s)
44107                 {
44108                   y = atoi (s);
44109                   s = strchr (s + 1, ' ');
44110                   if (s)
44111                   {
44112                     b = atoi (s);
44113                   }
44114                   vt_mouse (vt, event, VT_MOUSE_RELEASE, b, x/cw + 1, y/ch + 1, x, y);
44115                 }
44116             }
44117           //clients[active].drawn_rev = 0;
44118           // queue-draw
44119         }
44120       return;
44121     }
44122 
44123   if (vt->scroll_on_input)
44124   {
44125     vt->scroll = 0.0;
44126   }
44127 
44128 
44129   if (vt->state == vt_state_vt52)
44130     {
44131       for (unsigned int i = 0; i<sizeof (keymap_vt52) /sizeof (keymap_vt52[0]); i++)
44132         if (!strcmp (str, keymap_vt52[i][0]) )
44133           { str = keymap_vt52[i][1]; goto done; }
44134     }
44135   else
44136     {
44137       if (vt->cursor_key_application)
44138         {
44139           for (unsigned int i = 0; i<sizeof (keymap_application) /sizeof (keymap_application[0]); i++)
44140             if (!strcmp (str, keymap_application[i][0]) )
44141               { str = keymap_application[i][1]; goto done; }
44142         }
44143     }
44144 
44145 
44146   if (!strcmp (str, "return") )
44147     {
44148       if (vt->cr_on_lf)
44149         { str = "\r\n"; }
44150       else
44151         { str = "\r"; }
44152       goto done;
44153     }
44154   if (!strcmp (str, "control-space") ||
44155       !strcmp (str, "control-`") ||
44156       !strcmp (str, "control-2") ||
44157       !strcmp (str, "shift-control-2") ||
44158       !strcmp (str, "shift-control-space") )
44159     {
44160       str = "\0\0";
44161       vt_write (vt, str, 1);
44162       return;
44163     }
44164   for (unsigned int i = 0; i< sizeof (keymap_general) /
44165                               sizeof (keymap_general[0]); i++)
44166     if (!strcmp (str, keymap_general[i][0]) )
44167       {
44168         str = keymap_general[i][1];
44169         break;
44170       }
44171 done:
44172   if (strlen (str) )
44173     {
44174       if (vt->local_editing)
44175         {
44176           for (int i = 0; str[i]; i++)
44177             {
44178               vt->state (vt, str[i]);
44179             }
44180         }
44181       else
44182         {
44183           vt_write (vt, str, strlen (str) );
44184         }
44185     }
44186 }
44187 
44188 void vt_paste (VT *vt, const char *str)
44189 {
44190   if (vt->bracket_paste)
44191     {
44192       vt_write (vt, "\033[200~", 6);
44193     }
44194   vt_feed_keystring (vt, NULL, str);
44195   if (vt->bracket_paste)
44196     {
44197       vt_write (vt, "\033[201~", 6);
44198     }
44199 }
44200 
44201 const char *vt_find_shell_command (void)
44202 {
44203   if (access ("/.flatpak-info", F_OK) != -1)
44204   {
44205     static char ret[512];
44206     char buf[256];
44207     FILE *fp = popen("flatpak-spawn --host getent passwd $USER|cut -f 7 -d :", "r");
44208     if (fp)
44209     {
44210       while (fgets (buf, sizeof(buf), fp) != NULL)
44211       {
44212         if (buf[strlen(buf)-1]=='\n')
44213           buf[strlen(buf)-1]=0;
44214         sprintf (ret, "flatpak-spawn --env=TERM=xterm --host %s", buf);
44215       }
44216       pclose (fp);
44217       return ret;
44218     }
44219   }
44220 
44221   if (getenv ("SHELL"))
44222   {
44223     return getenv ("SHELL");
44224   }
44225   int i;
44226   const char *command = NULL;
44227   struct stat stat_buf;
44228   static char *alts[][2] =
44229   {
44230     {"/bin/bash",     "/bin/bash"},
44231     {"/usr/bin/bash", "/usr/bin/bash"},
44232     {"/bin/sh",       "/bin/sh"},
44233     {"/usr/bin/sh",   "/usr/bin/sh"},
44234     {NULL, NULL}
44235   };
44236   for (i = 0; alts[i][0] && !command; i++)
44237     {
44238       lstat (alts[i][0], &stat_buf);
44239       if (S_ISREG (stat_buf.st_mode) || S_ISLNK (stat_buf.st_mode) )
44240         { command = alts[i][1]; }
44241     }
44242   return command;
44243 }
44244 
44245 static char *string_chop_head (char *orig) /* return pointer to reset after arg */
44246 {
44247   int j=0;
44248   int eat=0; /* number of chars to eat at start */
44249 
44250   if(orig)
44251     {
44252       int got_more;
44253       char *o = orig;
44254       while(o[j] == ' ')
44255         {j++;eat++;}
44256 
44257       if (o[j]=='"')
44258         {
44259           eat++;j++;
44260           while(o[j] != '"' &&
44261                 o[j] != 0)
44262             j++;
44263           o[j]='\0';
44264           j++;
44265         }
44266       else if (o[j]=='\'')
44267         {
44268           eat++;j++;
44269           while(o[j] != '\'' &&
44270                 o[j] != 0)
44271             j++;
44272           o[j]='\0';
44273           j++;
44274         }
44275       else
44276         {
44277           while(o[j] != ' ' &&
44278                 o[j] != 0 &&
44279                 o[j] != ';')
44280             j++;
44281         }
44282       if (o[j] == 0 ||
44283           o[j] == ';')
44284         got_more = 0;
44285       else
44286         got_more = 1;
44287       o[j]=0; /* XXX: this is where foo;bar won't work but foo ;bar works*/
44288 
44289       if(eat)
44290        {
44291          int k;
44292          for (k=0; k<j-eat; k++)
44293            orig[k] = orig[k+eat];
44294        }
44295       if (got_more)
44296         return &orig[j+1];
44297     }
44298   return NULL;
44299 }
44300 
44301 void _ctx_add_listen_fd (int fd);
44302 void _ctx_remove_listen_fd (int fd);
44303 
44304 static pid_t
44305 vt_forkpty (int  *amaster,
44306             char *aname,
44307             const struct termios *termp,
44308             const struct winsize *winsize)
44309 {
44310   pid_t pid;
44311   int master = posix_openpt (O_RDWR|O_NOCTTY);
44312   int slave;
44313 
44314   if (master < 0)
44315     return -1;
44316   if (grantpt (master) != 0)
44317     return -1;
44318   if (unlockpt (master) != 0)
44319     return -1;
44320 #if 0
44321   char name[1024];
44322   if (ptsname_r (master, name, sizeof(name)-1))
44323     return -1;
44324 #else
44325   char *name = NULL;
44326   if ((name = ptsname (master)) == NULL)
44327     return -1;
44328 #endif
44329 
44330   slave = open(name, O_RDWR|O_NOCTTY);
44331 
44332   if (termp)   tcsetattr(slave, TCSAFLUSH, termp);
44333   if (winsize) ioctl(slave, TIOCSWINSZ, winsize);
44334 
44335   pid = fork();
44336   if (pid < 0)
44337   {
44338     return pid;
44339   } else if (pid == 0)
44340   {
44341     close (master);
44342     setsid ();
44343     dup2 (slave, STDIN_FILENO);
44344     dup2 (slave, STDOUT_FILENO);
44345     dup2 (slave, STDERR_FILENO);
44346 
44347     close (slave);
44348     return 0;
44349   }
44350   ioctl (slave, TIOCSCTTY, NULL);
44351   close (slave);
44352   *amaster = master;
44353   return pid;
44354 }
44355 
44356 static void vt_run_command (VT *vt, const char *command, const char *term)
44357 {
44358   struct winsize ws;
44359   //signal (SIGCHLD,signal_child);
44360 #if 0
44361   int was_pidone = (getpid () == 1);
44362 #else
44363   int was_pidone = 0; // do no special treatment, all child processes belong
44364                       // to root
44365 #endif
44366   signal (SIGINT,SIG_DFL);
44367   ws.ws_row = vt->rows;
44368   ws.ws_col = vt->cols;
44369   ws.ws_xpixel = ws.ws_col * vt->cw;
44370   ws.ws_ypixel = ws.ws_row * vt->ch;
44371   vt->vtpty.pid = vt_forkpty (&vt->vtpty.pty, NULL, NULL, &ws);
44372   if (vt->vtpty.pid == 0)
44373     {
44374       int i;
44375       if (was_pidone)
44376       {
44377         if (setuid(1000)) fprintf (stderr, "setuid failed\n");
44378       }
44379       else
44380       {
44381         for (i = 3; i<768; i++) { close (i); } /*hack, trying to close xcb */
44382       }
44383       unsetenv ("TERM");
44384       unsetenv ("COLUMNS");
44385       unsetenv ("LINES");
44386       unsetenv ("TERMCAP");
44387       unsetenv ("COLOR_TERM");
44388       unsetenv ("COLORTERM");
44389       unsetenv ("VTE_VERSION");
44390       unsetenv ("CTX_BACKEND");
44391       //setenv ("TERM", "ansi", 1);
44392       //setenv ("TERM", "vt102", 1);
44393       //setenv ("TERM", "vt100", 1);
44394       // setenv ("TERM", term?term:"xterm", 1);
44395       setenv ("TERM", term?term:"xterm-256color", 1);
44396       setenv ("COLORTERM", "truecolor", 1);
44397       //setenv ("CTX_VERSION", "0", 1);
44398       setenv ("CTX_BACKEND", "ctx", 1); // speeds up launching of clients
44399 
44400       {
44401         char *cargv[32];
44402         int   cargc;
44403         char *rest, *copy;
44404         copy = calloc (strlen (command)+2, 1);
44405         strcpy (copy, command);
44406         rest = copy;
44407         cargc = 0;
44408         while (rest && cargc < 30 && rest[0] != ';')
44409         {
44410           cargv[cargc++] = rest;
44411           rest = string_chop_head (rest);
44412         }
44413         cargv[cargc] = NULL;
44414         execvp (cargv[0], cargv);
44415       }
44416       exit (0);
44417     }
44418   else if (vt->vtpty.pid < 0)
44419     {
44420       VT_error ("forkpty failed (%s)", command);
44421       return;
44422     }
44423   fcntl(vt->vtpty.pty, F_SETFL, O_NONBLOCK|O_NOCTTY);
44424   _ctx_add_listen_fd (vt->vtpty.pty);
44425 }
44426 
44427 void vt_destroy (VT *vt)
44428 {
44429   while (vt->lines)
44430     {
44431       vt_line_free (vt->lines->data, 1);
44432       ctx_list_remove (&vt->lines, vt->lines->data);
44433       vt->line_count--;
44434     }
44435   while (vt->scrollback)
44436     {
44437       vt_line_free (vt->scrollback->data, 1);
44438       ctx_list_remove (&vt->scrollback, vt->scrollback->data);
44439     }
44440   if (vt->ctxp)
44441     ctx_parser_free (vt->ctxp);
44442   //if (vt->ctx)
44443   //  { ctx_free (vt->ctx); }
44444   free (vt->argument_buf);
44445   ctx_list_remove (&vts, vt);
44446   kill (vt->vtpty.pid, 9);
44447   _ctx_remove_listen_fd (vt->vtpty.pty);
44448   close (vt->vtpty.pty);
44449 #if 1
44450   if (vt->title)
44451     free (vt->title);
44452 #endif
44453   free (vt);
44454 }
44455 
44456 int vt_get_line_count (VT *vt)
44457 {
44458   int max_pop = 0;
44459   int no = 0;
44460   for (CtxList *l = vt->lines; l; l = l->next, no++)
44461   {
44462     CtxString *str = l->data;
44463     if (str->str[0]) max_pop = no;
44464   }
44465   return max_pop + 1;
44466 }
44467 
44468 const char *vt_get_line (VT *vt, int no)
44469 {
44470   if (no >= vt->rows)
44471   {
44472     CtxList *l = ctx_list_nth (vt->scrollback, no - vt->rows);
44473     if (!l)
44474       {
44475          return "";
44476       }
44477     CtxString *str = l->data;
44478     return str->str;
44479   }
44480   else
44481   {
44482     CtxList *l = ctx_list_nth (vt->lines, no);
44483     if (!l)
44484       {
44485          return "-";
44486       }
44487     CtxString *str = l->data;
44488     return str->str;
44489   }
44490 }
44491 
44492 int vt_line_is_continuation (VT *vt, int no)
44493 {
44494   if (no >= vt->rows)
44495   {
44496     CtxList *l = ctx_list_nth (vt->scrollback, no - vt->rows);
44497     if (!l)
44498       {
44499          return 1;
44500       }
44501     VtLine *line = l->data;
44502     return line->wrapped;
44503   }
44504   else
44505   {
44506     CtxList *l = ctx_list_nth (vt->lines, no);
44507     if (!l)
44508       {
44509          return 1;
44510       }
44511     VtLine *line = l->data;
44512     return line->wrapped;
44513   }
44514 }
44515 
44516 int vt_get_cols (VT *vt)
44517 {
44518   return vt->cols;
44519 }
44520 
44521 int vt_get_rows (VT *vt)
44522 {
44523   return vt->rows;
44524 }
44525 
44526 int vt_get_cursor_x (VT *vt)
44527 {
44528   return vt->cursor_x;
44529 }
44530 
44531 int vt_get_cursor_y (VT *vt)
44532 {
44533   return vt->cursor_y;
44534 }
44535 
44536 static void draw_braille_bit (Ctx *ctx, float x, float y, float cw, float ch, int u, int v)
44537 {
44538   ctx_rectangle (ctx, 0.167 * cw + x + u * cw * 0.5,
44539                  y - ch + 0.080 * ch + v * ch * 0.25,
44540                  0.33 *cw, 0.33 * cw);
44541 }
44542 
44543 static void draw_sextant_bit (Ctx *ctx, float x, float y, float cw, float ch, int u, int v)
44544 {
44545   ctx_rectangle (ctx,  x + u * cw * 0.5,
44546                        y - ch + v * ch * 0.3333,
44547                        0.5 *cw, 0.34 * ch);
44548 }
44549 
44550 int vt_special_glyph (Ctx *ctx, VT *vt, float x, float y, int cw, int ch, int unichar)
44551 {
44552   switch (unichar)
44553     {
44554       case 0x2594: // UPPER_ONE_EIGHT_BLOCK
44555         ctx_begin_path (ctx);
44556         {
44557           float factor = 1.0f/8.0f;
44558           ctx_rectangle (ctx, x, y - ch, cw, ch * factor);
44559           ctx_fill (ctx);
44560         }
44561         return 0;
44562       case 0x2581: // LOWER_ONE_EIGHT_BLOCK:
44563         ctx_begin_path (ctx);
44564         {
44565           float factor = 1.0f/8.0f;
44566           ctx_rectangle (ctx, x, y - ch * factor, cw, ch * factor);
44567           ctx_fill (ctx);
44568         }
44569         return 0;
44570       case 0x2582: // LOWER_ONE_QUARTER_BLOCK:
44571         ctx_begin_path (ctx);
44572         {
44573           float factor = 1.0f/4.0f;
44574           ctx_rectangle (ctx, x, y - ch * factor, cw, ch * factor);
44575           ctx_fill (ctx);
44576         }
44577         return 0;
44578       case 0x2583: // LOWER_THREE_EIGHTS_BLOCK:
44579         ctx_begin_path (ctx);
44580         {
44581           float factor = 3.0f/8.0f;
44582           ctx_rectangle (ctx, x, y - ch * factor, cw, ch * factor);
44583           ctx_fill (ctx);
44584         }
44585         return 0;
44586       case 0x2585: // LOWER_FIVE_EIGHTS_BLOCK:
44587         ctx_begin_path (ctx);
44588         {
44589           float factor = 5.0f/8.0f;
44590           ctx_rectangle (ctx, x, y - ch * factor, cw, ch * factor);
44591           ctx_fill (ctx);
44592         }
44593         return 0;
44594       case 0x2586: // LOWER_THREE_QUARTERS_BLOCK:
44595         ctx_begin_path (ctx);
44596         {
44597           float factor = 3.0f/4.0f;
44598           ctx_rectangle (ctx, x, y - ch * factor, cw, ch * factor);
44599           ctx_fill (ctx);
44600         }
44601         return 0;
44602       case 0x2587: // LOWER_SEVEN_EIGHTS_BLOCK:
44603         ctx_begin_path (ctx);
44604         {
44605           float factor = 7.0f/8.0f;
44606           ctx_rectangle (ctx, x, y - ch * factor, cw, ch * factor);
44607           ctx_fill (ctx);
44608         }
44609         return 0;
44610       case 0x2589: // LEFT_SEVEN_EIGHTS_BLOCK:
44611         ctx_begin_path (ctx);
44612         ctx_rectangle (ctx, x, y - ch, cw*7/8, ch);
44613         ctx_fill (ctx);
44614         return 0;
44615       case 0x258A: // LEFT_THREE_QUARTERS_BLOCK:
44616         ctx_begin_path (ctx);
44617         ctx_rectangle (ctx, x, y - ch, cw*3/4, ch);
44618         ctx_fill (ctx);
44619         return 0;
44620       case 0x258B: // LEFT_FIVE_EIGHTS_BLOCK:
44621         ctx_begin_path (ctx);
44622         ctx_rectangle (ctx, x, y - ch, cw*5/8, ch);
44623         ctx_fill (ctx);
44624         return 0;
44625       case 0x258D: // LEFT_THREE_EIGHTS_BLOCK:
44626         ctx_begin_path (ctx);
44627         ctx_rectangle (ctx, x, y - ch, cw*3/8, ch);
44628         ctx_fill (ctx);
44629         return 0;
44630       case 0x258E: // LEFT_ONE_QUARTER_BLOCK:
44631         ctx_begin_path (ctx);
44632         ctx_rectangle (ctx, x, y - ch, cw/4, ch);
44633         ctx_fill (ctx);
44634         return 0;
44635       case 0x258F: // LEFT_ONE_EIGHT_BLOCK:
44636         ctx_begin_path (ctx);
44637         ctx_rectangle (ctx, x, y - ch, cw/8, ch);
44638         ctx_fill (ctx);
44639         return 0;
44640       case 0x258C: // HALF_LEFT_BLOCK:
44641         ctx_begin_path (ctx);
44642         ctx_rectangle (ctx, x, y - ch, cw/2, ch);
44643         ctx_fill (ctx);
44644         return 0;
44645       case 0x2590: // HALF_RIGHT_BLOCK:
44646         ctx_begin_path (ctx);
44647         ctx_rectangle (ctx, x + cw/2, y - ch, cw/2, ch);
44648         ctx_fill (ctx);
44649         return 0;
44650       case 0x1fb8f: // VT_RIGHT_SEVEN_EIGHTS_BLOCK:
44651         ctx_begin_path (ctx);
44652         ctx_rectangle (ctx, x + cw*1/8, y - ch, cw*7/8, ch);
44653         ctx_fill (ctx);
44654         return 0;
44655       case 0x1fb8d: // VT_RIGHT_FIVE_EIGHTS_BLOCK:
44656         ctx_begin_path (ctx);
44657         ctx_rectangle (ctx, x + cw*3/8, y - ch, cw*5/8, ch);
44658         ctx_fill (ctx);
44659         return 0;
44660       case 0x1fb8b: // VT_RIGHT_ONE_QUARTER_BLOCK:
44661         ctx_begin_path (ctx);
44662         ctx_rectangle (ctx, x + cw*3/4, y - ch, cw/4, ch);
44663         ctx_fill (ctx);
44664         return 0;
44665       case 0x1fb8e: // VT_RIGHT_THREE_QUARTER_BLOCK:
44666         ctx_begin_path (ctx);
44667         ctx_rectangle (ctx, x + cw*1/4, y - ch, cw*3/4, ch);
44668         ctx_fill (ctx);
44669         return 0;
44670       case 0x2595: // VT_RIGHT_ONE_EIGHT_BLOCK:
44671         ctx_begin_path (ctx);
44672         ctx_rectangle (ctx, x + cw*7/8, y - ch, cw/8, ch);
44673         ctx_fill (ctx);
44674         return 0;
44675       case 0x2580: // HALF_UP_BLOCK:
44676         ctx_begin_path (ctx);
44677         ctx_rectangle (ctx, x, y - ch, cw, ch/2);
44678         ctx_fill (ctx);
44679         return 0;
44680       case 0x2584: // _HALF_DOWN_BLOCK:
44681         ctx_begin_path (ctx);
44682         ctx_rectangle (ctx, x, y - ch/2, cw, ch/2);
44683         ctx_fill (ctx);
44684         return 0;
44685       case 0x2596: // _QUADRANT LOWER LEFT
44686         ctx_begin_path (ctx);
44687         ctx_rectangle (ctx, x, y - ch/2, cw/2, ch/2);
44688         ctx_fill (ctx);
44689         return 0;
44690       case 0x2597: // _QUADRANT LOWER RIGHT
44691         ctx_begin_path (ctx);
44692         ctx_rectangle (ctx, x+cw/2, y - ch/2, cw/2, ch/2);
44693         ctx_fill (ctx);
44694         return 0;
44695       case 0x2598: // _QUADRANT UPPER LEFT
44696         ctx_begin_path (ctx);
44697         ctx_rectangle (ctx, x, y - ch, cw/2, ch/2);
44698         ctx_fill (ctx);
44699         return 0;
44700       case 0x259D: // _QUADRANT UPPER RIGHT
44701         ctx_begin_path (ctx);
44702         ctx_rectangle (ctx, x + cw/2, y - ch, cw/2, ch/2);
44703         ctx_fill (ctx);
44704         return 0;
44705       case 0x2599: // _QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT
44706         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2598);
44707         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2596);
44708         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2597);
44709         return 0;
44710       case 0x259A: // _QUADRANT UPPER LEFT AND LOWER RIGHT
44711         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2598);
44712         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2597);
44713         return 0;
44714       case 0x259B: // _QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT
44715         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2598);
44716         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x259D);
44717         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2596);
44718         return 0;
44719       case 0x259C: // _QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT
44720         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2598);
44721         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x259D);
44722         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2597);
44723         return 0;
44724       case 0x259E: // _QUADRANT UPPER RIGHT AND LOWER LEFT
44725         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x259D);
44726         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2596);
44727         return 0;
44728       case 0x259F: // _QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
44729         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x259D);
44730         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2596);
44731         vt_special_glyph (ctx, vt, x, y, cw, ch, 0x2597);
44732         return 0;
44733       case 0x2588: // FULL_BLOCK:
44734         ctx_begin_path (ctx);
44735         ctx_rectangle (ctx, x, y - ch, cw, ch);
44736         ctx_fill (ctx);
44737         return 0;
44738       case 0x2591: // LIGHT_SHADE:
44739         ctx_begin_path (ctx);
44740         ctx_rectangle (ctx, x, y - ch, cw, ch);
44741         ctx_save (ctx);
44742         ctx_global_alpha (ctx, 0.25);
44743         ctx_fill (ctx);
44744         ctx_restore (ctx);
44745         return 0;
44746       case 0x2592: // MEDIUM_SHADE:
44747         ctx_begin_path (ctx);
44748         ctx_rectangle (ctx, x, y - ch, cw, ch);
44749         ctx_save (ctx);
44750         ctx_global_alpha (ctx, 0.5);
44751         ctx_fill (ctx);
44752         ctx_restore (ctx);
44753         return 0;
44754       case 0x2593: // DARK SHADE:
44755         ctx_begin_path (ctx);
44756         ctx_rectangle (ctx, x, y - ch, cw, ch);
44757         ctx_save (ctx);
44758         ctx_global_alpha (ctx, 0.75);
44759         ctx_fill (ctx);
44760         ctx_restore (ctx);
44761         return 0;
44762       case 0x23BA: //HORIZONTAL_SCANLINE-1
44763         ctx_begin_path (ctx);
44764         ctx_rectangle (ctx, x,      y - ch + ch*0.1 - ch * 0.1,
44765                        cw, ch * 0.1);
44766         ctx_fill (ctx);
44767         return 0;
44768       case 0x23BB: //HORIZONTAL_SCANLINE-3
44769         ctx_begin_path (ctx);
44770         ctx_rectangle (ctx, x,      y - ch + ch*0.3 - ch * 0.075,
44771                        cw, ch * 0.1);
44772         ctx_fill (ctx);
44773         return 0;
44774       case 0x23BC: //HORIZONTAL_SCANLINE-7
44775         ctx_begin_path (ctx);
44776         ctx_rectangle (ctx, x,      y - ch + ch*0.7 - ch * 0.025,
44777                        cw, ch * 0.1);
44778         ctx_fill (ctx);
44779         return 0;
44780       case 0x23BD: //HORIZONTAL_SCANLINE-9
44781         ctx_begin_path (ctx);
44782         ctx_rectangle (ctx, x,      y - ch + ch*0.9 + ch * 0.0,
44783                        cw, ch * 0.1);
44784         ctx_fill (ctx);
44785         return 0;
44786       case 0x2500: //VT_BOX_DRAWINGS_LIGHT_HORIZONTAL // and scanline 5
44787         ctx_begin_path (ctx);
44788         ctx_rectangle (ctx, x, y - ch/2 - ch * 0.1 / 2, cw, ch * 0.1);
44789         ctx_fill (ctx);
44790         return 0;
44791       case 0x2212: // minus -sign
44792         ctx_begin_path (ctx);
44793         ctx_rectangle (ctx, x + cw * 0.1, y - ch/2 - ch * 0.1 / 2, cw * 0.8, ch * 0.1);
44794         ctx_fill (ctx);
44795         return 0;
44796       case 0x2502: // VT_BOX_DRAWINGS_LIGHT_VERTICAL:
44797         ctx_begin_path (ctx);
44798         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch, ch * 0.1, ch + 1);
44799         ctx_fill (ctx);
44800         return 0;
44801       case 0x250c: //VT_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT:
44802         ctx_begin_path (ctx);
44803         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch/2 - ch*0.1/2, ch * 0.1, ch/2 + ch*0.1);
44804         ctx_fill (ctx);
44805         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch/2 - ch*0.1/2, cw/2+ ch * 0.1, ch*0.1);
44806         ctx_fill (ctx);
44807         return 0;
44808       case 0x2510: //VT_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT:
44809         ctx_begin_path (ctx);
44810         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch/2 - ch*0.1/2, ch * 0.1, ch/2 + ch*0.1);
44811         ctx_fill (ctx);
44812         ctx_rectangle (ctx, x, y - ch/2 - ch*0.1/2, cw/2+ ch * 0.1/2, ch*0.1);
44813         ctx_fill (ctx);
44814         return 0;
44815       case 0x2514: //VT_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT:
44816         ctx_begin_path (ctx);
44817         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch, ch * 0.1, ch/2+ch*0.1/2);
44818         ctx_fill (ctx);
44819         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch/2 - ch*0.1/2, cw/2 + ch * 0.1, ch*0.1);
44820         ctx_fill (ctx);
44821         return 0;
44822       case 0x2518: //VT_BOX_DRAWINGS_LIGHT_UP_AND_LEFT:
44823         ctx_begin_path (ctx);
44824         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch, ch * 0.1, ch/2+ ch*0.1/2);
44825         ctx_fill (ctx);
44826         ctx_rectangle (ctx, x, y - ch/2-ch*0.1/2, cw/2+ch * 0.1/2, ch*0.1);
44827         ctx_fill (ctx);
44828         return 0;
44829       case 0x251C: //VT_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT:
44830         ctx_begin_path (ctx);
44831         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch/2-ch*0.1/2, cw/2+ch * 0.1, ch*0.1);
44832         ctx_fill (ctx);
44833         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch, ch * 0.1, ch);
44834         ctx_fill (ctx);
44835         return 0;
44836       case 0x2524: //VT_BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT:
44837         ctx_begin_path (ctx);
44838         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch, ch * 0.1, ch);
44839         ctx_fill (ctx);
44840         ctx_rectangle (ctx, x, y - ch/2-ch*0.1/2, cw/2+ch * 0.1/2, ch*0.1);
44841         ctx_fill (ctx);
44842         return 0;
44843       case 0x252C: // VT_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL:
44844         ctx_begin_path (ctx);
44845         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch/2-ch*0.1/2, ch * 0.1, ch/2+ch*0.1);
44846         ctx_fill (ctx);
44847         ctx_rectangle (ctx, x, y - ch/2 - ch * 0.1 / 2, cw, ch * 0.1);
44848         ctx_fill (ctx);
44849         return 0;
44850       case 0x2534: // VT_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL:
44851         ctx_begin_path (ctx);
44852         ctx_rectangle (ctx, x, y - ch/2 - ch * 0.1 / 2, cw, ch * 0.1);
44853         ctx_fill (ctx);
44854         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch, ch * 0.1, ch /2+ch*0.1/2);
44855         ctx_fill (ctx);
44856         return 0;
44857       case 0x253C: // VT_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL:
44858         ctx_begin_path (ctx);
44859         ctx_rectangle (ctx, x, y - ch/2 - ch * 0.1 / 2, cw, ch * 0.1);
44860         ctx_fill (ctx);
44861         ctx_rectangle (ctx, x + cw/2 - ch * 0.1 / 2, y - ch, ch * 0.1, ch);
44862         ctx_fill (ctx);
44863         return 0;
44864       case 0xe0a0: // PowerLine branch
44865         ctx_save (ctx);
44866         ctx_begin_path (ctx);
44867         ctx_move_to (ctx, x+cw/2, y - 0.15 * ch);
44868         ctx_rel_line_to (ctx, -cw/3, -ch * 0.7);
44869         ctx_rel_line_to (ctx, cw/2, 0);
44870         ctx_rel_line_to (ctx, -cw/3, ch * 0.7);
44871         ctx_line_width (ctx, cw * 0.25);
44872         ctx_stroke (ctx);
44873         ctx_restore (ctx);
44874         break;
44875       // case 0xe0a1: // PowerLine LN
44876       // case 0xe0a2: // PowerLine Lock
44877       case 0xe0b0: // PowerLine left solid
44878         ctx_begin_path (ctx);
44879         ctx_move_to (ctx, x, y);
44880         ctx_rel_line_to (ctx, 0, -ch);
44881         ctx_rel_line_to (ctx, cw, ch/2);
44882         ctx_fill (ctx);
44883         return 0;
44884       case 0xe0b1: // PowerLine left line
44885         ctx_save (ctx);
44886         ctx_begin_path (ctx);
44887         ctx_move_to (ctx, x, y - ch * 0.1);
44888         ctx_rel_line_to (ctx, cw * 0.9, -ch/2 * 0.8);
44889         ctx_rel_line_to (ctx, -cw * 0.9, -ch/2 * 0.8);
44890         ctx_line_width (ctx, cw * 0.2);
44891         ctx_stroke (ctx);
44892         ctx_restore (ctx);
44893         return 0;
44894       case 0xe0b2: // PowerLine Right solid
44895         ctx_begin_path (ctx);
44896         ctx_move_to (ctx, x, y);
44897         ctx_rel_move_to (ctx, cw, 0);
44898         ctx_rel_line_to (ctx, -cw, -ch/2);
44899         ctx_rel_line_to (ctx, cw, -ch/2);
44900         ctx_fill (ctx);
44901         return 0;
44902       case 0xe0b3: // PowerLine right line
44903         ctx_save (ctx);
44904         ctx_begin_path (ctx);
44905         ctx_move_to (ctx, x, y - ch * 0.1);
44906         ctx_rel_move_to (ctx, cw, 0);
44907         ctx_rel_line_to (ctx, -cw * 0.9, -ch/2 * 0.8);
44908         ctx_rel_line_to (ctx,  cw * 0.9, ch/2 * 0.8);
44909         ctx_line_width (ctx, cw * 0.2);
44910         ctx_stroke (ctx);
44911         ctx_restore (ctx);
44912         return 0;
44913         /*
44914       case 0x1fb70: // left triangular one quarter block
44915         ctx_begin_path (ctx);
44916         ctx_move_to (ctx, x, y);
44917         ctx_rel_line_to (ctx, 0, -ch);
44918         ctx_rel_line_to (ctx, cw/2, -ch/2);
44919         ctx_fill (ctx);
44920         return 0;
44921       case 0x1fb72: // right triangular one quarter block
44922         ctx_begin_path (ctx);
44923         ctx_move_to (ctx, x, y);
44924         ctx_rel_move_to (ctx, cw/2, -ch/2);
44925         ctx_rel_line_to (ctx, cw/2, -ch/2);
44926         ctx_rel_line_to (ctx, 0, ch);
44927         ctx_fill (ctx);
44928         return 0;
44929       case 0x1fb73: // lower triangular one quarter block
44930         ctx_begin_path (ctx);
44931         ctx_move_to (ctx, x, y);
44932         ctx_rel_line_to (ctx, cw/2, -ch/2);
44933         ctx_rel_line_to (ctx, cw/2, ch/2);
44934         ctx_fill (ctx);
44935         return 0;
44936       case 0x1fb71: // upper triangular one quarter block
44937         ctx_begin_path (ctx);
44938         ctx_move_to (ctx, x, y);
44939         ctx_rel_move_to (ctx, cw/2, -ch/2);
44940         ctx_rel_line_to (ctx, -cw/2, -ch/2);
44941         ctx_rel_line_to (ctx, cw, 0);
44942         ctx_fill (ctx);
44943         return 0;
44944         */
44945       case 0x25E2: // VT_BLACK_LOWER_RIGHT_TRIANGLE:
44946         ctx_begin_path (ctx);
44947         ctx_move_to (ctx, x, y);
44948         ctx_rel_line_to (ctx, cw, -ch);
44949         ctx_rel_line_to (ctx, 0, ch);
44950         ctx_fill (ctx);
44951         return 0;
44952       case 0x25E3: //  VT_BLACK_LOWER_LEFT_TRIANGLE:
44953         ctx_begin_path (ctx);
44954         ctx_move_to (ctx, x, y);
44955         ctx_rel_line_to (ctx, 0, -ch);
44956         ctx_rel_line_to (ctx, cw, ch);
44957         ctx_fill (ctx);
44958         return 0;
44959       case 0x25E4: // tri
44960         ctx_begin_path (ctx);
44961         ctx_move_to (ctx, x, y);
44962         ctx_rel_line_to (ctx, 0, -ch);
44963         ctx_rel_line_to (ctx, cw, 0);
44964         ctx_fill (ctx);
44965         return 0;
44966       case 0x25E5: // tri
44967         ctx_begin_path (ctx);
44968         ctx_move_to (ctx, x, y - ch);
44969         ctx_rel_line_to (ctx, cw, 0);
44970         ctx_rel_line_to (ctx, 0, ch);
44971         ctx_fill (ctx);
44972         return 0;
44973       case 0x2800:
44974       case 0x2801:
44975       case 0x2802:
44976       case 0x2803:
44977       case 0x2804:
44978       case 0x2805:
44979       case 0x2806:
44980       case 0x2807:
44981       case 0x2808:
44982       case 0x2809:
44983       case 0x280A:
44984       case 0x280B:
44985       case 0x280C:
44986       case 0x280D:
44987       case 0x280E:
44988       case 0x280F:
44989       case 0x2810:
44990       case 0x2811:
44991       case 0x2812:
44992       case 0x2813:
44993       case 0x2814:
44994       case 0x2815:
44995       case 0x2816:
44996       case 0x2817:
44997       case 0x2818:
44998       case 0x2819:
44999       case 0x281A:
45000       case 0x281B:
45001       case 0x281C:
45002       case 0x281D:
45003       case 0x281E:
45004       case 0x281F:
45005       case 0x2820:
45006       case 0x2821:
45007       case 0x2822:
45008       case 0x2823:
45009       case 0x2824:
45010       case 0x2825:
45011       case 0x2826:
45012       case 0x2827:
45013       case 0x2828:
45014       case 0x2829:
45015       case 0x282A:
45016       case 0x282B:
45017       case 0x282C:
45018       case 0x282D:
45019       case 0x282E:
45020       case 0x282F:
45021       case 0x2830:
45022       case 0x2831:
45023       case 0x2832:
45024       case 0x2833:
45025       case 0x2834:
45026       case 0x2835:
45027       case 0x2836:
45028       case 0x2837:
45029       case 0x2838:
45030       case 0x2839:
45031       case 0x283A:
45032       case 0x283B:
45033       case 0x283C:
45034       case 0x283D:
45035       case 0x283E:
45036       case 0x283F:
45037         ctx_begin_path (ctx);
45038         {
45039           int bit_pattern = unichar - 0x2800;
45040           int bit = 0;
45041           int u = 0;
45042           int v = 0;
45043           for (bit = 0; bit < 6; bit++)
45044             {
45045               if (bit_pattern & (1<<bit) )
45046                 {
45047                   draw_braille_bit (ctx, x, y, cw, ch, u, v);
45048                 }
45049               v++;
45050               if (v > 2)
45051                 {
45052                   v = 0;
45053                   u++;
45054                 }
45055             }
45056         }
45057         ctx_fill (ctx);
45058         return 0;
45059       case 0x2840:
45060       case 0x2841:
45061       case 0x2842:
45062       case 0x2843:
45063       case 0x2844:
45064       case 0x2845:
45065       case 0x2846:
45066       case 0x2847:
45067       case 0x2848:
45068       case 0x2849:
45069       case 0x284A:
45070       case 0x284B:
45071       case 0x284C:
45072       case 0x284D:
45073       case 0x284E:
45074       case 0x284F:
45075       case 0x2850:
45076       case 0x2851:
45077       case 0x2852:
45078       case 0x2853:
45079       case 0x2854:
45080       case 0x2855:
45081       case 0x2856:
45082       case 0x2857:
45083       case 0x2858:
45084       case 0x2859:
45085       case 0x285A:
45086       case 0x285B:
45087       case 0x285C:
45088       case 0x285D:
45089       case 0x285E:
45090       case 0x285F:
45091       case 0x2860:
45092       case 0x2861:
45093       case 0x2862:
45094       case 0x2863:
45095       case 0x2864:
45096       case 0x2865:
45097       case 0x2866:
45098       case 0x2867:
45099       case 0x2868:
45100       case 0x2869:
45101       case 0x286A:
45102       case 0x286B:
45103       case 0x286C:
45104       case 0x286D:
45105       case 0x286E:
45106       case 0x286F:
45107       case 0x2870:
45108       case 0x2871:
45109       case 0x2872:
45110       case 0x2873:
45111       case 0x2874:
45112       case 0x2875:
45113       case 0x2876:
45114       case 0x2877:
45115       case 0x2878:
45116       case 0x2879:
45117       case 0x287A:
45118       case 0x287B:
45119       case 0x287C:
45120       case 0x287D:
45121       case 0x287E:
45122       case 0x287F:
45123         ctx_begin_path (ctx);
45124         draw_braille_bit (ctx, x, y, cw, ch, 0, 3);
45125         {
45126           int bit_pattern = unichar - 0x2840;
45127           int bit = 0;
45128           int u = 0;
45129           int v = 0;
45130           for (bit = 0; bit < 6; bit++)
45131             {
45132               if (bit_pattern & (1<<bit) )
45133                 {
45134                   draw_braille_bit (ctx, x, y, cw, ch, u, v);
45135                 }
45136               v++;
45137               if (v > 2)
45138                 {
45139                   v = 0;
45140                   u++;
45141                 }
45142             }
45143         }
45144         ctx_fill (ctx);
45145         return 0;
45146       case 0x2880:
45147       case 0x2881:
45148       case 0x2882:
45149       case 0x2883:
45150       case 0x2884:
45151       case 0x2885:
45152       case 0x2886:
45153       case 0x2887:
45154       case 0x2888:
45155       case 0x2889:
45156       case 0x288A:
45157       case 0x288B:
45158       case 0x288C:
45159       case 0x288D:
45160       case 0x288E:
45161       case 0x288F:
45162       case 0x2890:
45163       case 0x2891:
45164       case 0x2892:
45165       case 0x2893:
45166       case 0x2894:
45167       case 0x2895:
45168       case 0x2896:
45169       case 0x2897:
45170       case 0x2898:
45171       case 0x2899:
45172       case 0x289A:
45173       case 0x289B:
45174       case 0x289C:
45175       case 0x289D:
45176       case 0x289E:
45177       case 0x289F:
45178       case 0x28A0:
45179       case 0x28A1:
45180       case 0x28A2:
45181       case 0x28A3:
45182       case 0x28A4:
45183       case 0x28A5:
45184       case 0x28A6:
45185       case 0x28A7:
45186       case 0x28A8:
45187       case 0x28A9:
45188       case 0x28AA:
45189       case 0x28AB:
45190       case 0x28AC:
45191       case 0x28AD:
45192       case 0x28AE:
45193       case 0x28AF:
45194       case 0x28B0:
45195       case 0x28B1:
45196       case 0x28B2:
45197       case 0x28B3:
45198       case 0x28B4:
45199       case 0x28B5:
45200       case 0x28B6:
45201       case 0x28B7:
45202       case 0x28B8:
45203       case 0x28B9:
45204       case 0x28BA:
45205       case 0x28BB:
45206       case 0x28BC:
45207       case 0x28BD:
45208       case 0x28BE:
45209       case 0x28BF:
45210         ctx_begin_path (ctx);
45211         draw_braille_bit (ctx, x, y, cw, ch, 1, 3);
45212         {
45213           int bit_pattern = unichar - 0x2880;
45214           int bit = 0;
45215           int u = 0;
45216           int v = 0;
45217           for (bit = 0; bit < 6; bit++)
45218             {
45219               if (bit_pattern & (1<<bit) )
45220                 {
45221                   draw_braille_bit (ctx, x, y, cw, ch, u, v);
45222                 }
45223               v++;
45224               if (v > 2)
45225                 {
45226                   v = 0;
45227                   u++;
45228                 }
45229             }
45230         }
45231         ctx_fill (ctx);
45232         return 0;
45233       case 0x28C0:
45234       case 0x28C1:
45235       case 0x28C2:
45236       case 0x28C3:
45237       case 0x28C4:
45238       case 0x28C5:
45239       case 0x28C6:
45240       case 0x28C7:
45241       case 0x28C8:
45242       case 0x28C9:
45243       case 0x28CA:
45244       case 0x28CB:
45245       case 0x28CC:
45246       case 0x28CD:
45247       case 0x28CE:
45248       case 0x28CF:
45249       case 0x28D0:
45250       case 0x28D1:
45251       case 0x28D2:
45252       case 0x28D3:
45253       case 0x28D4:
45254       case 0x28D5:
45255       case 0x28D6:
45256       case 0x28D7:
45257       case 0x28D8:
45258       case 0x28D9:
45259       case 0x28DA:
45260       case 0x28DB:
45261       case 0x28DC:
45262       case 0x28DD:
45263       case 0x28DE:
45264       case 0x28DF:
45265       case 0x28E0:
45266       case 0x28E1:
45267       case 0x28E2:
45268       case 0x28E3:
45269       case 0x28E4:
45270       case 0x28E5:
45271       case 0x28E6:
45272       case 0x28E7:
45273       case 0x28E8:
45274       case 0x28E9:
45275       case 0x28EA:
45276       case 0x28EB:
45277       case 0x28EC:
45278       case 0x28ED:
45279       case 0x28EE:
45280       case 0x28EF:
45281       case 0x28F0:
45282       case 0x28F1:
45283       case 0x28F2:
45284       case 0x28F3:
45285       case 0x28F4:
45286       case 0x28F5:
45287       case 0x28F6:
45288       case 0x28F7:
45289       case 0x28F8:
45290       case 0x28F9:
45291       case 0x28FA:
45292       case 0x28FB:
45293       case 0x28FC:
45294       case 0x28FD:
45295       case 0x28FE:
45296       case 0x28FF:
45297         ctx_begin_path (ctx);
45298         draw_braille_bit (ctx, x, y, cw, ch, 0, 3);
45299         draw_braille_bit (ctx, x, y, cw, ch, 1, 3);
45300         {
45301           int bit_pattern = unichar - 0x28C0;
45302           int bit = 0;
45303           int u = 0;
45304           int v = 0;
45305           for (bit = 0; bit < 6; bit++)
45306             {
45307               if (bit_pattern & (1<<bit) )
45308                 {
45309                   draw_braille_bit (ctx, x, y, cw, ch, u, v);
45310                 }
45311               v++;
45312               if (v > 2)
45313                 {
45314                   v = 0;
45315                   u++;
45316                 }
45317             }
45318         }
45319         ctx_fill (ctx);
45320         return 0;
45321       case 0x1fb00:
45322       case 0x1fb01:
45323       case 0x1fb02:
45324       case 0x1fb03:
45325       case 0x1fb04:
45326       case 0x1fb05:
45327       case 0x1fb06:
45328       case 0x1fb07:
45329       case 0x1fb08:
45330       case 0x1fb09:
45331       case 0x1fb0a:
45332       case 0x1fb0b:
45333       case 0x1fb0c:
45334       case 0x1fb0d:
45335       case 0x1fb0e:
45336       case 0x1fb0f:
45337       case 0x1fb10:
45338       case 0x1fb11:
45339       case 0x1fb12:
45340       case 0x1fb13:
45341       case 0x1fb14:
45342       case 0x1fb15:
45343       case 0x1fb16:
45344       case 0x1fb17:
45345       case 0x1fb18:
45346       case 0x1fb19:
45347       case 0x1fb1a:
45348       case 0x1fb1b:
45349       case 0x1fb1c:
45350       case 0x1fb1d:
45351       case 0x1fb1e:
45352       case 0x1fb1f:
45353       case 0x1fb20:
45354       case 0x1fb21:
45355       case 0x1fb22:
45356       case 0x1fb23:
45357       case 0x1fb24:
45358       case 0x1fb25:
45359       case 0x1fb26:
45360       case 0x1fb27:
45361       case 0x1fb28:
45362       case 0x1fb29:
45363       case 0x1fb2a:
45364       case 0x1fb2b:
45365       case 0x1fb2c:
45366       case 0x1fb2d:
45367       case 0x1fb2e:
45368       case 0x1fb2f:
45369       case 0x1fb30:
45370       case 0x1fb31:
45371       case 0x1fb32:
45372       case 0x1fb33:
45373       case 0x1fb34:
45374       case 0x1fb35:
45375       case 0x1fb36:
45376       case 0x1fb37:
45377       case 0x1fb38:
45378       case 0x1fb39:
45379       case 0x1fb3a:
45380       case 0x1fb3b:
45381 
45382         {
45383           ctx_begin_path (ctx);
45384           uint32_t bitmask = (unichar - 0x1fb00) + 1;
45385           if (bitmask > 20) bitmask ++;
45386           if (bitmask > 41) bitmask ++;
45387           int bit = 0;
45388           for (int v = 0; v < 3; v ++)
45389           for (int u = 0; u < 2; u ++, bit ++)
45390           {
45391             if (bitmask & (1<<bit))
45392             {
45393               draw_sextant_bit (ctx, x, y, cw, ch, u, v);
45394             }
45395           }
45396           ctx_fill (ctx);
45397           return 0;
45398         }
45399         break;
45400       case 0x1fb3c:
45401         {
45402           ctx_begin_path (ctx);
45403           ctx_move_to (ctx, x, y);
45404           ctx_rel_line_to (ctx, 0, -ch / 3.0f);
45405           ctx_rel_line_to (ctx, cw/2, ch/3.0f);
45406           ctx_fill (ctx);
45407           return 0;
45408         }
45409         break;
45410       case 0x1fb3d:
45411         {
45412           ctx_begin_path (ctx);
45413           ctx_move_to (ctx, x, y);
45414           ctx_rel_line_to (ctx, 0, -ch/3.0f);
45415           ctx_rel_line_to (ctx, cw, ch/3.0f);
45416           ctx_fill (ctx);
45417           return 0;
45418         }
45419         break;
45420       case 0x1fb3e:
45421         {
45422           ctx_begin_path (ctx);
45423           ctx_move_to (ctx, x, y);
45424           ctx_rel_line_to (ctx, 0,   -ch/3.0f * 2);
45425           ctx_rel_line_to (ctx, cw/2, ch/3.0f * 2);
45426           ctx_fill (ctx);
45427           return 0;
45428         }
45429         break;
45430       case 0x1fb3f:
45431         {
45432           ctx_begin_path (ctx);
45433           ctx_move_to (ctx, x, y);
45434           ctx_rel_line_to (ctx, 0,  -ch/3.0f * 2);
45435           ctx_rel_line_to (ctx, cw, ch/3.0f * 2);
45436           ctx_fill (ctx);
45437           return 0;
45438         }
45439         break;
45440       case 0x1fb40:
45441         {
45442           ctx_begin_path (ctx);
45443           ctx_move_to (ctx, x, y);
45444           ctx_rel_line_to (ctx, 0, -ch);
45445           ctx_rel_line_to (ctx, cw/2, ch);
45446           ctx_fill (ctx);
45447           return 0;
45448         }
45449       case 0x1fb41:
45450         {
45451           ctx_begin_path (ctx);
45452           ctx_move_to (ctx, x, y);
45453           ctx_rel_line_to (ctx, 0, -ch/3.0*2);
45454           ctx_rel_line_to (ctx, cw/2, -ch/3.0);
45455           ctx_rel_line_to (ctx, cw/2, 0);
45456           ctx_rel_line_to (ctx, 0.0, ch);
45457           ctx_rel_line_to (ctx, -cw, 0);
45458           ctx_fill (ctx);
45459           return 0;
45460         }
45461       case 0x1fb42:
45462         {
45463           ctx_begin_path (ctx);
45464           ctx_move_to (ctx, x, y);
45465           ctx_rel_line_to (ctx, 0, -ch/3.0*2);
45466           ctx_rel_line_to (ctx, cw, -ch/3.0);
45467           ctx_rel_line_to (ctx, 0.0, ch);
45468           ctx_rel_line_to (ctx, -cw, 0);
45469           ctx_fill (ctx);
45470           return 0;
45471         }
45472       case 0x1fb43:
45473         {
45474           ctx_begin_path (ctx);
45475           ctx_move_to (ctx, x, y);
45476           ctx_rel_line_to (ctx, 0, -ch/3.0f);
45477           ctx_rel_line_to (ctx, cw/2, -ch/3.0f*2.0f);
45478           ctx_rel_line_to (ctx, cw/2, 0);
45479           ctx_rel_line_to (ctx, 0.0, ch);
45480           ctx_rel_line_to (ctx, -cw, 0);
45481           ctx_fill (ctx);
45482           return 0;
45483         }
45484       case 0x1fb44:
45485         {
45486           ctx_begin_path (ctx);
45487           ctx_move_to (ctx, x, y);
45488           ctx_rel_line_to (ctx, 0, -ch/3.0);
45489           ctx_rel_line_to (ctx, cw, -ch/3.0 * 2);
45490           ctx_rel_line_to (ctx, 0.0, ch);
45491           ctx_rel_line_to (ctx, -cw, 0);
45492           ctx_fill (ctx);
45493           return 0;
45494         }
45495       case 0x1fb45:
45496         {
45497           ctx_begin_path (ctx);
45498           ctx_move_to (ctx, x, y);
45499           ctx_rel_line_to (ctx, cw/2, -ch);
45500           ctx_rel_line_to (ctx, cw/2, 0);
45501           ctx_rel_line_to (ctx, 0.0, ch);
45502           ctx_rel_line_to (ctx, -cw, 0);
45503           ctx_fill (ctx);
45504           return 0;
45505         }
45506       case 0x1fb46:
45507         {
45508           ctx_begin_path (ctx);
45509           ctx_move_to (ctx, x, y);
45510           ctx_rel_line_to (ctx, 0, -ch/3.0);
45511           ctx_rel_line_to (ctx, cw, -ch/3.0);
45512           ctx_rel_line_to (ctx, 0.0, ch/3.0*2);
45513           ctx_rel_line_to (ctx, -cw, 0);
45514           ctx_fill (ctx);
45515           return 0;
45516         }
45517       case 0x1fb47:
45518         {
45519           ctx_begin_path (ctx);
45520           ctx_move_to (ctx, x, y);
45521           ctx_rel_move_to (ctx, cw/2, 0);
45522           ctx_rel_line_to (ctx, cw/2, -ch/3.0);
45523           ctx_rel_line_to (ctx, 0.0, ch/3.0);
45524           ctx_rel_line_to (ctx, -cw/2, 0);
45525           ctx_fill (ctx);
45526           return 0;
45527         }
45528       case 0x1fb48:
45529         {
45530           ctx_begin_path (ctx);
45531           ctx_move_to (ctx, x, y);
45532           ctx_rel_line_to (ctx, cw, -ch/3.0);
45533           ctx_rel_line_to (ctx, 0.0, ch/3.0);
45534           ctx_rel_line_to (ctx, -cw, 0);
45535           ctx_fill (ctx);
45536           return 0;
45537         }
45538       case 0x1fb49:
45539         {
45540           ctx_begin_path (ctx);
45541           ctx_move_to (ctx, x, y);
45542           ctx_rel_move_to (ctx, cw/2, 0);
45543           ctx_rel_line_to (ctx, cw/2, -ch/3.0*2);
45544           ctx_rel_line_to (ctx, 0.0, ch/3.0*2);
45545           ctx_rel_line_to (ctx, -cw/2, 0);
45546           ctx_fill (ctx);
45547           return 0;
45548         }
45549       case 0x1fb4a:
45550         {
45551           ctx_begin_path (ctx);
45552           ctx_move_to (ctx, x, y);
45553           ctx_rel_line_to (ctx, cw, -ch/3.0*2);
45554           ctx_rel_line_to (ctx, 0.0, ch/3.0*2);
45555           ctx_rel_line_to (ctx, -cw, 0);
45556           ctx_fill (ctx);
45557           return 0;
45558         }
45559       case 0x1fb4b:
45560         {
45561           ctx_begin_path (ctx);
45562           ctx_move_to (ctx, x, y);
45563           ctx_rel_line_to (ctx, 0, -ch);
45564           ctx_rel_line_to (ctx, cw/2, 0);
45565           ctx_rel_line_to (ctx, cw/2, ch/3);
45566           ctx_rel_line_to (ctx, 0, ch/3.0*2);
45567           ctx_rel_line_to (ctx, -cw, 0);
45568           ctx_fill (ctx);
45569           return 0;
45570         }
45571       case 0x1fb4c:
45572         {
45573           ctx_begin_path (ctx);
45574           ctx_move_to (ctx, x, y);
45575           ctx_rel_line_to (ctx, 0, -ch);
45576           ctx_rel_line_to (ctx, cw, ch/3);
45577           ctx_rel_line_to (ctx, 0, ch/3.0*2);
45578           ctx_rel_line_to (ctx, -cw, 0);
45579           ctx_fill (ctx);
45580           return 0;
45581         }
45582       case 0x1fb4d:
45583         {
45584           ctx_begin_path (ctx);
45585           ctx_move_to (ctx, x, y);
45586           ctx_rel_line_to (ctx, 0, -ch);
45587           ctx_rel_line_to (ctx, cw, ch/3);
45588           ctx_rel_line_to (ctx, 0, ch/3.0*2);
45589           ctx_rel_line_to (ctx, -cw, 0);
45590           ctx_fill (ctx);
45591           return 0;
45592         }
45593       case 0x1fb4e:
45594         {
45595           ctx_begin_path (ctx);
45596           ctx_move_to (ctx, x, y);
45597           ctx_rel_line_to (ctx, 0, -ch);
45598           ctx_rel_line_to (ctx, cw/2, 0);
45599           ctx_rel_line_to (ctx, cw/2, ch/3 *  2);
45600           ctx_rel_line_to (ctx, 0, ch/3.0);
45601           ctx_rel_line_to (ctx, -cw, 0);
45602           ctx_fill (ctx);
45603           return 0;
45604         }
45605       case 0x1fb4f:
45606         {
45607           ctx_begin_path (ctx);
45608           ctx_move_to (ctx, x, y);
45609           ctx_rel_line_to (ctx, 0, -ch);
45610           ctx_rel_line_to (ctx, cw, ch/3 *  2);
45611           ctx_rel_line_to (ctx, 0, ch/3.0);
45612           ctx_rel_line_to (ctx, -cw, 0);
45613           ctx_fill (ctx);
45614           return 0;
45615         }
45616       case 0x1fb50:
45617         {
45618           ctx_begin_path (ctx);
45619           ctx_move_to (ctx, x, y);
45620           ctx_rel_line_to (ctx, 0, -ch);
45621           ctx_rel_line_to (ctx, cw/2, 0);
45622           ctx_rel_line_to (ctx, cw/2, ch);
45623           ctx_rel_line_to (ctx, -cw, 0);
45624           ctx_fill (ctx);
45625           return 0;
45626         }
45627       case 0x1fb51:
45628         {
45629           ctx_begin_path (ctx);
45630           ctx_move_to (ctx, x, y);
45631           ctx_rel_line_to (ctx, 0, -ch/3.0*2);
45632           ctx_rel_line_to (ctx, cw, ch/3.0);
45633           ctx_rel_line_to (ctx, 0, ch/3.0);
45634           ctx_rel_line_to (ctx, -cw, 0);
45635           ctx_fill (ctx);
45636           return 0;
45637         }
45638       case 0x1fb52:
45639         {
45640           ctx_begin_path (ctx);
45641           ctx_move_to (ctx, x, y);
45642           ctx_rel_move_to (ctx, 0, -ch/3.0);
45643           ctx_rel_line_to (ctx, 0, -ch/3.0*2);
45644           ctx_rel_line_to (ctx, cw, 0);
45645           ctx_rel_line_to (ctx, 0, ch);
45646           ctx_rel_line_to (ctx, -cw/2, 0);
45647           ctx_fill (ctx);
45648           return 0;
45649         }
45650       case 0x1fb53:
45651         {
45652           ctx_begin_path (ctx);
45653           ctx_move_to (ctx, x, y);
45654           ctx_rel_move_to (ctx, 0, -ch/3.0);
45655           ctx_rel_line_to (ctx, 0, -ch/3.0*2);
45656           ctx_rel_line_to (ctx, cw, 0);
45657           ctx_rel_line_to (ctx, 0, ch);
45658           ctx_rel_line_to (ctx, -cw, -ch/3.0);
45659           ctx_fill (ctx);
45660           return 0;
45661         }
45662       case 0x1fb54:
45663         {
45664           ctx_begin_path (ctx);
45665           ctx_move_to (ctx, x, y);
45666           ctx_rel_move_to (ctx, 0, -ch/3.0*2);
45667           ctx_rel_line_to (ctx, 0, -ch/3.0);
45668           ctx_rel_line_to (ctx, cw, 0);
45669           ctx_rel_line_to (ctx, 0, ch);
45670           ctx_rel_line_to (ctx, -cw/2, 0);
45671           ctx_fill (ctx);
45672           return 0;
45673         }
45674       case 0x1fb55:
45675         {
45676           ctx_begin_path (ctx);
45677           ctx_move_to (ctx, x, y);
45678           ctx_rel_move_to (ctx, 0, -ch/3.0*2);
45679           ctx_rel_line_to (ctx, 0, -ch/3.0);
45680           ctx_rel_line_to (ctx, cw, 0);
45681           ctx_rel_line_to (ctx, 0, ch);
45682           ctx_rel_line_to (ctx, -cw, -ch/3.0*2);
45683           ctx_fill (ctx);
45684           return 0;
45685         }
45686       case 0x1fb56:
45687         {
45688           ctx_begin_path (ctx);
45689           ctx_move_to (ctx, x, y);
45690           ctx_rel_move_to (ctx, 0, -ch);
45691           ctx_rel_line_to (ctx, cw, 0);
45692           ctx_rel_line_to (ctx, 0, ch);
45693           ctx_rel_line_to (ctx, -cw/2, 0);
45694           ctx_rel_line_to (ctx, -cw/2, -ch);
45695           ctx_fill (ctx);
45696           return 0;
45697         }
45698       case 0x1fb57:
45699         {
45700           ctx_begin_path (ctx);
45701           ctx_move_to (ctx, x, y);
45702           ctx_rel_move_to (ctx, 0, -ch/3.0*2);
45703           ctx_rel_line_to (ctx, 0, -ch/3);
45704           ctx_rel_line_to (ctx, cw/2, 0);
45705           ctx_rel_line_to (ctx, -cw/2, ch/3);
45706           ctx_fill (ctx);
45707           return 0;
45708         }
45709       case 0x1fb58:
45710         {
45711           ctx_begin_path (ctx);
45712           ctx_move_to (ctx, x, y);
45713           ctx_rel_move_to (ctx, 0, -ch/3.0*2);
45714           ctx_rel_line_to (ctx, 0, -ch/3);
45715           ctx_rel_line_to (ctx, cw, 0);
45716           ctx_rel_line_to (ctx, -cw, ch/3);
45717           ctx_fill (ctx);
45718           return 0;
45719         }
45720       case 0x1fb59:
45721         {
45722           ctx_begin_path (ctx);
45723           ctx_move_to (ctx, x, y);
45724           ctx_rel_move_to (ctx, 0, -ch/3.0);
45725           ctx_rel_line_to (ctx, 0, -ch/3.0*2);
45726           ctx_rel_line_to (ctx, cw/2, 0);
45727           ctx_rel_line_to (ctx, -cw/2, ch/3 * 2);
45728           ctx_fill (ctx);
45729           return 0;
45730         }
45731       case 0x1fb5a:
45732         {
45733           ctx_begin_path (ctx);
45734           ctx_move_to (ctx, x, y);
45735           ctx_rel_move_to (ctx, 0, -ch/3.0);
45736           ctx_rel_line_to (ctx, 0, -ch/3.0*2);
45737           ctx_rel_line_to (ctx, cw, 0);
45738           ctx_rel_line_to (ctx, -cw, ch/3 * 2);
45739           ctx_fill (ctx);
45740           return 0;
45741         }
45742       case 0x1fb5b:
45743         {
45744           ctx_begin_path (ctx);
45745           ctx_move_to (ctx, x, y);
45746           ctx_rel_line_to (ctx, 0, -ch);
45747           ctx_rel_line_to (ctx, cw/2, 0);
45748           ctx_rel_line_to (ctx, -cw/2, ch);
45749           ctx_fill (ctx);
45750           return 0;
45751         }
45752       case 0x1fb5c:
45753         {
45754           ctx_begin_path (ctx);
45755           ctx_move_to (ctx, x, y);
45756           ctx_rel_move_to (ctx, 0, -ch/3);
45757 
45758           ctx_rel_line_to (ctx, 0, -ch/3.0*2);
45759           ctx_rel_line_to (ctx, cw, 0);
45760           ctx_rel_line_to (ctx, 0, ch/3);
45761           ctx_rel_line_to (ctx, -cw, ch/3);
45762           ctx_fill (ctx);
45763           return 0;
45764         }
45765       case 0x1fb5d:
45766         {
45767           ctx_begin_path (ctx);
45768           ctx_move_to (ctx, x, y);
45769           ctx_rel_line_to (ctx, 0, -ch);
45770           ctx_rel_line_to (ctx, cw, 0);
45771           ctx_rel_line_to (ctx, 0, ch/3 * 2);
45772           ctx_rel_line_to (ctx, -cw/2, ch/3);
45773           ctx_rel_line_to (ctx, -cw/2, 0);
45774           ctx_fill (ctx);
45775           return 0;
45776         }
45777       case 0x1fb5e:
45778         {
45779           ctx_begin_path (ctx);
45780           ctx_move_to (ctx, x, y);
45781           ctx_rel_line_to (ctx, 0, -ch);
45782           ctx_rel_line_to (ctx, cw, 0);
45783           ctx_rel_line_to (ctx, 0, ch/3 * 2);
45784           ctx_rel_line_to (ctx, -cw, ch/3);
45785           ctx_fill (ctx);
45786           return 0;
45787         }
45788       case 0x1fb5f:
45789         {
45790           ctx_begin_path (ctx);
45791           ctx_move_to (ctx, x, y);
45792           ctx_rel_line_to (ctx, 0, -ch);
45793           ctx_rel_line_to (ctx, cw, 0);
45794           ctx_rel_line_to (ctx, 0, ch/3);
45795           ctx_rel_line_to (ctx, -cw/2, ch/3*2);
45796           ctx_rel_line_to (ctx, -cw/2, 0);
45797           ctx_fill (ctx);
45798           return 0;
45799         }
45800       case 0x1fb60:
45801         {
45802           ctx_begin_path (ctx);
45803           ctx_move_to (ctx, x, y);
45804           ctx_rel_line_to (ctx, 0, -ch);
45805           ctx_rel_line_to (ctx, cw, 0);
45806           ctx_rel_line_to (ctx, 0, ch/3);
45807           ctx_rel_line_to (ctx, -cw, ch/3*2);
45808           ctx_fill (ctx);
45809           return 0;
45810         }
45811       case 0x1fb61:
45812         {
45813           ctx_begin_path (ctx);
45814           ctx_move_to (ctx, x, y);
45815           ctx_rel_line_to (ctx, 0, -ch);
45816           ctx_rel_line_to (ctx, cw, 0);
45817           ctx_rel_line_to (ctx, -cw/2, ch);
45818           ctx_rel_line_to (ctx, -cw/2, 0);
45819           ctx_fill (ctx);
45820           return 0;
45821         }
45822       case 0x1fb62:
45823         {
45824           ctx_begin_path (ctx);
45825           ctx_move_to (ctx, x, y);
45826           ctx_rel_move_to (ctx, cw/2, -ch);
45827           ctx_rel_line_to (ctx, cw/2, 0);
45828           ctx_rel_line_to (ctx, 0, ch/3);
45829           ctx_rel_line_to (ctx, -cw/2, -ch/3);
45830           ctx_fill (ctx);
45831           return 0;
45832         }
45833       case 0x1fb63:
45834         {
45835           ctx_begin_path (ctx);
45836           ctx_move_to (ctx, x, y);
45837           ctx_rel_move_to (ctx, 0, -ch);
45838           ctx_rel_line_to (ctx, cw, 0);
45839           ctx_rel_line_to (ctx, 0, ch/3);
45840           ctx_rel_line_to (ctx, -cw, -ch/3);
45841           ctx_fill (ctx);
45842           return 0;
45843         }
45844       case 0x1fb64:
45845         {
45846           ctx_begin_path (ctx);
45847           ctx_move_to (ctx, x, y);
45848           ctx_rel_move_to (ctx, cw/2, -ch);
45849           ctx_rel_line_to (ctx, cw/2, 0);
45850           ctx_rel_line_to (ctx, 0, ch/3*2);
45851           ctx_rel_line_to (ctx, -cw/2, -ch/3*2);
45852           ctx_fill (ctx);
45853           return 0;
45854         }
45855       case 0x1fb65:
45856         {
45857           ctx_begin_path (ctx);
45858           ctx_move_to (ctx, x, y);
45859           ctx_rel_move_to (ctx, 0, -ch);
45860           ctx_rel_line_to (ctx, cw, 0);
45861           ctx_rel_line_to (ctx, 0, ch/3*2);
45862           ctx_rel_line_to (ctx, -cw, -ch/3*2);
45863           ctx_fill (ctx);
45864           return 0;
45865         }
45866       case 0x1fb66:
45867         {
45868           ctx_begin_path (ctx);
45869           ctx_move_to (ctx, x, y);
45870           ctx_rel_move_to (ctx, cw/2, -ch);
45871           ctx_rel_line_to (ctx, cw/2, 0);
45872           ctx_rel_line_to (ctx, 0, ch);
45873           ctx_rel_line_to (ctx, -cw/2, -ch);
45874           ctx_fill (ctx);
45875           return 0;
45876         }
45877       case 0x1fb67:
45878         {
45879           ctx_begin_path (ctx);
45880           ctx_move_to (ctx, x, y);
45881           ctx_rel_move_to (ctx, 0, -ch/3.0*2);
45882           ctx_rel_line_to (ctx, 0, -ch/3);
45883           ctx_rel_line_to (ctx, cw, 0);
45884           ctx_rel_line_to (ctx, 0, ch/3.0*2);
45885           ctx_rel_line_to (ctx, -cw, -ch/3.0);
45886           ctx_fill (ctx);
45887           return 0;
45888         }
45889       case 0x1fb68:
45890         {
45891           ctx_begin_path (ctx);
45892           ctx_move_to (ctx, x, y);
45893           ctx_rel_line_to (ctx, cw/2, -ch/2);
45894           ctx_rel_line_to (ctx, -cw/2, -ch/2);
45895           ctx_rel_line_to (ctx, cw, 0);
45896           ctx_rel_line_to (ctx, 0, ch);
45897           ctx_rel_line_to (ctx, -cw, 0);
45898           ctx_fill (ctx);
45899           return 0;
45900         }
45901       case 0x1fb69:
45902         {
45903           ctx_begin_path (ctx);
45904           ctx_move_to (ctx, x, y);
45905           ctx_rel_line_to (ctx, 0, -ch);
45906           ctx_rel_line_to (ctx, cw/2, ch/2);
45907           ctx_rel_line_to (ctx, cw/2, -ch/2);
45908           ctx_rel_line_to (ctx, 0, ch);
45909           ctx_rel_line_to (ctx, -cw, 0);
45910           ctx_fill (ctx);
45911           return 0;
45912         }
45913       case 0x1fb6a:
45914         {
45915           ctx_begin_path (ctx);
45916           ctx_move_to (ctx, x, y);
45917           ctx_rel_line_to (ctx, 0, -ch);
45918           ctx_rel_line_to (ctx, cw, 0);
45919           ctx_rel_line_to (ctx, -cw/2, ch/2);
45920           ctx_rel_line_to (ctx, cw/2, ch/2);
45921           ctx_rel_line_to (ctx, -cw, 0);
45922           ctx_fill (ctx);
45923           return 0;
45924         }
45925       case 0x1fb6b:
45926         {
45927           ctx_begin_path (ctx);
45928           ctx_move_to (ctx, x, y);
45929           ctx_rel_line_to (ctx, 0, -ch);
45930           ctx_rel_line_to (ctx, cw, 0);
45931           ctx_rel_line_to (ctx, 0, ch);
45932           ctx_rel_line_to (ctx, -cw/2, -ch/2);
45933           ctx_rel_line_to (ctx, -cw/2, ch/2);
45934           ctx_fill (ctx);
45935           return 0;
45936         }
45937       case 0x1fb6c:
45938         {
45939           ctx_begin_path (ctx);
45940           ctx_move_to (ctx, x, y);
45941           ctx_rel_line_to (ctx, 0, -ch);
45942           ctx_rel_line_to (ctx, cw/2, ch/2);
45943           ctx_rel_line_to (ctx, -cw/2, ch/2);
45944           ctx_fill (ctx);
45945           return 0;
45946         }
45947       case 0x1fb6d:
45948         {
45949           ctx_begin_path (ctx);
45950           ctx_move_to (ctx, x, y);
45951           ctx_rel_move_to (ctx, 0, -ch);
45952           ctx_rel_line_to (ctx, cw, 0);
45953           ctx_rel_line_to (ctx, -cw/2, ch/2);
45954           ctx_rel_line_to (ctx, -cw/2, -ch/2);
45955           ctx_fill (ctx);
45956           return 0;
45957         }
45958       case 0x1fb6e:
45959         {
45960           ctx_begin_path (ctx);
45961           ctx_move_to (ctx, x, y);
45962           ctx_rel_move_to (ctx, cw, -ch);
45963           ctx_rel_line_to (ctx, 0, ch);
45964           ctx_rel_line_to (ctx, -cw/2, -ch/2);
45965           ctx_rel_line_to (ctx, cw/2, -ch/2);
45966           ctx_fill (ctx);
45967           return 0;
45968         }
45969       case 0x1fb6f:
45970         {
45971           ctx_begin_path (ctx);
45972           ctx_move_to (ctx, x, y);
45973           ctx_rel_line_to (ctx, cw/2, -ch/2);
45974           ctx_rel_line_to (ctx, cw/2, ch/2);
45975           ctx_rel_line_to (ctx, -cw, 0);
45976           ctx_fill (ctx);
45977           return 0;
45978         }
45979       case 0x1fb82:
45980         {
45981           ctx_begin_path (ctx);
45982           ctx_move_to (ctx, x, y);
45983           ctx_rel_move_to (ctx, 0, -ch/8 * 2);
45984           ctx_rel_line_to (ctx, cw, 0);
45985           ctx_rel_move_to (ctx, 0, ch/8 * 2);
45986           ctx_rel_line_to (ctx, -cw, 0);
45987           ctx_fill (ctx);
45988           return 0;
45989         }
45990       case 0x1fb83:
45991         {
45992           ctx_begin_path (ctx);
45993           ctx_move_to (ctx, x, y);
45994           ctx_rel_move_to (ctx, 0, -ch/8 * 3);
45995           ctx_rel_line_to (ctx, cw, 0);
45996           ctx_rel_move_to (ctx, 0, ch/8 * 3);
45997           ctx_rel_line_to (ctx, -cw, 0);
45998           ctx_fill (ctx);
45999           return 0;
46000         }
46001       case 0x1fb84:
46002         {
46003           ctx_begin_path (ctx);
46004           ctx_move_to (ctx, x, y);
46005           ctx_rel_move_to (ctx, 0, -ch/8 * 5);
46006           ctx_rel_line_to (ctx, cw, 0);
46007           ctx_rel_move_to (ctx, 0, ch/8 * 5);
46008           ctx_rel_line_to (ctx, -cw, 0);
46009           ctx_fill (ctx);
46010           return 0;
46011         }
46012       case 0x1fb85:
46013         {
46014           ctx_begin_path (ctx);
46015           ctx_move_to (ctx, x, y);
46016           ctx_rel_move_to (ctx, 0, -ch/8 * 6);
46017           ctx_rel_line_to (ctx, cw, 0);
46018           ctx_rel_move_to (ctx, 0, ch/8 * 6);
46019           ctx_rel_line_to (ctx, -cw, 0);
46020           ctx_fill (ctx);
46021           return 0;
46022         }
46023       case 0x1fb86:
46024         {
46025           ctx_begin_path (ctx);
46026           ctx_move_to (ctx, x, y);
46027           ctx_rel_move_to (ctx, 0, -ch/8 * 7);
46028           ctx_rel_line_to (ctx, cw, 0);
46029           ctx_rel_move_to (ctx, 0, ch/8 * 7);
46030           ctx_rel_line_to (ctx, -cw, 0);
46031           ctx_fill (ctx);
46032           return 0;
46033         }
46034       case 0x1fb87:
46035         {
46036           ctx_begin_path (ctx);
46037           ctx_move_to (ctx, x, y);
46038           ctx_rel_move_to (ctx, cw/8*6, 0);
46039           ctx_rel_line_to (ctx, 0, -ch);
46040           ctx_rel_move_to (ctx, cw/8*2, 0);
46041           ctx_rel_line_to (ctx, 0, ch);
46042           ctx_rel_move_to (ctx, -cw/8*2, 0);
46043           ctx_fill (ctx);
46044           return 0;
46045         }
46046       case 0x1fb88:
46047         {
46048           ctx_begin_path (ctx);
46049           ctx_move_to (ctx, x, y);
46050           ctx_rel_move_to (ctx, cw/8*5, 0);
46051           ctx_rel_line_to (ctx, 0, -ch);
46052           ctx_rel_move_to (ctx, cw/8*3, 0);
46053           ctx_rel_line_to (ctx, 0, ch);
46054           ctx_rel_move_to (ctx, -cw/8*3, 0);
46055           ctx_fill (ctx);
46056           return 0;
46057         }
46058       case 0x1fb89:
46059         {
46060           ctx_begin_path (ctx);
46061           ctx_move_to (ctx, x, y);
46062           ctx_rel_move_to (ctx, cw/8*3, 0);
46063           ctx_rel_line_to (ctx, 0, -ch);
46064           ctx_rel_move_to (ctx, cw/8*5, 0);
46065           ctx_rel_line_to (ctx, 0, ch);
46066           ctx_rel_move_to (ctx, -cw/8*5, 0);
46067           ctx_fill (ctx);
46068           return 0;
46069         }
46070       case 0x1fb8a:
46071         {
46072           ctx_begin_path (ctx);
46073           ctx_move_to (ctx, x, y);
46074           ctx_rel_move_to (ctx, cw/8*2, 0);
46075           ctx_rel_line_to (ctx, 0, -ch);
46076           ctx_rel_move_to (ctx, cw/8*6, 0);
46077           ctx_rel_line_to (ctx, 0, ch);
46078           ctx_rel_move_to (ctx, -cw/8*6, 0);
46079           ctx_fill (ctx);
46080           return 0;
46081         }
46082       case 0x1fb97:
46083         {
46084           ctx_begin_path (ctx);
46085           ctx_move_to (ctx, x, y);
46086           ctx_rel_line_to (ctx, 0, -ch/4);
46087           ctx_rel_move_to (ctx, cw, 0);
46088           ctx_rel_line_to (ctx, 0, ch/4);
46089           ctx_rel_line_to (ctx, -cw, 0);
46090           ctx_close_path (ctx);
46091           ctx_move_to (ctx, 0, -ch/2);
46092           ctx_rel_line_to (ctx, 0, -ch/4);
46093           ctx_rel_move_to (ctx, cw, 0);
46094           ctx_rel_line_to (ctx, 0, ch/4);
46095           ctx_rel_line_to (ctx, -cw, 0);
46096           ctx_fill (ctx);
46097           return 0;
46098         }
46099       case 0x1fb9a:
46100         {
46101           ctx_begin_path (ctx);
46102           ctx_move_to (ctx, x, y);
46103           ctx_rel_line_to (ctx, cw/2, -ch/2);
46104           ctx_rel_line_to (ctx, -cw/2, -ch/2);
46105           ctx_rel_move_to (ctx, cw, 0);
46106           ctx_rel_line_to (ctx, -cw/2, ch/2);
46107           ctx_rel_line_to (ctx, cw/2, ch/2);
46108           ctx_rel_line_to (ctx, -cw, 0);
46109           ctx_fill (ctx);
46110           return 0;
46111         }
46112       case 0x1fb9b:
46113         {
46114           ctx_begin_path (ctx);
46115           ctx_move_to (ctx, x, y);
46116           ctx_rel_line_to (ctx, 0, -ch);
46117           ctx_rel_line_to (ctx, cw/2, ch/2);
46118           ctx_rel_line_to (ctx, cw/2, -ch/2);
46119           ctx_rel_line_to (ctx, 0, ch);
46120           ctx_rel_line_to (ctx, -cw/2, -ch/2);
46121           ctx_rel_line_to (ctx, -cw/2, ch/2);
46122           ctx_fill (ctx);
46123           return 0;
46124         }
46125 
46126     }
46127   return -1;
46128 }
46129 
46130 void vt_ctx_glyph (Ctx *ctx, VT *vt, float x, float y, int unichar, int bold, float scale_x, float scale_y, float offset_y)
46131 {
46132   int did_save = 0;
46133   if (unichar <= ' ')
46134     return;
46135   scale_x *= vt->scale_x;
46136   scale_y *= vt->scale_y;
46137 
46138   if (!ctx_renderer_is_term (ctx))
46139   {
46140     // TODO : use our own special glyphs when glyphs are not passed through
46141     if (!vt_special_glyph (ctx, vt, x, y + offset_y * vt->ch, vt->cw * scale_x, vt->ch * scale_y, unichar) )
46142       return;
46143   }
46144 
46145   if (scale_x != 1.0 || scale_y != 1.0)
46146     {
46147       if (!did_save)
46148       {
46149         ctx_save (ctx);
46150         did_save = 1;
46151       }
46152 
46153       ctx_translate (ctx, x, y);
46154       ctx_scale (ctx, scale_x, scale_y);
46155       ctx_translate (ctx, -x, -y);
46156     }
46157   if (offset_y != 0.0f)
46158   {
46159     if (!did_save)
46160     {
46161       ctx_save (ctx);
46162       did_save = 1;
46163     }
46164     ctx_translate (ctx, 0, vt->font_size * offset_y);
46165   }
46166   y -= vt->font_size * 0.22;
46167   if (bold
46168       && !ctx_renderer_is_term (ctx)
46169      )
46170     {
46171       ctx_move_to (ctx, x - vt->font_size/30.0, y);
46172       //ctx_line_width (ctx, vt->font_size/30.0);
46173       ctx_glyph (ctx, unichar, 0);
46174     }
46175   ctx_move_to (ctx, x, y);
46176   ctx_glyph (ctx, unichar, 0);
46177   if (did_save)
46178     ctx_restore (ctx);
46179 }
46180 
46181 //static uint8_t palette[256][3];
46182 
46183 /* optimized for ANSI ART - and avoidance of human metamers
46184  * among color deficient vision - by distributing and pertubating
46185  * until all 64 combinations - sans self application, have
46186  * likely to be discernable by humans.
46187  */
46188 
46189 
46190 void vt_ctx_get_color (VT *vt, int no, int intensity, uint8_t *rgba)
46191 {
46192   uint8_t r = 0, g = 0, b = 0;
46193   if (no < 16 && no >= 0)
46194     {
46195       switch (intensity)
46196         {
46197           case 0:
46198             no = 0;
46199             break;
46200           case 1:
46201             // 15 becomes 7
46202             if (no == 15) { no = 8; }
46203             else if (no > 8) { no -= 8; }
46204             break;
46205           case 2:
46206             /* give the normal color special treatment, and in really normal
46207              * cirumstances it is the dim variant of foreground that is used
46208              */
46209             if (no == 15) { no = 7; }
46210             break;
46211           case 3:
46212           case 4:
46213             if (no < 8)
46214               { no += 8; }
46215             break;
46216           default:
46217             break;
46218         }
46219       r = palettes[vt->palette_no][no][0];
46220       g = palettes[vt->palette_no][no][1];
46221       b = palettes[vt->palette_no][no][2];
46222     }
46223   else if (no < 16 + 6*6*6)
46224     {
46225       no = no-16;
46226       b = (no % 6) * 255 / 5;
46227       no /= 6;
46228       g = (no % 6) * 255 / 5;
46229       no /= 6;
46230       r = (no % 6) * 255 / 5;
46231     }
46232   else
46233     {
46234       int gray = no - (16 + 6*6*6);
46235       float val = gray * 255 / 24;
46236       r = g = b = val;
46237     }
46238   rgba[0]=r;
46239   rgba[1]=g;
46240   rgba[2]=b;
46241   rgba[3]=255;
46242 }
46243 
46244 int vt_keyrepeat (VT *vt)
46245 {
46246   return vt->keyrepeat;
46247 }
46248 
46249 static void vt_flush_bg (VT *vt, Ctx *ctx)
46250 {
46251   if (vt->bg_active)
46252   {
46253     ctx_rgba8 (ctx, vt->bg_rgba[0], vt->bg_rgba[1], vt->bg_rgba[2], vt->bg_rgba[3]);
46254     ctx_rectangle (ctx, vt->bg_x0, vt->bg_y0, vt->bg_width, vt->bg_height);
46255     ctx_fill (ctx);
46256     vt->bg_active = 0;
46257   }
46258 }
46259 
46260 static void vt_draw_bg (VT *vt, Ctx *ctx,
46261                         float x0, float y0,
46262                         float width, float height,
46263                         uint8_t *rgba)
46264 {
46265    int same_color = !memcmp(rgba, vt->bg_rgba, 4);
46266    if (vt->bg_active && !same_color)
46267    {
46268      vt_flush_bg (vt, ctx);
46269    }
46270 
46271    if (vt->bg_active && same_color)
46272    {
46273      vt->bg_width += width;
46274    }
46275    else
46276    {
46277      memcpy (vt->bg_rgba, rgba, 4);
46278      vt->bg_active = 1;
46279      vt->bg_x0 = x0;
46280      vt->bg_y0 = y0;
46281      vt->bg_width = width;
46282      vt->bg_height = height;
46283    }
46284 }
46285 
46286 float vt_draw_cell (VT      *vt, Ctx *ctx,
46287                     int      row, int col, // pass 0 to force draw - like
46288                     float    x0, float y0, // for scrollback visible
46289                     uint64_t style,
46290                     uint32_t unichar,
46291                     int      dw, int dh,
46292                     int      in_smooth_scroll,
46293                     int      in_select,
46294                     int      is_fg)
46295 // dw is 0 or 1
46296 // dh is 0 1 or -1  1 is upper -1 is lower
46297 {
46298   int on_white = vt->reverse_video;
46299   int color = 0;
46300   int bold = (style & STYLE_BOLD) != 0;
46301   int dim = (style & STYLE_DIM) != 0;
46302   int is_hidden = (style & STYLE_HIDDEN) != 0;
46303   int proportional = (style & STYLE_PROPORTIONAL) != 0;
46304   int fg_set = (style & STYLE_FG_COLOR_SET) != 0;
46305   int bg_intensity = 0;
46306   int fg_intensity = 2;
46307   int reverse = ( (style & STYLE_REVERSE) != 0) ^ in_select;
46308   int blink = ( (style & STYLE_BLINK) != 0);
46309   int blink_fast = ( (style & STYLE_BLINK_FAST) != 0);
46310   int cw = vt->cw;
46311   int ch = vt->ch;
46312   if (proportional)
46313     {
46314       if (vt->font_is_mono)
46315         {
46316           ctx_font (ctx, "regular");
46317           vt->font_is_mono = 0;
46318         }
46319       cw = ctx_glyph_width (ctx, unichar);
46320     }
46321   else
46322     {
46323       if (vt->font_is_mono == 0)
46324         {
46325           ctx_font (ctx, "mono");
46326           vt->font_is_mono = 1;
46327           if (col > 1)
46328             {
46329               int x = x0;
46330               int new_cw = cw - ( (x % cw) );
46331               if (new_cw < cw*3/2)
46332                 { new_cw += cw; }
46333               cw = new_cw;
46334             }
46335         }
46336     }
46337   float scale_x  = 1.0f;
46338   float scale_y  = 1.0f;
46339   float offset_y = 0.0f;
46340   if (dw)
46341     {
46342       scale_x = 2.0f;
46343     }
46344   if (dh)
46345     {
46346       scale_y = 2.0f;
46347     }
46348   if (dh == 1)
46349     {
46350       offset_y = 0.5f;
46351     }
46352   else if (dh == -1)
46353     {
46354       offset_y =  0.0f;
46355     }
46356   if (in_smooth_scroll)
46357     {
46358       offset_y -= vt->scroll_offset / (dh?2:1);
46359     }
46360   cw *= scale_x;
46361   if (blink_fast)
46362     {
46363       if ( (vt->blink_state % 2) == 0)
46364         { blink = 1; }
46365       else
46366         { blink = 0; }
46367     }
46368   else if (blink)
46369     {
46370       if ( (vt->blink_state % 10) < 5)
46371         { blink = 1; }
46372       else
46373         { blink = 0; }
46374     }
46375   /*
46376      from the vt100 technical-manual:
46377 
46378      "Reverse characters [..] normally have dim backgrounds with
46379      black characters so that large white spaces have the same impact
46380      on the viewer's eye as the smaller brighter white areas of
46381      normal characters. Bold and reverse asserted together give a
46382      background of normal intensity. Blink applied to nonreverse
46383      characters causes them to alternate between their usual
46384      intensity and the next lower intensity. (Normal characters vary
46385      between normal and dim intensity. Bold characters vary between
46386      bright and normal intensity.) Blink applied to a reverse
46387      character causes that character to alternate between normal and
46388      reverse video representations of that character."
46389 
46390      This is in contrast with how the truth table appears to be
46391      meant used, since it uses a reverse computed as the xor of
46392      the global screen reverse and the reverse attribute of the
46393      cell.
46394 
46395      To fulfil the more asthethic resulting from implementing the
46396      text, and would be useful to show how the on_bright background
46397      mode of the vt100 actually displays the vttest.
46398 
46399      */
46400   if (on_white)
46401     {
46402           if (bold)
46403             {
46404               bg_intensity =           2;
46405               fg_intensity = blink?1:  0;
46406             }
46407           else if (dim)
46408             {
46409               bg_intensity =           2;
46410               fg_intensity = blink?3:  1;
46411             }
46412           else
46413             {
46414               bg_intensity =           2;
46415               fg_intensity = blink?1:  0;
46416             }
46417           if (fg_set)
46418             {
46419               fg_intensity = blink?2:3;
46420             }
46421     }
46422   else /* bright on dark */
46423     {
46424           if (bold)
46425             {
46426               bg_intensity =           0;
46427               fg_intensity = blink?2:  3;
46428             }
46429           else if (dim)
46430             {
46431               bg_intensity =           0;
46432               fg_intensity = blink?0:  1;
46433             }
46434           else
46435             {
46436               bg_intensity =           0;
46437               fg_intensity = blink?1:  2;
46438             }
46439     }
46440   uint8_t bg_rgb[4]= {0,0,0,255};
46441   uint8_t fg_rgb[4]= {255,255,255,255};
46442   {
46443       //ctx_begin_path (ctx);
46444       if (style &  STYLE_BG24_COLOR_SET)
46445         {
46446           uint64_t temp = style >> 40;
46447           bg_rgb[0] = temp & 0xff;
46448           temp >>= 8;
46449           bg_rgb[1] = temp & 0xff;
46450           temp >>= 8;
46451           bg_rgb[2] = temp & 0xff;
46452 #if 0
46453           if (dh)
46454           {
46455              bg_rgb[0] =
46456              bg_rgb[1] =
46457              bg_rgb[2] = 30;
46458           }
46459 #endif
46460         }
46461       else
46462         {
46463           if (style & STYLE_BG_COLOR_SET)
46464             {
46465               color = (style >> 40) & 255;
46466               bg_intensity = -1;
46467               vt_ctx_get_color (vt, color, bg_intensity, bg_rgb);
46468             }
46469           else
46470             {
46471               switch (bg_intensity)
46472                 {
46473                   case 0:
46474                     for (int i = 0; i <3 ; i++)
46475                       { bg_rgb[i] = vt->bg_color[i]; }
46476                     break;
46477                   case 1:
46478                     for (int i = 0; i <3 ; i++)
46479                       { bg_rgb[i] = vt->bg_color[i] * 0.5 + vt->fg_color[i] * 0.5; }
46480                     break;
46481                   case 2:
46482                     for (int i = 0; i <3 ; i++)
46483                       { bg_rgb[i] = vt->bg_color[i] * 0.05 + vt->fg_color[i] * 0.95; }
46484                     break;
46485                   case 3:
46486                     for (int i = 0; i <3 ; i++)
46487                       { bg_rgb[i] = vt->fg_color[i]; }
46488                     break;
46489                 }
46490             }
46491         }
46492   }
46493   if (style & STYLE_FG24_COLOR_SET)
46494     {
46495       uint64_t temp = style >> 16;
46496       fg_rgb[0] = temp & 0xff;
46497       temp >>= 8;
46498       fg_rgb[1] = temp & 0xff;
46499       temp >>= 8;
46500       fg_rgb[2] = temp & 0xff;
46501     }
46502   else
46503     {
46504       if ( (style & STYLE_FG_COLOR_SET) == 0)
46505         {
46506           switch (fg_intensity)
46507             {
46508               case 0:
46509                 for (int i = 0; i <3 ; i++)
46510                   { fg_rgb[i] = vt->bg_color[i] * 0.7 + vt->fg_color[i] * 0.3; }
46511                 break;
46512               case 1:
46513                 for (int i = 0; i <3 ; i++)
46514                   { fg_rgb[i] = vt->bg_color[i] * 0.5 + vt->fg_color[i] * 0.5; }
46515                 break;
46516               case 2:
46517                 for (int i = 0; i <3 ; i++)
46518                   { fg_rgb[i] = vt->bg_color[i] * 0.20 + vt->fg_color[i] * 0.80; }
46519                 break;
46520               case 3:
46521                 for (int i = 0; i <3 ; i++)
46522                   { fg_rgb[i] = vt->fg_color[i]; }
46523             }
46524         }
46525       else
46526         {
46527           color = (style >> 16) & 255;
46528           vt_ctx_get_color (vt, color, fg_intensity, fg_rgb);
46529         }
46530   }
46531 
46532   if (reverse)
46533   {
46534     for (int c = 0; c < 3; c ++)
46535     {
46536       int t = bg_rgb[c];
46537       bg_rgb[c] = fg_rgb[c];
46538       fg_rgb[c] = t;
46539     }
46540   }
46541 
46542   if (is_fg ||
46543       ((!on_white) && bg_rgb[0]==0 && bg_rgb[1]==0 && bg_rgb[2]==0) ||
46544       ((on_white) && bg_rgb[0]==255 && bg_rgb[1]==255 && bg_rgb[2]==255))
46545           /* these comparisons are not entirely correct, when on dark background we assume black to
46546            * be default and non-set, even when theme might differ
46547            */
46548   {
46549     /* skipping draw of background */
46550   }
46551   else
46552   {
46553     if (dh)
46554     {
46555       vt_draw_bg (vt, ctx, ctx_floorf(x0),
46556          ctx_floorf(y0 - ch - ch * (vt->scroll_offset)), cw, ch, bg_rgb);
46557     }
46558     else
46559     {
46560       vt_draw_bg (vt, ctx, x0, y0 - ch + ch * offset_y, cw, ch, bg_rgb);
46561     }
46562   }
46563 
46564   if (!is_fg)
46565     return cw;
46566 
46567   int italic        = (style & STYLE_ITALIC) != 0;
46568   int strikethrough = (style & STYLE_STRIKETHROUGH) != 0;
46569   int overline      = (style & STYLE_OVERLINE) != 0;
46570   int underline     = (style & STYLE_UNDERLINE) != 0;
46571   int underline_var = (style & STYLE_UNDERLINE_VAR) != 0;
46572   if (dh == 1)
46573     {
46574       underline = underline_var = 0;
46575     }
46576   int double_underline = 0;
46577   int curved_underline = 0;
46578   if (underline_var)
46579     {
46580       if (underline)
46581         {
46582           double_underline = 1;
46583         }
46584       else
46585         {
46586           curved_underline = 1;
46587         }
46588     }
46589 
46590   int has_underline = (underline || double_underline || curved_underline);
46591 
46592   if (unichar == ' ' && !has_underline)
46593     is_hidden = 1;
46594 
46595   if (!is_hidden)
46596     {
46597 
46598       ctx_rgba8 (ctx, fg_rgb[0], fg_rgb[1], fg_rgb[2], 255);
46599 
46600 
46601       if (italic)
46602         {
46603           ctx_save (ctx);
46604           ctx_translate (ctx, (x0 + cw/3), (y0 + vt->ch/2) );
46605           ctx_scale (ctx, 0.9, 0.9);
46606           ctx_rotate (ctx, 0.15);
46607           ctx_translate (ctx, - (x0 + cw/3), - (y0 + vt->ch/2) );
46608         }
46609       vt_ctx_glyph (ctx, vt, x0, y0, unichar, bold, scale_x, scale_y, offset_y);
46610       if (italic)
46611         {
46612           ctx_restore (ctx);
46613         }
46614       if (curved_underline)
46615         {
46616           ctx_begin_path (ctx);
46617           ctx_move_to (ctx, x0, y0 - vt->font_size * 0.07 - vt->ch * vt->scroll_offset);
46618           ctx_rel_line_to (ctx, (cw+2) /3, -vt->ch * 0.05);
46619           ctx_rel_line_to (ctx, (cw+2) /3, vt->ch * 0.1);
46620           ctx_rel_line_to (ctx, (cw+2) /3, -vt->ch * 0.05);
46621           //ctx_rel_line_to (ctx, cw, 0);
46622           ctx_line_width (ctx, vt->font_size * (style &  STYLE_BOLD?0.050:0.04) );
46623           ctx_stroke (ctx);
46624         }
46625       else if (double_underline)
46626         {
46627           ctx_begin_path (ctx);
46628           ctx_move_to (ctx, x0, y0 - vt->font_size * 0.130 - vt->ch * vt->scroll_offset);
46629           ctx_rel_line_to (ctx, cw, 0);
46630           ctx_move_to (ctx, x0, y0 - vt->font_size * 0.030 - vt->ch * vt->scroll_offset);
46631           ctx_rel_line_to (ctx, cw, 0);
46632           ctx_line_width (ctx, vt->font_size * (style &  STYLE_BOLD?0.050:0.04) );
46633           ctx_stroke (ctx);
46634         }
46635       else if (underline)
46636         {
46637           ctx_begin_path (ctx);
46638           ctx_move_to (ctx, x0, y0 - vt->font_size * 0.07 - vt->ch * vt->scroll_offset);
46639           ctx_rel_line_to (ctx, cw, 0);
46640           ctx_line_width (ctx, vt->font_size * (style &  STYLE_BOLD?0.075:0.05) );
46641           ctx_stroke (ctx);
46642         }
46643       if (overline)
46644         {
46645           ctx_begin_path (ctx);
46646           ctx_move_to (ctx, x0, y0 - vt->font_size * 0.94 - vt->ch * vt->scroll_offset);
46647           ctx_rel_line_to (ctx, cw, 0);
46648           ctx_line_width (ctx, vt->font_size * (style &  STYLE_BOLD?0.075:0.05) );
46649           ctx_stroke (ctx);
46650         }
46651       if (strikethrough)
46652         {
46653           ctx_begin_path (ctx);
46654           ctx_move_to (ctx, x0, y0 - vt->font_size * 0.43 - vt->ch * vt->scroll_offset);
46655           ctx_rel_line_to (ctx, cw, 0);
46656           ctx_line_width (ctx, vt->font_size * (style &  STYLE_BOLD?0.075:0.05) );
46657           ctx_stroke (ctx);
46658         }
46659     }
46660   return cw;
46661 }
46662 
46663 int vt_has_blink (VT *vt)
46664 {
46665   if (!vt) return 0;
46666   return (vt->in_smooth_scroll ?  10 : 0);
46667   //return vt->has_blink + (vt->in_smooth_scroll ?  10 : 0);
46668 }
46669 
46670 //extern int enable_terminal_menu;
46671 //
46672 
46673 //void ctx_set_popup (Ctx *ctx, void (*popup)(Ctx *ctx, void *data), void *popup_data);
46674 
46675 static char *primary = NULL;
46676 static void scrollbar_drag (CtxEvent *event, void *data, void *data2);
46677 static int scrollbar_down = 0;
46678 
46679 void vt_mouse_event (CtxEvent *event, void *data, void *data2)
46680 {
46681   VT   *vt = data;
46682   CtxClient *client = vt_get_client (vt);
46683   float  x = event->x;
46684   float  y = event->y;
46685   int device_no = event->device_no;
46686   char buf[128]="";
46687   if ((!vt->in_alt_screen) &&
46688       (event->x > vt->width - vt->cw * 1.5 || scrollbar_down) &&
46689       (event->type == CTX_DRAG_MOTION ||
46690       event->type == CTX_DRAG_PRESS ||
46691       event->type == CTX_DRAG_RELEASE))
46692     return scrollbar_drag (event, data, data2);
46693   switch (event->type)
46694   {
46695     case CTX_MOTION:
46696     case CTX_DRAG_MOTION:
46697       //if (event->device_no==1)
46698       {
46699         sprintf (buf, "mouse-motion %.0f %.0f %i", x, y, device_no);
46700 //      ctx_set_dirty (event->ctx, 1);
46701         ctx_client_lock (client);
46702         vt_feed_keystring (vt, event, buf);
46703         ctx_client_unlock (client);
46704 //      vt->rev++;
46705       }
46706       break;
46707     case CTX_DRAG_PRESS:
46708       if (event->device_no==2)
46709       {
46710         if (primary)
46711         {
46712           if (vt)
46713             vt_paste (vt, primary);
46714         }
46715       }
46716       else if (event->device_no==3 && !vt->in_alt_screen)
46717       {
46718         vt->popped = 1;
46719       }
46720       else
46721       {
46722         sprintf (buf, "mouse-press %.0f %.0f %i", x, y, device_no);
46723         ctx_client_lock (client);
46724         vt_feed_keystring (vt, event, buf);
46725         ctx_client_unlock (client);
46726 //      ctx_set_dirty (event->ctx, 1);
46727 //      vt->rev++;
46728       }
46729       break;
46730     case CTX_DRAG_RELEASE:
46731       if (event->device_no==3 && !vt->in_alt_screen)
46732       {
46733         vt->popped = 0;
46734       }
46735         ctx_set_dirty (event->ctx, 1);
46736         sprintf (buf, "mouse-release %.0f %.0f %i", x, y, device_no);
46737         ctx_client_lock (client);
46738         vt_feed_keystring (vt, event, buf);
46739         ctx_client_unlock (client);
46740       break;
46741     default:
46742       // we should not stop propagation
46743       return;
46744       break;
46745   }
46746   event->stop_propagate = 1;
46747 //vt->rev++;
46748 }
46749 static int scrollbar_focused = 0;
46750 #if 0
46751 static void scrollbar_enter (CtxEvent *event, void *data, void *data2)
46752 {
46753   VT *vt = data;
46754   vt->rev++;
46755   scrollbar_focused = 1;
46756 }
46757 
46758 static void scrollbar_leave (CtxEvent *event, void *data, void *data2)
46759 {
46760   VT *vt = data;
46761   vt->rev++;
46762   scrollbar_focused = 0;
46763 }
46764 #endif
46765 
46766 int ctx_vt_had_alt_screen (VT *vt)
46767 {
46768   return vt?vt->had_alt_screen:0;
46769 }
46770 
46771 static void scrollbar_drag (CtxEvent *event, void *data, void *data2)
46772 {
46773   VT *vt = data;
46774   float disp_lines = vt->rows;
46775   float tot_lines = vt->line_count + vt->scrollback_count;
46776 
46777   vt->scroll = tot_lines - disp_lines - (event->y*1.0/ ctx_client_height (vt->id)) * tot_lines + disp_lines/2;
46778   if (vt->scroll < 0) { vt->scroll = 0.0; }
46779   if (vt->scroll > vt->scrollback_count) { vt->scroll = vt->scrollback_count; }
46780   vt->rev++;
46781   ctx_set_dirty (event->ctx, 1);
46782   event->stop_propagate = 1;
46783 
46784   switch (event->type)
46785   {
46786     case CTX_DRAG_PRESS:
46787       scrollbar_down = 1;
46788       break;
46789     case CTX_DRAG_RELEASE:
46790       scrollbar_down = 0;
46791       break;
46792     default:
46793       break;
46794   }
46795 }
46796 
46797 #if 0
46798 static void scroll_handle_drag (CtxEvent *event, void *data, void *data2)
46799 {
46800   VT *vt = data;
46801   float tot_lines = vt->line_count + vt->scrollback_count;
46802   if (event->type == CTX_DRAG_MOTION)
46803   {
46804     vt->scroll -= (event->delta_y * tot_lines) / (vt->rows * vt->ch);
46805   }
46806   if (vt->scroll < 0) { vt->scroll = 0.0; }
46807   if (vt->scroll > vt->scrollback_count) { vt->scroll = vt->scrollback_count; }
46808   vt->rev++;
46809   event->stop_propagate = 1;
46810 }
46811 #endif
46812 
46813 #if 0
46814 static void test_popup (Ctx *ctx, void *data)
46815 {
46816   VT *vt = data;
46817 
46818   float x = ctx_client_x (vt->id);
46819   float y = ctx_client_y (vt->id);
46820   ctx_rectangle (ctx, x, y, 100, 100);
46821   ctx_rgb (ctx, 1,0,0);
46822   ctx_fill (ctx);
46823 }
46824 #endif
46825 
46826 void itk_style_color (Ctx *ctx, const char *name); // only itk fun used in vt
46827 
46828 void vt_use_images (VT *vt, Ctx *ctx)
46829 {
46830   /*  this is a call intended for minimized/shaded fully obscured
46831    *  clients to make sure their textures are kept alive
46832    *  in the server
46833    */
46834   //float x0=0;
46835   float y0=0;
46836   //vt->has_blink = 0;
46837   //vt->blink_state++;
46838 
46839   ctx_save (ctx);
46840 
46841   {
46842     /* draw graphics */
46843     for (int row = ((vt->scroll!=0.0f)?vt->scroll:0);
46844          row < (vt->scroll) + vt->rows * 4;
46845          row ++)
46846     {
46847        CtxList *l = ctx_list_nth (vt->lines, row);
46848        float y = y0 + vt->ch * (vt->rows - row);
46849 
46850        if (row >= vt->rows && !vt->in_alt_screen)
46851          {
46852            l = ctx_list_nth (vt->scrollback, row-vt->rows);
46853          }
46854 
46855        if (l && y <= (vt->rows - vt->scroll) *  vt->ch)
46856          {
46857            VtLine *line = l->data;
46858            if (line->ctx_copy)
46859              {
46860                ctx_render_ctx_textures (line->ctx_copy, ctx);
46861              }
46862          }
46863     }
46864   }
46865   ctx_restore (ctx);
46866 }
46867 
46868 
46869 void vt_register_events (VT *vt, Ctx *ctx, double x0, double y0)
46870 {
46871   ctx_begin_path (ctx);
46872   ctx_save (ctx);
46873   ctx_translate (ctx, x0, y0);
46874   ctx_rectangle (ctx, 0, 0, vt->cols * vt->cw, vt->rows * vt->ch);
46875   ctx_listen (ctx, CTX_DRAG,   vt_mouse_event, vt, NULL);
46876   ctx_listen (ctx, CTX_MOTION, vt_mouse_event, vt, NULL);
46877   ctx_begin_path (ctx);
46878   ctx_restore (ctx);
46879 }
46880 
46881 void vt_draw (VT *vt, Ctx *ctx, double x0, double y0)
46882 {
46883   ctx_begin_path (ctx);
46884   ctx_save (ctx);
46885   ctx_translate (ctx, x0, y0);
46886   x0 = 0;
46887   y0 = 0;
46888   ctx_font (ctx, "mono");
46889   vt->font_is_mono = 0;
46890   ctx_font_size (ctx, vt->font_size * vt->font_to_cell_scale);
46891   vt->has_blink = 0;
46892   vt->blink_state++;
46893 #if 0
46894   int cursor_x_px = 0;
46895   int cursor_y_px = 0;
46896   int cursor_w = vt->cw;
46897   int cursor_h = vt->ch;
46898   cursor_x_px = x0 + (vt->cursor_x - 1) * vt->cw;
46899   cursor_y_px = y0 + (vt->cursor_y - 1) * vt->ch;
46900   cursor_w = vt->cw;
46901   cursor_h = vt->ch;
46902 #endif
46903   ctx_save (ctx);
46904   //if (vt->scroll || full)
46905     {
46906       ctx_begin_path (ctx);
46907 #if 1
46908       ctx_rectangle (ctx, 0, 0, vt->width, //(vt->cols) * vt->cw,
46909                      (vt->rows) * vt->ch);
46910       if (vt->reverse_video)
46911         {
46912           itk_style_color (ctx, "terminal-bg-reverse");
46913           ctx_fill  (ctx);
46914         }
46915       else
46916         {
46917           itk_style_color (ctx, "terminal-bg");
46918           ctx_fill  (ctx);
46919         }
46920 #endif
46921       if (vt->scroll != 0.0f)
46922         ctx_translate (ctx, 0.0, vt->ch * vt->scroll);
46923     }
46924   /* draw terminal lines */
46925    {
46926      for (int row = (vt->scroll!=0.0f)?vt->scroll:0; row < (vt->scroll) + vt->rows; row ++)
46927        {
46928          CtxList *l = ctx_list_nth (vt->lines, row);
46929          float y = y0 + vt->ch * (vt->rows - row);
46930          if (row >= vt->rows)
46931            {
46932              l = ctx_list_nth (vt->scrollback, row-vt->rows);
46933            }
46934          if (l && y <= (vt->rows - vt->scroll) *  vt->ch)
46935            {
46936              VtLine *line = l->data;
46937              int r = vt->rows - row;
46938              const char *data = line->string.str;
46939 
46940              vt->bg_active = 0;
46941              for (int is_fg = 0; is_fg < 2; is_fg++)
46942              {
46943                const char *d = data;
46944                float x = x0;
46945                uint64_t style = 0;
46946                uint32_t unichar = 0;
46947                int in_scrolling_region = vt->in_smooth_scroll &&
46948                    ((r >= vt->margin_top && r <= vt->margin_bottom) || r <= 0);
46949                if (is_fg)
46950                   vt_flush_bg (vt, ctx);
46951 
46952                for (int col = 1; col <= vt->cols * 1.33 && x < vt->cols * vt->cw; col++)
46953                  {
46954                    int c = col;
46955                    int real_cw;
46956                    int in_selected_region = 0;
46957                    //if (vt->in_alt_screen == 0)
46958                    {
46959                    if (r > vt->select_start_row && r < vt->select_end_row)
46960                      {
46961                        in_selected_region = 1;
46962                      }
46963                    else if (r == vt->select_start_row)
46964                      {
46965                        if (col >= vt->select_start_col) { in_selected_region = 1; }
46966                        if (r == vt->select_end_row)
46967                          {
46968                            if (col > vt->select_end_col) { in_selected_region = 0; }
46969                          }
46970                      }
46971                    else if (r == vt->select_end_row)
46972                      {
46973                        in_selected_region = 1;
46974                        if (col > vt->select_end_col) { in_selected_region = 0; }
46975                      }
46976                    }
46977                    if (vt->select_active == 0) in_selected_region = 0;
46978                    style = vt_line_get_style (line, col-1);
46979                    unichar = d?ctx_utf8_to_unichar (d) :' ';
46980 
46981                    int is_cursor = 0;
46982                    if (vt->cursor_x == col && vt->cursor_y == vt->rows - row && vt->cursor_visible)
46983                       is_cursor = 1;
46984 
46985                    real_cw=vt_draw_cell (vt, ctx, r, c, x, y, style, unichar,
46986                                          line->double_width,
46987                                          line->double_height_top?1:
46988                                          line->double_height_bottom?-1:0,
46989                                          in_scrolling_region,
46990                                          in_selected_region ^ is_cursor, is_fg);
46991                    if (r == vt->cursor_y && col == vt->cursor_x)
46992                      {
46993 #if 0
46994                        cursor_x_px = x;
46995 #endif
46996                      }
46997                    x+=real_cw;
46998                    if (style & STYLE_BLINK ||
46999                        style & STYLE_BLINK_FAST)
47000                      {
47001                        vt->has_blink = 1;
47002                      }
47003                    if (d)
47004                      {
47005                        d = mrg_utf8_skip (d, 1);
47006                        if (!*d) { d = NULL; }
47007                      }
47008                  }
47009              }
47010 #if 0
47011              if (line->wrapped)
47012              {
47013                ctx_rectangle (ctx, x0, y, 10, 10);
47014                ctx_rgb (ctx, 1,0,0);
47015                ctx_fill (ctx);
47016              }
47017 #endif
47018           }
47019       }
47020   }
47021 
47022 #if 0
47023   /* draw cursor (done inline with fg/bg reversing, some cursor styles might need
47024    * additional drawing though
47025    */
47026   if (vt->cursor_visible)
47027     {
47028     //  ctx_rgba (ctx, 0.9, 0.8, 0.0, 0.5333);
47029       ctx_rgba (ctx, 1.0,1.0,1.0,1.0);
47030       ctx_begin_path (ctx);
47031       ctx_rectangle (ctx,
47032                      cursor_x_px, cursor_y_px,
47033                      cursor_w, cursor_h);
47034       ctx_fill (ctx);
47035     }
47036 #endif
47037 
47038 
47039   {
47040     /* draw graphics */
47041      for (int row = ((vt->scroll!=0.0f)?vt->scroll:0); row < (vt->scroll) + vt->rows * 4; row ++)
47042       {
47043         CtxList *l = ctx_list_nth (vt->lines, row);
47044         float y = y0 + vt->ch * (vt->rows - row);
47045 
47046         if (row >= vt->rows && !vt->in_alt_screen)
47047           {
47048             l = ctx_list_nth (vt->scrollback, row-vt->rows);
47049           }
47050 
47051         if (l && y <= (vt->rows - vt->scroll) *  vt->ch)
47052           {
47053             VtLine *line = l->data;
47054             {
47055             for (int i = 0; i < 4; i++)
47056               {
47057                 Image *image = line->images[i];
47058                 if (image)
47059                   {
47060                     int u = (line->image_col[i]-1) * vt->cw + (line->image_X[i] * vt->cw);
47061                     int v = y - vt->ch + (line->image_Y[i] * vt->ch);
47062                 //  int rows = (image->height + (vt->ch-1) ) /vt->ch;
47063                 //
47064                 //
47065                     if (v + image->height +vt->scroll * vt->ch > 0.0 &&
47066                         image->width && image->height /* some ghost images appear with these */
47067                         )
47068                     {
47069                     ctx_save (ctx);
47070                     ctx_rectangle (ctx, x0, y0 - vt->scroll * vt->ch, vt->cw * vt->cols,
47071                                     vt->ch * vt->rows);
47072                     ctx_clip (ctx);
47073                     char texture_n[65];
47074 
47075                     sprintf (texture_n, "vtimg%i", image->eid_no);
47076                     ctx_rectangle (ctx, u, v, image->width, image->height);
47077                     ctx_translate (ctx, u, v);
47078 
47079                     //replace this texture_n with NULL to
47080                     // be content addressed - but bit slower
47081                     ctx_define_texture (ctx, texture_n, image->width,
47082                                         image->height,
47083                                         0,
47084                                         image->kitty_format == 32 ?
47085                                                  CTX_FORMAT_RGBA8 :
47086                                                  CTX_FORMAT_RGB8,
47087                                         image->data, texture_n);
47088                     ctx_fill (ctx);
47089 
47090                     ctx_restore (ctx);
47091                     }
47092                   }
47093               }
47094 
47095             if (line->ctx_copy)
47096               {
47097                 //fprintf (stderr, " [%i]\n", _ctx_frame (ctx));
47098                 //ctx_render_stream (line->ctx_copy, stderr, 1);
47099 
47100                 ctx_begin_path (ctx);
47101                 ctx_save (ctx);
47102                 ctx_rectangle (ctx, x0, y0 - vt->scroll * vt->ch, vt->cw * vt->cols,
47103                                     vt->ch * vt->rows);
47104                 ctx_clip (ctx);
47105                 ctx_translate (ctx, 0.0, y - vt->ch);
47106 
47107                 //(vt->rows-row-1) * (vt->ch) );
47108                 //float factor = vt->cols * vt->cw / 1000.0;
47109                 //ctx_scale (ctx, factor, factor);
47110                 //
47111                 ctx_render_ctx (line->ctx_copy, ctx);
47112                 ctx_restore (ctx);
47113               }
47114             }
47115           }
47116     //  y -= vt->ch;
47117       }
47118   }
47119 
47120 
47121   for (int i = 0; i < 4; i++)
47122     {
47123       if (vt->leds[i])
47124         {
47125           ctx_rgba (ctx, .5,1,.5,0.8);
47126           ctx_rectangle (ctx, vt->cw * i + vt->cw * 0.25, vt->ch * 0.25, vt->cw/2, vt->ch/2);
47127           ctx_fill (ctx);
47128         }
47129     }
47130   ctx_restore (ctx);
47131 //#define SCROLL_SPEED 0.25;
47132 #define SCROLL_SPEED 0.001;
47133   if (vt->in_smooth_scroll)
47134    {
47135      if (vt->in_smooth_scroll<0)
47136        {
47137          vt->scroll_offset += SCROLL_SPEED;
47138          if (vt->scroll_offset >= 0.0)
47139            {
47140              vt->scroll_offset = 0;
47141              vt->in_smooth_scroll = 0;
47142              vt->rev++;
47143            }
47144        }
47145      else
47146        {
47147          vt->scroll_offset -= SCROLL_SPEED;
47148          if (vt->scroll_offset <= 0.0)
47149            {
47150              vt->scroll_offset = 0;
47151              vt->in_smooth_scroll = 0;
47152              vt->rev++;
47153            }
47154        }
47155    }
47156 
47157     /* scrollbar */
47158     if (!vt->in_alt_screen)
47159     {
47160       float disp_lines = vt->rows;
47161       float tot_lines = vt->line_count + vt->scrollback_count;
47162       float offset = (tot_lines - disp_lines - vt->scroll) / tot_lines;
47163       float win_len = disp_lines / tot_lines;
47164 
47165 #if 0
47166       ctx_rectangle (ctx, (vt->cols *vt->cw), 0,
47167                        (vt->width) - (vt->cols * vt->cw),
47168                        vt->rows *  vt->ch);
47169       ctx_rgb (ctx,1,0,0);
47170       ctx_fill (ctx);
47171 #endif
47172 
47173       ctx_rectangle (ctx, (vt->width) - vt->cw * 1.5,
47174                      0, 1.5 * vt->cw,
47175                      vt->rows * vt->ch);
47176       //ctx_listen (ctx, CTX_DRAG,  scrollbar_drag, vt, NULL);
47177       //ctx_listen (ctx, CTX_ENTER, scrollbar_enter, vt, NULL);
47178       //ctx_listen (ctx, CTX_LEAVE, scrollbar_leave, vt, NULL);
47179       if (vt->scroll != 0 || scrollbar_focused)
47180         ctx_rgba (ctx, 0.5, 0.5, 0.5, .25);
47181       else
47182         ctx_rgba (ctx, 0.5, 0.5, 0.5, .10);
47183       ctx_fill (ctx);
47184       ctx_round_rectangle (ctx, (vt->width) - vt->cw * 1.5,
47185                            offset * vt->rows * vt->ch, (1.5-0.2) * vt->cw,
47186                            win_len * vt->rows * vt->ch,
47187                            vt->cw * 1.5 /2);
47188       //ctx_listen (ctx, CTX_DRAG, scroll_handle_drag, vt, NULL);
47189       if (vt->scroll != 0 || scrollbar_focused)
47190         ctx_rgba (ctx, 1, 1, 1, .25);
47191       else
47192         ctx_rgba (ctx, 1, 1, 1, .10);
47193       ctx_fill (ctx);
47194     }
47195 
47196     ctx_rectangle (ctx, 0, 0, vt->cols * vt->cw, vt->rows * vt->ch);
47197     ctx_listen (ctx, CTX_DRAG,   vt_mouse_event, vt, NULL);
47198     ctx_listen (ctx, CTX_MOTION, vt_mouse_event, vt, NULL);
47199     ctx_begin_path (ctx);
47200 
47201     ctx_restore (ctx);
47202 
47203     if (vt->popped)
47204     {
47205        //ctx_set_popup (ctx, test_popup, vt);
47206     }
47207 }
47208 
47209 
47210 int vt_is_done (VT *vt)
47211 {
47212   return vt->vtpty.done;
47213 }
47214 
47215 int vt_get_result (VT *vt)
47216 {
47217   /* we could block - at least for a while, here..? */
47218   return vt->result;
47219 }
47220 
47221 void vt_set_scrollback_lines (VT *vt, int scrollback_lines)
47222 {
47223   vt->scrollback_limit = scrollback_lines;
47224 }
47225 
47226 int  vt_get_scrollback_lines (VT *vt)
47227 {
47228   return vt->scrollback_limit;
47229 }
47230 
47231 void vt_set_scroll (VT *vt, int scroll)
47232 {
47233   if (vt->scroll == scroll)
47234     return;
47235   vt->scroll = scroll;
47236   if (vt->scroll > ctx_list_length (vt->scrollback) )
47237     { vt->scroll = ctx_list_length (vt->scrollback); }
47238   if (vt->scroll < 0)
47239     { vt->scroll = 0; }
47240 }
47241 
47242 int vt_get_scroll (VT *vt)
47243 {
47244   return vt->scroll;
47245 }
47246 
47247 char *
47248 vt_get_selection (VT *vt)
47249 {
47250   CtxString *str = ctx_string_new ("");
47251   char *ret;
47252   for (int row = vt->select_start_row; row <= vt->select_end_row; row++)
47253     {
47254       const char *line_str = vt_get_line (vt, vt->rows - row);
47255       int col = 1;
47256       for (const char *c = line_str; *c; c = mrg_utf8_skip (c, 1), col ++)
47257         {
47258           if (row == vt->select_end_row && col > vt->select_end_col)
47259             { continue; }
47260           if (row == vt->select_start_row && col < vt->select_start_col)
47261             { continue; }
47262           ctx_string_append_utf8char (str, c);
47263         }
47264       if (row < vt->select_end_row && !vt_line_is_continuation (vt, vt->rows-row-1))
47265       {
47266         _ctx_string_append_byte (str, '\n');
47267       }
47268     }
47269   ret = str->str;
47270   ctx_string_free (str, 0);
47271   return ret;
47272 }
47273 
47274 int vt_get_local (VT *vt)
47275 {
47276   return vt->local_editing;
47277 }
47278 
47279 void vt_set_local (VT *vt, int local)
47280 {
47281   vt->local_editing = local;
47282 }
47283 
47284 static unsigned long prev_press_time = 0;
47285 static int short_count = 0;
47286 
47287 
47288 void terminal_set_primary (const char *text)
47289 {
47290   if (primary) free (primary);
47291   primary = NULL;
47292   if (text) primary = strdup (text);
47293 }
47294 
47295 void terminal_long_tap (Ctx *ctx, VT *vt);
47296 static int long_tap_cb_id = 0;
47297 static int single_tap (Ctx *ctx, void *data)
47298 {
47299 #if 0 // XXX
47300   VT *vt = data;
47301   if (short_count == 0 && !vt->select_active)
47302     terminal_long_tap (ctx, vt);
47303 #endif
47304   return 0;
47305 }
47306 
47307 void vt_mouse (VT *vt, CtxEvent *event, VtMouseEvent type, int button, int x, int y, int px_x, int px_y)
47308 {
47309  char buf[64]="";
47310  int button_state = 0;
47311  vt->rev++;
47312  ctx_ticks();
47313  if ((! (vt->mouse | vt->mouse_all | vt->mouse_drag)) ||
47314      (event && (event->state & CTX_MODIFIER_STATE_SHIFT)))
47315    {
47316      // regular mouse select, this is incomplete
47317      // fully ignorant of scrollback for now
47318      //
47319      if (type == VT_MOUSE_PRESS)
47320        {
47321          vt->cursor_down = 1;
47322          vt->select_begin_col = x;
47323          vt->select_begin_row = y - (int)vt->scroll;
47324          vt->select_start_col = x;
47325          vt->select_start_row = y - (int)vt->scroll;
47326          vt->select_end_col = x;
47327          vt->select_end_row = y - (int)vt->scroll;
47328          vt->select_active = 0;
47329          if (long_tap_cb_id)
47330            {
47331              ctx_remove_idle (vt->root_ctx, long_tap_cb_id);
47332              long_tap_cb_id = 0;
47333            }
47334 
47335          if ((ctx_ticks () - prev_press_time) < 1000*300 &&
47336              abs(px_x - vt->select_begin_x) +
47337              abs(px_y - vt->select_begin_y) < 8)
47338          {
47339            short_count++;
47340            switch (short_count)
47341            {
47342              case 1:
47343              {
47344                /* extend selection until space, XXX  should handle utf8 instead of ascii here!  */
47345 
47346                int hit_space = 0;
47347 
47348                while (vt->select_start_col > 1 && !hit_space)
47349                {
47350                  vt->select_start_col --;
47351                  char *sel = vt_get_selection (vt);
47352                  if (sel[0] == ' ' || sel[0] == '\0')
47353                    hit_space = 1;
47354                  free (sel);
47355                }
47356                if (hit_space)
47357                  vt->select_start_col++;
47358 
47359                hit_space = 0;
47360                while ((hit_space == 0) &&
47361                       (vt->select_end_col < vt->cols))
47362                {
47363                  vt->select_end_col ++;
47364                  char *sel = vt_get_selection (vt);
47365                  int len = strlen(sel);
47366                  if (sel[len-1]==' ')
47367                    hit_space = 1;
47368                  free (sel);
47369                }
47370                if (hit_space)
47371                  vt->select_end_col--;
47372 
47373                vt->select_active = 1;
47374 
47375                { char *sel = vt_get_selection (vt);
47376                  if (sel)
47377                  {
47378                     terminal_set_primary (sel);
47379                     free (sel);
47380                  }
47381                }
47382                }
47383                break;
47384              case 2:
47385                vt->select_start_col = 1;
47386                vt->select_end_col = vt->cols;
47387                vt->select_active = 1;
47388                {
47389                  char *sel = vt_get_selection (vt);
47390                  if (sel){
47391                     terminal_set_primary (sel);
47392                     free (sel);
47393                  }
47394                }
47395                break;
47396              case 3:
47397                short_count = 0;
47398                vt->select_start_col =
47399                vt->select_end_col = vt->select_begin_col;
47400                vt->select_active = 0;
47401                terminal_set_primary ("");
47402                break;
47403            }
47404          }
47405          else
47406          {
47407            if (vt->root_ctx && short_count == 0)
47408              long_tap_cb_id = ctx_add_timeout (vt->root_ctx, 1000, single_tap, vt);
47409            short_count = 0;
47410            //vt->select_start_col =
47411            //vt->select_end_col = vt->select_begin_col;
47412          }
47413          vt->select_begin_x = px_x;
47414          vt->select_begin_y = px_y;
47415          prev_press_time = ctx_ticks ();
47416          vt->rev++;
47417        }
47418      else if (type == VT_MOUSE_RELEASE)
47419        {
47420          if (long_tap_cb_id)
47421            {
47422              ctx_remove_idle (vt->root_ctx, long_tap_cb_id);
47423              long_tap_cb_id = 0;
47424            }
47425          vt->cursor_down = 0;
47426        }
47427      else if (type == VT_MOUSE_MOTION && vt->cursor_down)
47428        {
47429          int row = y - (int)vt->scroll;
47430          int col = x;
47431          if ((row > vt->select_begin_row) ||
47432              ((row == vt->select_begin_row) && (col >= vt->select_begin_col)))
47433          {
47434            vt->select_start_col = vt->select_begin_col;
47435            vt->select_start_row = vt->select_begin_row;
47436            vt->select_end_col = col;
47437            vt->select_end_row = row;
47438          }
47439          else
47440          {
47441            vt->select_start_col = col;
47442            vt->select_start_row = row;
47443            vt->select_end_col = vt->select_begin_col;
47444            vt->select_end_row = vt->select_begin_row;
47445          }
47446          if (vt->select_end_row == vt->select_start_row &&
47447              abs (vt->select_begin_x - px_x) < vt->cw/2)
47448          {
47449            vt->select_active = 0;
47450          }
47451          else
47452          {
47453            vt->select_active = 1;
47454            char *selection = vt_get_selection (vt);
47455            if (selection)
47456            {
47457              terminal_set_primary (selection);
47458              free (selection);
47459            }
47460          }
47461 
47462          if (y < 1)
47463          {
47464            vt->scroll += 1.0f;
47465            if (vt->scroll > vt->scrollback_count)
47466              vt->scroll = vt->scrollback_count;
47467          }
47468          else if (y > vt->rows)
47469          {
47470            vt->scroll -= 1.0f;
47471            if (vt->scroll < 0)
47472              vt->scroll = 0.0f;
47473          }
47474 
47475          vt->rev++;
47476        }
47477      return;
47478    }
47479  if (type == VT_MOUSE_MOTION)
47480    { button_state = 3; }
47481 
47482  if (vt->unit_pixels && vt->mouse_decimal)
47483    {
47484      x = px_x;
47485      y = px_y;
47486    }
47487  switch (type)
47488    {
47489      case VT_MOUSE_MOTION:
47490        if (!vt->mouse_all)
47491          return;
47492        if (x==vt->lastx && y==vt->lasty)
47493          return;
47494        vt->lastx = x;
47495        vt->lasty = y;
47496    //  sprintf (buf, "\033[<35;%i;%iM", x, y);
47497        break;
47498      case VT_MOUSE_RELEASE:
47499        if (vt->mouse_decimal == 0)
47500          button_state = 3;
47501        break;
47502      case VT_MOUSE_PRESS:
47503        button_state = 0;
47504        break;
47505      case VT_MOUSE_DRAG: // XXX not really used - remove
47506        if (! (vt->mouse_all || vt->mouse_drag) )
47507          return;
47508        button_state = 32;
47509        break;
47510    }
47511  // todo : mix in ctrl/meta state
47512  if (vt->mouse_decimal)
47513    {
47514      sprintf (buf, "\033[<%i;%i;%i%c", button_state, x, y, type == VT_MOUSE_RELEASE?'m':'M');
47515    }
47516  else
47517    {
47518      sprintf (buf, "\033[M%c%c%c", button_state + 32, x + 32, y + 32);
47519    }
47520  if (buf[0])
47521    {
47522      vt_write (vt, buf, strlen (buf) );
47523      fflush (NULL);
47524    }
47525 }
47526 
47527 pid_t vt_get_pid (VT *vt)
47528 {
47529   return vt->vtpty.pid;
47530 }
47531 
47532 void vt_set_ctx (VT *vt, Ctx *ctx)
47533 {
47534   vt->root_ctx = ctx;
47535 }
47536 #ifndef _DEFAULT_SOURCE
47537 #define _DEFAULT_SOURCE
47538 #endif
47539 
47540 #if !__COSMOPOLITAN__
47541 #include <unistd.h>
47542 #include <assert.h>
47543 #include <stdlib.h>
47544 #include <stdio.h>
47545 #include <stdint.h>
47546 #include <string.h>
47547 #include <sys/types.h>
47548 #include <sys/wait.h>
47549 #include <sys/ioctl.h>
47550 #include <signal.h>
47551 #include <math.h>
47552 #include <sys/time.h>
47553 #include <time.h>
47554 #endif
47555 
47556 #define VT_RECORD 0
47557 extern Ctx *ctx;
47558 #define flag_is_set(a, f) (((a) & (f))!=0)
47559 #define flag_set(a, f)    ((a) |= (f));
47560 #define flag_unset(a, f)  ((a) &= ~(f));
47561 
47562 //#define CTX_x            CTX_STRH('x',0,0,0,0,0,0,0,0,0,0,0,0,0)
47563 //#define CTX_y            CTX_STRH('y',0,0,0,0,0,0,0,0,0,0,0,0,0)
47564 #define CTX_lower_bottom CTX_STRH('l','o','w','e','r','-','b','o','t','t','o','m',0,0)
47565 #define CTX_lower        CTX_STRH('l','o','w','e','r',0,0,0,0,0,0,0,0,0)
47566 #define CTX_raise        CTX_STRH('r','a','i','s','e',0,0,0,0,0,0,0,0,0)
47567 #define CTX_raise_top    CTX_STRH('r','a','i','s','e','-','t','o','p',0,0,0,0,0)
47568 #define CTX_terminate    CTX_STRH('t','e','r','m','i','n','a','t','e',0,0,0,0,0)
47569 #define CTX_maximize     CTX_STRH('m','a','x','i','m','i','z','e',0,0,0,0,0,0)
47570 #define CTX_unmaximize   CTX_STRH('u','n','m','a','x','i','m','i','z','e',0,0,0,0)
47571 //#define CTX_width        CTX_STRH('w','i','d','t','h',0,0,0,0,0,0,0,0,0)
47572 //#define CTX_title        CTX_STRH('t','i','t','l','e',0,0,0,0,0,0,0,0,0)
47573 #define CTX_title        15643372
47574 #define CTX_action       CTX_STRH('a','c','t','i','o','n',0,0,0,0,0,0,0,0)
47575 //#define CTX_height       CTX_STRH('h','e','i','g','h','t',0,0,0,0,0,0,0,0)
47576 
47577 void terminal_update_title  (const char *title);
47578 int  ctx_renderer_is_sdl    (Ctx *ctx);
47579 int  ctx_renderer_is_fb     (Ctx *ctx);
47580 int  ctx_renderer_is_kms    (Ctx *ctx);
47581 int  ctx_renderer_is_tiled  (Ctx *ctx);
47582 int  ctx_renderer_is_term   (Ctx *ctx);
47583 void ctx_sdl_set_fullscreen (Ctx *ctx, int val);
47584 int  ctx_sdl_get_fullscreen (Ctx *ctx);
47585 float ctx_target_fps = 25.0;
47586 static int ctx_fetched_bytes = 1;
47587 
47588 CtxClient *vt_get_client (VT *vt);
47589 
47590 CtxList *vts = NULL;
47591 
47592 void ctx_clients_signal_child (int signum)
47593 {
47594   pid_t pid;
47595   int   status;
47596   if ( (pid = waitpid (-1, &status, WNOHANG) ) != -1)
47597     {
47598       if (pid)
47599         {
47600           for (CtxList *l = vts; l; l=l->next)
47601             {
47602               VtPty *vt = l->data;
47603               if (vt->pid == pid)
47604                 {
47605                   vt->done = 1;
47606                   //vt->result = status;
47607                 }
47608             }
47609         }
47610     }
47611 }
47612 
47613 
47614 
47615 int vt_set_prop (VT *vt, uint32_t key_hash, const char *val)
47616 {
47617 #if 1
47618   switch (key_hash)
47619   {
47620     case CTX_title:
47621      {
47622        CtxClient *client = vt_get_client (vt);
47623        if (client)
47624        {
47625          if (client->title) free (client->title);
47626          client->title = strdup (val);
47627        }
47628      }
47629 
47630      break;
47631   }
47632 #else
47633   float fval = strtod (val, NULL);
47634   CtxClient *client = ctx_client_by_id (ct->id);
47635   uint32_t val_hash = ctx_strhash (val);
47636   if (!client)
47637     return 0;
47638 
47639   if (key_hash == ctx_strhash("start_move"))
47640   {
47641     start_moving (client);
47642     moving_client = 1;
47643     return 0;
47644   }
47645 
47646 // set "pcm-hz"       "8000"
47647 // set "pcm-bits"     "8"
47648 // set "pcm-encoding" "ulaw"
47649 // set "play-pcm"     "d41ata312313"
47650 // set "play-pcm-ref" "foo.wav"
47651 
47652 // get "free"
47653 // storage of blobs for referencing when drawing or for playback
47654 // set "foo.wav"      "\3\1\1\4\"
47655 // set "fnord.png"    "PNG12.4a312"
47656 
47657   switch (key_hash)
47658   {
47659     case CTX_title:  ctx_client_set_title (ct->id, val); break;
47660     case CTX_x:      client->x = fval; break;
47661     case CTX_y:      client->y = fval; break;
47662     case CTX_width:  ctx_client_resize (ct->id, fval, client->height); break;
47663     case CTX_height: ctx_client_resize (ct->id, client->width, fval); break;
47664     case CTX_action:
47665       switch (val_hash)
47666       {
47667         case CTX_maximize:     ctx_client_maximize (client); break;
47668         case CTX_unmaximize:   ctx_client_unmaximize (client); break;
47669         case CTX_lower:        ctx_client_lower (client); break;
47670         case CTX_lower_bottom: ctx_client_lower_bottom (client);  break;
47671         case CTX_raise:        ctx_client_raise (client); break;
47672         case CTX_raise_top:    ctx_client_raise_top (client); break;
47673       }
47674       break;
47675   }
47676   ct->rev++;
47677 #endif
47678   return 0;
47679 }
47680 
47681 static float _ctx_font_size = 10.0;
47682 
47683 CtxList *clients = NULL;
47684 CtxClient *active = NULL;
47685 CtxClient *active_tab = NULL;
47686 
47687 static CtxClient *ctx_client_by_id (int id);
47688 
47689 int ctx_client_resize (int id, int width, int height);
47690 void ctx_client_maximize (int id);
47691 
47692 CtxClient *vt_get_client (VT *vt)
47693 {
47694   for (CtxList *l = clients; l; l =l->next)
47695   {
47696     CtxClient *client = l->data;
47697     if (client->vt == vt)
47698             return client;
47699   }
47700   return NULL;
47701 }
47702 
47703 CtxClient *ctx_client_new (Ctx *ctx,
47704                            const char *commandline,
47705                            int x, int y, int width, int height,
47706                            float font_size,
47707                            CtxClientFlags flags,
47708                            void *user_data,
47709                            CtxClientFinalize finalize)
47710 {
47711   static int global_id = 0;
47712   if (font_size <= 0.0) font_size = ctx_get_font_size (ctx);
47713   CtxClient *client = calloc (sizeof (CtxClient), 1);
47714   ctx_list_append (&clients, client);
47715   client->id = global_id++;
47716   client->x = x;
47717   client->y = y;
47718   client->flags = flags;
47719   client->ctx = ctx;
47720   client->width = width;
47721   client->height = height;
47722   client->user_data = user_data;
47723   client->finalize = finalize;
47724 
47725   if (ctx_renderer_is_term (ctx))
47726   {
47727     font_size = 3;
47728   }
47729 
47730       //fprintf (stderr, "client new:%f\n", font_size);
47731 #if CTX_THREADS
47732   mtx_init (&client->mtx, mtx_plain);
47733 #endif
47734   float line_spacing = 2.0f;
47735   client->vt = vt_new (commandline, width, height, font_size,line_spacing, client->id, (flags & ITK_CLIENT_CAN_LAUNCH)!=0);
47736   vt_set_ctx (client->vt, ctx);
47737   return client;
47738 }
47739 
47740 CtxClient *ctx_client_new_argv (Ctx *ctx, const char **argv, int x, int y, int width, int height, float font_size, CtxClientFlags flags, void *user_data, CtxClientFinalize finalize)
47741 {
47742   CtxString *string = ctx_string_new ("");
47743   for (int i = 0; argv[i]; i++)
47744   {
47745     char space = ' ';
47746     if (i > 0)
47747       ctx_string_append_data (string, &space, 1);
47748     for (int c = 0; argv[i][c]; c++)
47749     {
47750        switch (argv[i][c])
47751        {
47752          case '"':ctx_string_append_str (string, "\\\"");break;
47753          case '\'':ctx_string_append_str (string, "\\\'");break;
47754          default:ctx_string_append_data (string, &argv[i][c], 1);break;
47755        }
47756     }
47757   }
47758   CtxClient *ret = ctx_client_new (ctx, string->str, x, y, width, height, font_size, flags, user_data, finalize);
47759   ctx_string_free (string, 1);
47760   return ret;
47761 }
47762 
47763 extern float ctx_shape_cache_rate;
47764 extern int _ctx_max_threads;
47765 
47766 static int focus_follows_mouse = 0;
47767 
47768 static CtxClient *find_active (int x, int y)
47769 {
47770   CtxClient *ret = NULL;
47771   float titlebar_height = _ctx_font_size;
47772   int resize_border = titlebar_height/2;
47773 
47774   for (CtxList *l = clients; l; l = l->next)
47775   {
47776      CtxClient *c = l->data;
47777      if ((c->flags & ITK_CLIENT_MAXIMIZED) && c == active_tab)
47778      if (x > c->x - resize_border && x < c->x+c->width + resize_border &&
47779          y > c->y - titlebar_height && y < c->y+c->height + resize_border)
47780      {
47781        ret = c;
47782      }
47783   }
47784 
47785   for (CtxList *l = clients; l; l = l->next)
47786   {
47787      CtxClient *c = l->data;
47788      if (!(c->flags &  ITK_CLIENT_MAXIMIZED))
47789      if (x > c->x - resize_border && x < c->x+c->width + resize_border &&
47790          y > c->y - titlebar_height && y < c->y+c->height + resize_border)
47791      {
47792        ret = c;
47793      }
47794   }
47795   return ret;
47796 }
47797 
47798 int id_to_no (int id)
47799 {
47800   CtxList *l;
47801   int no = 0;
47802 
47803   for (l = clients; l; l = l->next)
47804   {
47805     CtxClient *client = l->data;
47806     if (client->id == id)
47807       return no;
47808     no++;
47809   }
47810   return -1;
47811 }
47812 
47813 void ctx_client_move (int id, int x, int y);
47814 int ctx_client_resize (int id, int w, int h);
47815 void ctx_client_shade_toggle (int id);
47816 float ctx_client_min_y_pos (Ctx *ctx);
47817 float ctx_client_max_y_pos (Ctx *ctx);
47818 
47819 #if 0
47820 void ensure_layout ()
47821 {
47822   int n_clients = ctx_list_length (clients);
47823   if (n_clients == 1)
47824   {
47825     CtxClient *client = clients->data;
47826     if (client->flags & ITK_CLIENT_MAXIMIZED)
47827     {
47828       ctx_client_move (client->id, 0, 0);
47829       ctx_client_resize (client->id, ctx_width (ctx), ctx_height(ctx));
47830       if (active_tab == NULL)
47831         active_tab = client;
47832     }
47833   }
47834   else
47835   for (CtxList *l = clients; l; l = l->next)
47836   {
47837     CtxClient *client = l->data;
47838     if (client->flags & ITK_CLIENT_MAXIMIZED)
47839     {
47840       ctx_client_move   (client->id, 0, client_min_y_pos (ctx));
47841       ctx_client_resize (client->id, ctx_width (ctx), ctx_height(ctx) -
47842                       ctx_client_min_y_pos (ctx) / 2);   // /2 to counter the double titlebar of non-maximized
47843       if (active_tab == NULL)
47844         active_tab = client;
47845     }
47846   }
47847 }
47848 #endif
47849 
47850 static CtxClient *ctx_client_by_id (int id)
47851 {
47852   for (CtxList *l = clients; l; l = l->next)
47853   {
47854     CtxClient *client = l->data;
47855     if (client->id == id)
47856       return client;
47857   }
47858   return NULL;
47859 }
47860 
47861 void ctx_client_remove (Ctx *ctx, CtxClient *client)
47862 {
47863   ctx_client_lock (client);
47864   if (!client->internal)
47865   {
47866 
47867     if (client->vt)
47868       vt_destroy (client->vt);
47869   }
47870 
47871   if (client->title)
47872     free (client->title);
47873 
47874 #if VT_RECORD
47875   if (client->recording)
47876     ctx_free (client->recording);
47877 #endif
47878   if (client->finalize)
47879      client->finalize (client, client->user_data);
47880 
47881   ctx_list_remove (&clients, client);
47882 
47883   if (client == active_tab)
47884   {
47885     active_tab = NULL;
47886   }
47887 
47888   if (ctx)
47889   if (client == active)
47890   {
47891     active = find_active (ctx_pointer_x (ctx), ctx_pointer_y (ctx));
47892     if (!active) active = clients?clients->data:NULL;
47893   }
47894 
47895   ctx_client_unlock (client);
47896   free (client);
47897   //ensure_layout();
47898 }
47899 
47900 #if 0
47901 void ctx_client_remove_by_id (int id)
47902 {
47903   int no = id_to_no (id);
47904   if (no>=0)
47905     ctx_client_remove (no);
47906 }
47907 #endif
47908 
47909 int ctx_client_height (int id)
47910 {
47911   CtxClient *client = ctx_client_by_id (id);
47912   if (!client) return 0;
47913   return client->height;
47914 }
47915 
47916 int ctx_client_x (int id)
47917 {
47918   CtxClient *client = ctx_client_by_id (id);
47919   if (!client) return 0;
47920   return client->x;
47921 }
47922 
47923 int ctx_client_y (int id)
47924 {
47925   CtxClient *client = ctx_client_by_id (id);
47926   if (!client) return 0;
47927   return client->y;
47928 }
47929 
47930 void ctx_client_raise_top (int id)
47931 {
47932   CtxClient *client = ctx_client_by_id (id);
47933   if (!client) return;
47934   ctx_list_remove (&clients, client);
47935   ctx_list_append (&clients, client);
47936 }
47937 
47938 void ctx_client_lower_bottom (int id)
47939 {
47940   CtxClient *client = ctx_client_by_id (id);
47941   if (!client) return;
47942   ctx_list_remove (&clients, client);
47943   ctx_list_prepend (&clients, client);
47944 }
47945 
47946 
47947 void ctx_client_iconify (int id)
47948 {
47949    CtxClient *client = ctx_client_by_id (id);
47950    if (!client) return;
47951    client->flags |= ITK_CLIENT_ICONIFIED;
47952 }
47953 
47954 int ctx_client_is_iconified (int id)
47955 {
47956    CtxClient *client = ctx_client_by_id (id);
47957    if (!client) return -1;
47958    return (client->flags & ITK_CLIENT_ICONIFIED) != 0;
47959 }
47960 
47961 void ctx_client_uniconify (int id)
47962 {
47963    CtxClient *client = ctx_client_by_id (id);
47964    if (!client) return;
47965    client->flags &= ~ITK_CLIENT_ICONIFIED;
47966 }
47967 
47968 void ctx_client_maximize (int id)
47969 {
47970    CtxClient *client = ctx_client_by_id (id);
47971    if (!client) return;
47972    if (client->flags &  ITK_CLIENT_MAXIMIZED)
47973      return;
47974    client->flags |= ITK_CLIENT_MAXIMIZED;
47975    client->unmaximized_x = client->x;
47976    client->unmaximized_y = client->y;
47977    client->unmaximized_width  = client->width;
47978    client->unmaximized_height = client->height;
47979 
47980    // enforce_layout does the size
47981    //client_resize (id, ctx_width (ctx), ctx_height(ctx) - ctx_client_min_y_pos (ctx));
47982 
47983    ctx_client_move (id, 0, ctx_client_min_y_pos (client->ctx));
47984    active_tab = client;
47985 }
47986 
47987 int ctx_client_is_maximized (int id)
47988 {
47989    CtxClient *client = ctx_client_by_id (id);
47990    if (!client) return -1;
47991    return (client->flags & ITK_CLIENT_MAXIMIZED) != 0;
47992 }
47993 
47994 void ctx_client_unmaximize (int id)
47995 {
47996    CtxClient *client = ctx_client_by_id (id);
47997    if (!client) return;
47998    if ((client->flags & ITK_CLIENT_MAXIMIZED) == 0)
47999      return;
48000    client->flags &= ~ITK_CLIENT_MAXIMIZED;
48001    ctx_client_resize (id, client->unmaximized_width, client->unmaximized_height);
48002    ctx_client_move (id, client->unmaximized_x, client->unmaximized_y);
48003    active_tab = NULL;
48004 }
48005 
48006 void ctx_client_maximized_toggle (int id)
48007 {
48008   if (ctx_client_is_maximized (id))
48009     ctx_client_unmaximize (id);
48010   else
48011     ctx_client_maximize (id);
48012 }
48013 
48014 
48015 void ctx_client_shade (int id)
48016 {
48017    CtxClient *client = ctx_client_by_id (id);
48018    if (!client) return;
48019    client->flags |= ITK_CLIENT_SHADED;
48020 }
48021 
48022 int ctx_client_is_shaded (int id)
48023 {
48024    CtxClient *client = ctx_client_by_id (id);
48025    if (!client) return -1;
48026    return (client->flags & ITK_CLIENT_SHADED) != 0;
48027 }
48028 
48029 void ctx_client_unshade (int id)
48030 {
48031    CtxClient *client = ctx_client_by_id (id);
48032    if (!client) return;
48033    client->flags &= ~ITK_CLIENT_SHADED;
48034 }
48035 
48036 void ctx_client_toggle_maximized (int id)
48037 {
48038    CtxClient *client = ctx_client_by_id (id);
48039    if (!client) return;
48040    if (ctx_client_is_maximized (id))
48041      ctx_client_unmaximize (id);
48042    else
48043      ctx_client_maximize (id);
48044 }
48045 
48046 void ctx_client_shade_toggle (int id)
48047 {
48048    CtxClient *client = ctx_client_by_id (id);
48049    if (!client) return;
48050    if (ctx_client_is_shaded (id))
48051     ctx_client_shade (id);
48052    else
48053     ctx_client_unshade (id);
48054 }
48055 
48056 void ctx_client_move (int id, int x, int y)
48057 {
48058    CtxClient *client = ctx_client_by_id (id);
48059    if (client && (client->x != x || client->y != y))
48060    {
48061      client->x = x;
48062      client->y = y;
48063      vt_rev_inc (client->vt);
48064    }
48065 }
48066 
48067 void ctx_client_set_font_size (int id, float font_size)
48068 {
48069    CtxClient *client = ctx_client_by_id (id);
48070    if (client->vt)
48071    {
48072      if (vt_get_font_size (client->vt) != font_size)
48073        vt_set_font_size (client->vt, font_size);
48074    }
48075 }
48076 float ctx_client_get_font_size (int id)
48077 {
48078    CtxClient *client = ctx_client_by_id (id);
48079    if (client->vt)
48080      return vt_get_font_size (client->vt);
48081    return 14.0;
48082 }
48083 
48084 int ctx_client_resize (int id, int width, int height)
48085 {
48086    CtxClient *client = ctx_client_by_id (id);
48087 
48088    if (client && ((height != client->height) || (width != client->width) ))
48089    {
48090      client->width  = width;
48091      client->height = height;
48092      if (client->vt)
48093        vt_set_px_size (client->vt, width, height);
48094      return 1;
48095    }
48096    return 0;
48097 }
48098 
48099 static void ctx_client_titlebar_drag (CtxEvent *event, void *data, void *data2)
48100 {
48101   CtxClient *client = data;
48102 
48103   if (event->type == CTX_DRAG_RELEASE)
48104   {
48105     static int prev_drag_end_time = 0;
48106     if (event->time - prev_drag_end_time < 500)
48107     {
48108       //client_shade_toggle (client->id);
48109       ctx_client_maximized_toggle (client->id);
48110     }
48111     prev_drag_end_time = event->time;
48112   }
48113 
48114   float new_x = client->x +  event->delta_x;
48115   float new_y = client->y +  event->delta_y;
48116 
48117   float snap_threshold = 8;
48118 
48119   if (ctx_renderer_is_term (event->ctx))
48120      snap_threshold = 1;
48121 
48122   if (new_y < ctx_client_min_y_pos (event->ctx)) new_y = ctx_client_min_y_pos (event->ctx);
48123   if (new_y > ctx_client_max_y_pos (event->ctx)) new_y = ctx_client_max_y_pos (event->ctx);
48124 
48125   if (fabs (new_x - 0) < snap_threshold) new_x = 0.0;
48126   if (fabs (ctx_width (event->ctx) - (new_x + client->width)) < snap_threshold) new_x = ctx_width (event->ctx) - client->width;
48127 
48128   ctx_client_move (client->id, new_x, new_y);
48129 
48130   //vt_rev_inc (client->vt);
48131   ctx_set_dirty (event->ctx, 1);
48132 
48133   event->stop_propagate = 1;
48134 }
48135 
48136 static float min_win_dim = 32;
48137 
48138 static void ctx_client_resize_se (CtxEvent *event, void *data, void *data2)
48139 {
48140   CtxClient *client = data;
48141   int new_w = client->width + event->delta_x;
48142   int new_h = client->height + event->delta_y;
48143   if (new_w <= min_win_dim) new_w = min_win_dim;
48144   if (new_h <= min_win_dim) new_h = min_win_dim;
48145   ctx_client_resize (client->id, new_w, new_h);
48146   if (client->vt) // force redraw
48147     vt_rev_inc (client->vt);
48148   ctx_set_dirty (event->ctx, 1);
48149   event->stop_propagate = 1;
48150 }
48151 
48152 static void ctx_client_resize_e (CtxEvent *event, void *data, void *data2)
48153 {
48154   CtxClient *client = data;
48155   int new_w = client->width + event->delta_x;
48156   if (new_w <= min_win_dim) new_w = min_win_dim;
48157   ctx_client_resize (client->id, new_w, client->height);
48158   if (client->vt) // force redraw
48159     vt_rev_inc (client->vt);
48160   ctx_set_dirty (event->ctx, 1);
48161   event->stop_propagate = 1;
48162 }
48163 
48164 static void ctx_client_resize_s (CtxEvent *event, void *data, void *data2)
48165 {
48166   CtxClient *client = data;
48167   int new_h = client->height + event->delta_y;
48168   if (new_h <= min_win_dim) new_h = min_win_dim;
48169   ctx_client_resize (client->id, client->width, new_h);
48170   if (client->vt) // force redraw
48171     vt_rev_inc (client->vt);
48172   ctx_set_dirty (event->ctx, 1);
48173   event->stop_propagate = 1;
48174 }
48175 
48176 static void ctx_client_resize_n (CtxEvent *event, void *data, void *data2)
48177 {
48178   CtxClient *client = data;
48179   float new_y = client->y +  event->delta_y;
48180   int new_h = client->height - event->delta_y;
48181   if (new_h <= min_win_dim) new_h = min_win_dim;
48182   ctx_client_resize (client->id, client->width, new_h);
48183   ctx_client_move (client->id, client->x, new_y);
48184   if (client->vt) // force redraw
48185     vt_rev_inc (client->vt);
48186   ctx_set_dirty (event->ctx, 1);
48187   event->stop_propagate = 1;
48188 }
48189 
48190 static void ctx_client_resize_ne (CtxEvent *event, void *data, void *data2)
48191 {
48192   CtxClient *client = data;
48193   float new_y = client->y +  event->delta_y;
48194   int new_h = client->height - event->delta_y;
48195   int new_w = client->width + event->delta_x;
48196   if (new_h <= min_win_dim) new_h = min_win_dim;
48197   if (new_w <= min_win_dim) new_w = min_win_dim;
48198   ctx_client_resize (client->id, new_w, new_h);
48199   ctx_client_move (client->id, client->x, new_y);
48200   if (client->vt) // force redraw
48201     vt_rev_inc (client->vt);
48202   ctx_set_dirty (event->ctx, 1);
48203   event->stop_propagate = 1;
48204 }
48205 
48206 static void ctx_client_resize_sw (CtxEvent *event, void *data, void *data2)
48207 {
48208   CtxClient *client = data;
48209 
48210   float new_x = client->x +  event->delta_x;
48211   int new_w = client->width - event->delta_x;
48212   int new_h = client->height + event->delta_y;
48213 
48214   if (new_h <= min_win_dim) new_h = min_win_dim;
48215   if (new_w <= min_win_dim) new_w = min_win_dim;
48216   ctx_client_resize (client->id, new_w, new_h);
48217   ctx_client_move (client->id, new_x, client->y);
48218   if (client->vt) // force redraw
48219     vt_rev_inc (client->vt);
48220   ctx_set_dirty (event->ctx, 1);
48221   event->stop_propagate = 1;
48222 }
48223 
48224 static void ctx_client_resize_nw (CtxEvent *event, void *data, void *data2)
48225 {
48226   CtxClient *client = data;
48227   float new_x = client->x +  event->delta_x;
48228   float new_y = client->y +  event->delta_y;
48229   int new_w = client->width - event->delta_x;
48230   int new_h = client->height - event->delta_y;
48231   if (new_h <= min_win_dim) new_h = min_win_dim;
48232   if (new_w <= min_win_dim) new_w = min_win_dim;
48233   ctx_client_resize (client->id, new_w, new_h);
48234   ctx_client_move (client->id, new_x, new_y);
48235   if (client->vt) // force redraw
48236     vt_rev_inc (client->vt);
48237   ctx_set_dirty (event->ctx, 1);
48238   event->stop_propagate = 1;
48239 }
48240 
48241 static void ctx_client_resize_w (CtxEvent *event, void *data, void *data2)
48242 {
48243   CtxClient *client = data;
48244 
48245   float new_x = client->x +  event->delta_x;
48246   int new_w = client->width - event->delta_x;
48247   if (new_w <= min_win_dim) new_w = min_win_dim;
48248   ctx_client_resize (client->id, new_w, client->height);
48249   ctx_client_move (client->id, new_x, client->y);
48250   if (client->vt) // force redraw
48251     vt_rev_inc (client->vt);
48252   ctx_set_dirty (event->ctx, 1);
48253 
48254   event->stop_propagate = 1;
48255 }
48256 
48257 static void ctx_client_close (CtxEvent *event, void *data, void *data2)
48258 {
48259   //Ctx *ctx = event->ctx;
48260   CtxClient *client = data;
48261 
48262  // client->do_quit = 1;
48263 
48264   ctx_client_remove (event->ctx, client);
48265 
48266   ctx_set_dirty (event->ctx, 1);
48267   event->stop_propagate = 1;
48268 }
48269 
48270 /********************/
48271 void vt_use_images (VT *vt, Ctx *ctx);
48272 float _ctx_green = 0.5;
48273 
48274 static void ctx_client_draw (Ctx *ctx, CtxClient *client, float x, float y)
48275 {
48276     if (client->internal)
48277     {
48278 #if 0
48279       ctx_save (ctx);
48280 
48281       ctx_translate (ctx, x, y);
48282       int width = client->width;
48283       int height = client->height;
48284 
48285       itk_panel_start (itk, "", 0, 0, width, height);
48286       //itk_seperator (itk);
48287 #if 0
48288       if (itk_button (itk, "add tab"))
48289       {
48290         add_tab (vt_find_shell_command(), 1);
48291       }
48292 #endif
48293       //itk_sameline (itk);
48294       //itk_toggle (itk, "on screen keyboard", &on_screen_keyboard);
48295       //itk_toggle (itk, "focus follows mouse", &focus_follows_mouse);
48296       itk_slider_float (itk, "CTX_GREEN", &_ctx_green, 0.0, 1.0, 0.5);
48297       itk_ctx_settings (itk);
48298       itk_itk_settings (itk);
48299 
48300       itk_panel_end (itk);
48301       itk_done (itk);
48302       //itk_key_bindings (itk);
48303 
48304       ctx_restore (ctx);
48305 #endif
48306     }
48307     else
48308     {
48309        ctx_client_lock (client);
48310 
48311           int found = 0;
48312           for (CtxList *l2 = clients; l2; l2 = l2->next)
48313             if (l2->data == client) found = 1;
48314           if (found)
48315           {
48316 
48317       int rev = vt_rev (client->vt);
48318 #if VT_RECORD
48319       if (client->drawn_rev != rev)
48320       {
48321         if (!client->recording)
48322           client->recording = ctx_new ();
48323         else
48324           ctx_reset (client->recording);
48325         vt_draw (client->vt, client->recording, 0.0, 0.0);
48326       }
48327 
48328       if (client->recording)
48329       {
48330         ctx_save (ctx);
48331         ctx_translate (ctx, x, y);
48332         ctx_render_ctx (client->recording, ctx);
48333         vt_register_events (client->vt, ctx, 0.0, 0.0);
48334         ctx_restore (ctx);
48335       }
48336 #else
48337 
48338       vt_draw (client->vt, ctx, x, y);
48339       vt_register_events (client->vt, ctx, x, y);
48340 #endif
48341       client->drawn_rev = rev;
48342       ctx_client_unlock (client);
48343           }
48344     }
48345 }
48346 
48347 static void ctx_client_use_images (Ctx *ctx, CtxClient *client)
48348 {
48349   if (!client->internal)
48350   {
48351       uint32_t rev = vt_rev (client->vt);
48352 #if VT_RECORD
48353       if (client->drawn_rev != rev)
48354       {
48355         if (!client->recording)
48356           client->recording = ctx_new ();
48357         else
48358           ctx_reset (client->recording);
48359         vt_draw (client->vt, client->recording, 0.0, 0.0);
48360       }
48361 
48362       if (client->recording)
48363       {
48364         ctx_save (ctx);
48365         ctx_render_ctx_textures (client->recording, ctx);
48366         ctx_restore (ctx);
48367       }
48368 #else
48369     vt_use_images (client->vt, ctx);
48370 #endif
48371     client->drawn_rev = rev;
48372   }
48373 }
48374 
48375 void ctx_client_lock (CtxClient *client)
48376 {
48377 #if CTX_THREADS
48378     mtx_lock (&client->mtx);
48379 #endif
48380 }
48381 
48382 void ctx_client_unlock (CtxClient *client)
48383 {
48384 #if CTX_THREADS
48385     mtx_unlock (&client->mtx);
48386 #endif
48387 }
48388 
48389 #if 0
48390 void ctx_client_handle_event (Ctx *ctx, CtxEvent *ctx_event, const char *event)
48391 {
48392   if (!active)
48393     return;
48394   if (active->internal)
48395     return;
48396   VT *vt = active->vt;
48397   CtxClient *client = vt_get_client (vt);
48398 
48399   ctx_client_lock (client);
48400 
48401   if (!strcmp (event, "F11"))
48402   {
48403 #if CTX_SDL
48404     if (ctx_renderer_is_sdl (ctx))
48405     {
48406       ctx_sdl_set_fullscreen (ctx, !ctx_sdl_get_fullscreen (ctx));
48407     }
48408 #endif
48409   }
48410   else if (!strcmp (event, "shift-return"))
48411   {
48412     vt_feed_keystring (vt, ctx_event, "return");
48413   }
48414   else if (!strcmp (event, "shift-control-v") )
48415     {
48416       char *text = ctx_get_clipboard (ctx);
48417       if (text)
48418         {
48419           if (vt)
48420             vt_paste (vt, text);
48421           free (text);
48422         }
48423     }
48424   else if (!strcmp (event, "shift-control-c") && vt)
48425     {
48426       char *text = vt_get_selection (vt);
48427       if (text)
48428         {
48429           ctx_set_clipboard (ctx, text);
48430           free (text);
48431         }
48432     }
48433   else if (!strcmp (event, "shift-control-t") ||
48434            ((ctx_renderer_is_fb (ctx) || ctx_renderer_is_term (ctx) || ctx_renderer_is_kms (ctx))
48435            &&   !strcmp (event, "control-t") ))
48436   {
48437     //XXX add_tab (vt_find_shell_command(), 1);
48438   }
48439   else if (!strcmp (event, "shift-control-n") )
48440     {
48441       pid_t pid;
48442       if ( (pid=fork() ) ==0)
48443         {
48444           unsetenv ("CTX_VERSION");
48445          // execlp (execute_self, execute_self, NULL);
48446           exit (0);
48447         }
48448     }
48449 
48450 #if 0
48451   else if (!strcmp (event, "alt-1"))   switch_to_tab(0);
48452   else if (!strcmp (event, "alt-2"))   switch_to_tab(1);
48453   else if (!strcmp (event, "alt-3"))   switch_to_tab(2);
48454   else if (!strcmp (event, "alt-4"))   switch_to_tab(3);
48455   else if (!strcmp (event, "alt-5"))   switch_to_tab(4);
48456   else if (!strcmp (event, "alt-6"))   switch_to_tab(5);
48457   else if (!strcmp (event, "alt-7"))   switch_to_tab(6);
48458   else if (!strcmp (event, "alt-8"))   switch_to_tab(7);
48459   else if (!strcmp (event, "alt-9"))   switch_to_tab(8);
48460   else if (!strcmp (event, "alt-0"))   switch_to_tab(9);
48461 #endif
48462   else if (!strcmp (event, "shift-control-q") )
48463     {
48464       ctx_quit (ctx);
48465     }
48466   else if (!strcmp (event, "shift-control-w") )
48467     {
48468       active->do_quit = 1;
48469     }
48470   else if (!strcmp (event, "shift-control-s") )
48471     {
48472       if (vt)
48473       {
48474         char *sel = vt_get_selection (vt);
48475         if (sel)
48476         {
48477           vt_feed_keystring (vt, ctx_event, sel);
48478           free (sel);
48479         }
48480       }
48481     }
48482   else
48483     {
48484       if (vt)
48485         vt_feed_keystring (vt, ctx_event, event);
48486     }
48487   ctx_client_unlock (client);
48488 }
48489 #endif
48490 
48491 static int ctx_clients_dirty_count (void)
48492 {
48493   int changes = 0;
48494   for (CtxList *l = clients; l; l = l->next)
48495   {
48496     CtxClient *client = l->data;
48497     if ((client->drawn_rev != vt_rev (client->vt) ) ||
48498         vt_has_blink (client->vt))
48499       changes++;
48500   }
48501   return changes;
48502 }
48503 
48504 static void ctx_client_titlebar_drag_maximized (CtxEvent *event, void *data, void *data2)
48505 {
48506   CtxClient *client = data;
48507 
48508   active = active_tab = client;
48509   if (event->type == CTX_DRAG_RELEASE)
48510   {
48511     static int prev_drag_end_time = 0;
48512     if (event->time - prev_drag_end_time < 500)
48513     {
48514       //client_shade_toggle (client->id);
48515       ctx_client_unmaximize (client->id);
48516       ctx_client_raise_top (client->id);
48517       active_tab = NULL;
48518     }
48519     prev_drag_end_time = event->time;
48520   }
48521   ctx_set_dirty (event->ctx, 1);
48522   vt_rev_inc (client->vt);
48523   event->stop_propagate = 1;
48524 }
48525 
48526 float ctx_client_min_y_pos (Ctx *ctx)
48527 {
48528   return _ctx_font_size * 2; // a titlebar and a panel
48529 }
48530 
48531 float ctx_client_max_y_pos (Ctx *ctx)
48532 {
48533   return ctx_height (ctx);
48534 }
48535 
48536 void ctx_client_titlebar_draw (Ctx *ctx, CtxClient *client,
48537                                float x, float y, float width, float titlebar_height)
48538 {
48539 #if 0
48540   ctx_move_to (ctx, x, y + height * 0.8);
48541   if (client == active)
48542     ctx_rgba (ctx, 1, 1,0.4, 1.0);
48543   else
48544     ctx_rgba (ctx, 1, 1,1, 0.8);
48545   ctx_text (ctx, client->title);
48546 #else
48547   ctx_rectangle (ctx, x, y - titlebar_height,
48548                  width, titlebar_height);
48549   if (client == active)
48550      itk_style_color (ctx, "titlebar-focused-bg");
48551   else
48552      itk_style_color (ctx, "titlebar-bg");
48553 
48554   if (flag_is_set(client->flags, ITK_CLIENT_MAXIMIZED) || y == titlebar_height)
48555   {
48556     ctx_listen (ctx, CTX_DRAG, ctx_client_titlebar_drag_maximized, client, NULL);
48557     ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_ALL);
48558   }
48559   else
48560   {
48561     ctx_listen (ctx, CTX_DRAG, ctx_client_titlebar_drag, client, NULL);
48562     ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_ALL);
48563   }
48564   ctx_fill (ctx);
48565   //ctx_font_size (ctx, itk->font_size);//titlebar_height);// * 0.85);
48566 
48567   if (client == active &&
48568       (flag_is_set(client->flags, ITK_CLIENT_MAXIMIZED) || y != titlebar_height))
48569 #if 1
48570   ctx_rectangle (ctx, x + width - titlebar_height,
48571                   y - titlebar_height, titlebar_height,
48572                   titlebar_height);
48573 #endif
48574   ctx_rgb (ctx, 1, 0,0);
48575   ctx_listen (ctx, CTX_PRESS, ctx_client_close, client, NULL);
48576   ctx_listen_set_cursor (ctx, CTX_CURSOR_ARROW);
48577   //ctx_fill (ctx);
48578   ctx_begin_path (ctx);
48579   ctx_move_to (ctx, x + width - titlebar_height * 0.8, y - titlebar_height * 0.22);
48580   if (client == active)
48581     itk_style_color (ctx, "titlebar-focused-close");
48582   else
48583     itk_style_color (ctx, "titlebar-close");
48584   ctx_text (ctx, "X");
48585 
48586   ctx_move_to (ctx, x +  width/2, y - titlebar_height * 0.22);
48587   if (client == active)
48588     itk_style_color (ctx, "titlebar-focused-fg");
48589   else
48590     itk_style_color (ctx, "titlebar-fg");
48591 
48592   ctx_save (ctx);
48593   ctx_text_align (ctx, CTX_TEXT_ALIGN_CENTER);
48594   if (client->title)
48595     ctx_text (ctx, client->title);
48596   else
48597     ctx_text (ctx, "untitled");
48598   ctx_restore (ctx);
48599 #endif
48600 }
48601 
48602 #if 0
48603 static void key_down (CtxEvent *event, void *data1, void *data2)
48604 {
48605   fprintf (stderr, "down %i %s\n", event->unicode, event->string);
48606 }
48607 static void key_up (CtxEvent *event, void *data1, void *data2)
48608 {
48609   fprintf (stderr, "up %i %s\n", event->unicode, event->string);
48610 }
48611 static void key_press (CtxEvent *event, void *data1, void *data2)
48612 {
48613   fprintf (stderr, "press %i %s\n", event->unicode, event->string);
48614 }
48615 #endif
48616 
48617 int ctx_clients_draw (Ctx *ctx, int layer2)
48618 {
48619   _ctx_font_size = ctx_get_font_size (ctx);
48620   float titlebar_height = _ctx_font_size;
48621   int n_clients         = ctx_list_length (clients);
48622 
48623   if (active && flag_is_set(active->flags, ITK_CLIENT_MAXIMIZED) && n_clients == 1)
48624   {
48625     ctx_client_draw (ctx, active, 0, 0);
48626     return 0;
48627   }
48628 
48629   for (CtxList *l = clients; l; l = l->next)
48630   {
48631     CtxClient *client = l->data;
48632     if (flag_is_set(client->flags, ITK_CLIENT_MAXIMIZED))
48633     {
48634       if (client == active_tab)
48635       {
48636         ctx_client_draw (ctx, client, 0, titlebar_height);
48637       }
48638       else
48639       {
48640         ctx_client_use_images (ctx, client);
48641       }
48642     }
48643   }
48644 
48645   {
48646   for (CtxList *l = clients; l; l = l->next)
48647   {
48648     CtxClient *client = l->data;
48649     VT *vt = client->vt;
48650 
48651     if (layer2)
48652     {
48653       if (!flag_is_set (client->flags, ITK_CLIENT_LAYER2))
48654         continue;
48655     }
48656     else
48657     {
48658       if (flag_is_set (client->flags, ITK_CLIENT_LAYER2))
48659         continue;
48660     }
48661 
48662     if (vt && !flag_is_set(client->flags, ITK_CLIENT_MAXIMIZED))
48663     {
48664       if (flag_is_set(client->flags, ITK_CLIENT_SHADED))
48665       {
48666         ctx_client_use_images (ctx, client);
48667       }
48668       else
48669       {
48670         ctx_client_draw (ctx, client, client->x, client->y);
48671 
48672       // resize regions
48673       if (client == active &&
48674          !flag_is_set(client->flags, ITK_CLIENT_SHADED) &&
48675          !flag_is_set(client->flags, ITK_CLIENT_MAXIMIZED) &&
48676          flag_is_set(client->flags, ITK_CLIENT_UI_RESIZABLE))
48677       {
48678         itk_style_color (ctx, "titlebar-focused-bg");
48679 
48680         ctx_rectangle (ctx,
48681                        client->x,
48682                        client->y - titlebar_height * 2,
48683                        client->width, titlebar_height);
48684         ctx_listen (ctx, CTX_DRAG, ctx_client_resize_n, client, NULL);
48685         ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_N);
48686         ctx_begin_path (ctx);
48687 
48688         ctx_rectangle (ctx,
48689                        client->x,
48690                        client->y + client->height - titlebar_height,
48691                        client->width, titlebar_height * 2);
48692         ctx_listen (ctx, CTX_DRAG, ctx_client_resize_s, client, NULL);
48693         ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_S);
48694         ctx_begin_path (ctx);
48695 
48696         ctx_rectangle (ctx,
48697                        client->x + client->width,
48698                        client->y - titlebar_height,
48699                        titlebar_height, client->height + titlebar_height);
48700         ctx_listen (ctx, CTX_DRAG, ctx_client_resize_e, client, NULL);
48701         ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_E);
48702         ctx_begin_path (ctx);
48703 
48704         ctx_rectangle (ctx,
48705                        client->x - titlebar_height,
48706                        client->y - titlebar_height,
48707                        titlebar_height, client->height + titlebar_height);
48708         ctx_listen (ctx, CTX_DRAG, ctx_client_resize_w, client, NULL);
48709         ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_W);
48710         ctx_begin_path (ctx);
48711 
48712         ctx_rectangle (ctx,
48713                        client->x + client->width - titlebar_height,
48714                        client->y - titlebar_height * 2,
48715                        titlebar_height * 2, titlebar_height * 2);
48716         ctx_listen (ctx, CTX_DRAG, ctx_client_resize_ne, client, NULL);
48717         ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_NE);
48718         ctx_begin_path (ctx);
48719 
48720         ctx_rectangle (ctx,
48721                        client->x - titlebar_height,
48722                        client->y - titlebar_height * 2,
48723                        titlebar_height * 2, titlebar_height * 2);
48724         ctx_listen (ctx, CTX_DRAG, ctx_client_resize_nw, client, NULL);
48725         ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_NW);
48726         ctx_begin_path (ctx);
48727 
48728         ctx_rectangle (ctx,
48729                        client->x - titlebar_height,
48730                        client->y + client->height - titlebar_height,
48731                        titlebar_height * 2, titlebar_height * 2);
48732         ctx_listen (ctx, CTX_DRAG, ctx_client_resize_sw, client, NULL);
48733         ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_SW);
48734         ctx_begin_path (ctx);
48735 
48736         ctx_rectangle (ctx,
48737                        client->x + client->width - titlebar_height,
48738                        client->y + client->height - titlebar_height,
48739                        titlebar_height * 2, titlebar_height * 2);
48740         ctx_listen (ctx, CTX_DRAG, ctx_client_resize_se, client, NULL);
48741         ctx_listen_set_cursor (ctx, CTX_CURSOR_RESIZE_SE);
48742         ctx_begin_path (ctx);
48743 
48744       }
48745 
48746       }
48747 
48748       if (client->flags & ITK_CLIENT_TITLEBAR)
48749         ctx_client_titlebar_draw (ctx, client, client->x, client->y, client->width, titlebar_height);
48750     }
48751   }
48752   }
48753   return 0;
48754 }
48755 
48756 extern int _ctx_enable_hash_cache;
48757 
48758 void vt_audio_task (VT *vt, int click);
48759 
48760 int ctx_input_pending (Ctx *ctx, int timeout);
48761 
48762 int ctx_clients_need_redraw (Ctx *ctx)
48763 {
48764   int changes = 0;
48765   int follow_mouse = focus_follows_mouse;
48766       CtxList *to_remove = NULL;
48767   //ensure_layout ();
48768 
48769 //  if (print_shape_cache_rate)
48770 //    fprintf (stderr, "\r%f ", ctx_shape_cache_rate);
48771 
48772    CtxClient *client = find_active (ctx_pointer_x (ctx),
48773                                     ctx_pointer_y (ctx));
48774 
48775    if (follow_mouse || ctx_pointer_is_down (ctx, 0) ||
48776        ctx_pointer_is_down (ctx, 1) || (active==NULL))
48777    {
48778         if (client)
48779         {
48780           if (active != client)
48781           {
48782             active = client;
48783             if (follow_mouse == 0 ||
48784                 (ctx_pointer_is_down (ctx, 0) ||
48785                  ctx_pointer_is_down (ctx, 1)))
48786             {
48787               //if (client != clients->data)
48788        #if 1
48789               if ((client->flags & ITK_CLIENT_MAXIMIZED)==0)
48790               {
48791                 ctx_list_remove (&clients, client);
48792                 ctx_list_append (&clients, client);
48793               }
48794 #endif
48795             }
48796             changes ++;
48797           }
48798         }
48799    }
48800 
48801    for (CtxList *l = clients; l; l = l->next)
48802    {
48803      CtxClient *client = l->data;
48804      if (client->vt)
48805        {
48806          if (vt_is_done (client->vt))
48807          {
48808            if ((client->flags & ITK_CLIENT_KEEP_ALIVE))
48809            {
48810              client->flags |= ITK_CLIENT_FINISHED;
48811            }
48812            else
48813            {
48814              ctx_list_prepend (&to_remove, client);
48815            }
48816          }
48817        }
48818    }
48819    while (to_remove)
48820    {
48821      changes++;
48822      ctx_client_remove (ctx, to_remove->data);
48823      ctx_list_remove (&to_remove, to_remove->data);
48824    }
48825 
48826    changes += ctx_clients_dirty_count ();
48827    return changes != 0;
48828 }
48829 
48830 float ctx_avg_bytespeed = 0.0;
48831 
48832 static void ctx_client_handle_events_iteration (Ctx *ctx)
48833 {
48834   static int fail_safe = 0;
48835   //int n_clients = ctx_list_length (clients);
48836       int pending_data = 0;
48837       long time_start = ctx_ticks ();
48838       int sleep_time = 1000000/ctx_target_fps;
48839 
48840       pending_data = ctx_input_pending (ctx, sleep_time);
48841 
48842       ctx_fetched_bytes = 0;
48843       if (pending_data || fail_safe>100)
48844       {
48845         if (!pending_data)pending_data = 1;
48846         /* record amount of time spent - and adjust time of reading for
48847          * vts?
48848          */
48849         long int fractional_sleep = sleep_time / pending_data;
48850         for (CtxList *l = clients; l; l = l->next)
48851         {
48852           CtxClient *client = l->data;
48853           ctx_client_lock (client);
48854           int found = 0;
48855           for (CtxList *l2 = clients; l2; l2 = l2->next)
48856             if (l2->data == client) found = 1;
48857           if (!found)
48858             goto done;
48859 
48860           ctx_fetched_bytes += vt_poll (client->vt, fractional_sleep);
48861           //ctx_fetched_bytes += vt_poll (client->vt, sleep_time); //fractional_sleep);
48862           ctx_client_unlock (client);
48863         }
48864 done:
48865         fail_safe = 0;
48866       }
48867       else
48868       {
48869         fail_safe ++;
48870         for (CtxList *l = clients; l; l = l->next)
48871         {
48872           CtxClient *client = l->data;
48873           vt_audio_task (client->vt, 0);
48874         }
48875       }
48876 
48877       //int got_events = 0;
48878 
48879       //while (ctx_get_event (ctx)) { }
48880 #if 0
48881       if (changes /*|| pending_data */)
48882       {
48883         ctx_target_fps *= 1.6;
48884         if (ctx_target_fps > 60) ctx_target_fps = 60;
48885       }
48886       else
48887       {
48888         ctx_target_fps = ctx_target_fps * 0.95 + 30.0 * 0.05;
48889 
48890         // 20fps is the lowest where sun 8bit ulaw 8khz works reliably
48891       }
48892 
48893       if (ctx_avg_bytespeed > 1024 * 1024) ctx_target_fps = 10.0;
48894 
48895       if (_ctx_green < 0.4)
48896         ctx_target_fps = 120.0;
48897       else if (_ctx_green > 0.6)
48898         ctx_target_fps = 25.0;
48899 
48900       //ctx_target_fps = 30.0;
48901 #else
48902       ctx_target_fps = 30.0;
48903 #endif
48904 
48905       long time_end = ctx_ticks ();
48906 
48907       int timed = (time_end-time_start);
48908       float bytespeed = ctx_fetched_bytes / ((timed)/ (1000.0f * 1000.0f));
48909 
48910       ctx_avg_bytespeed = bytespeed * 0.2 + ctx_avg_bytespeed * 0.8;
48911 #if 0
48912       fprintf (stderr, "%.2fmb/s %i/%i  %.2f                    \r", ctx_avg_bytespeed/1024/1024, ctx_fetched_bytes, timed, ctx_target_fps);
48913 #endif
48914 }
48915 
48916 
48917 static int ctx_clients_handle_events_fun (void *data)
48918 {
48919   Ctx *ctx = data;
48920   while (!ctx->quit)
48921   {
48922     int n_clients = ctx_list_length (clients);
48923     ctx_client_handle_events_iteration (data);
48924     switch (n_clients)
48925     {
48926       case 0:
48927         usleep (1000 * 10);
48928         break;
48929       case 1:
48930         usleep (1); // letting quit work - and also makes framerate for dump
48931         break;
48932       default:
48933         usleep (0); // the switching between clients should be enough
48934         break;
48935     }
48936   }
48937   return 0;
48938 }
48939 
48940 void ctx_clients_handle_events (Ctx *ctx)
48941 {
48942 #if 1 //#if CTX_THREADS==0
48943     ctx_client_handle_events_iteration (ctx);
48944 #else
48945     static thrd_t tid = 0;
48946     if (tid == 0)
48947     {
48948       thrd_create (&tid, (void*)ctx_clients_handle_events_fun, ctx);
48949     }
48950 #endif
48951 }
48952 
48953 #endif /* CTX_VT */
48954 #endif //  __CTX_H__
48955