diff --git a/src/configure.ml b/src/configure.ml index eb2f2698..f188c8b9 100644 --- a/src/configure.ml +++ b/src/configure.ml @@ -24,11 +24,16 @@ let () = (foreign_stubs (language c) (names config util unicode point rect list hashtable event - gdi_keyboard gdi_backend gdi_target gdi_window gdi_context - qtz_keyboard qtz_backend qtz_target qtz_window qtz_context - x11_keysym x11_keyboard x11_backend x11_target x11_window x11_context - wl_backend wl_target wl_window wl_context - window pixmap image_interpolation filters context transform draw_instr + gdi_keyboard gdi_backend gdi_target gdi_window + gdi_sw_context gdi_hw_context + qtz_keyboard qtz_backend qtz_target qtz_window + qtz_sw_context qtz_hw_context + x11_keysym x11_keyboard x11_backend x11_target x11_window + x11_sw_context x11_hw_context + wl_backend wl_target wl_window + wl_sw_context wl_hw_context + window pixmap image_interpolation filters transform draw_instr + sw_context hw_context context font_desc gdi_font qtz_font unx_font font gdi_impexp qtz_impexp unx_impexp impexp path arc path2d polygon polygonize diff --git a/src/dune.inc b/src/dune.inc index 52bfefba..927d083b 100644 --- a/src/dune.inc +++ b/src/dune.inc @@ -9,11 +9,16 @@ (foreign_stubs (language c) (names config util unicode point rect list hashtable event - gdi_keyboard gdi_backend gdi_target gdi_window gdi_context - qtz_keyboard qtz_backend qtz_target qtz_window qtz_context - x11_keysym x11_keyboard x11_backend x11_target x11_window x11_context - wl_backend wl_target wl_window wl_context - window pixmap image_interpolation filters context transform draw_instr + gdi_keyboard gdi_backend gdi_target gdi_window + gdi_sw_context gdi_hw_context + qtz_keyboard qtz_backend qtz_target qtz_window + qtz_sw_context qtz_hw_context + x11_keysym x11_keyboard x11_backend x11_target x11_window + x11_sw_context x11_hw_context + wl_backend wl_target wl_window + wl_sw_context wl_hw_context + window pixmap image_interpolation filters transform draw_instr + sw_context hw_context context font_desc gdi_font qtz_font unx_font font gdi_impexp qtz_impexp unx_impexp impexp path arc path2d polygon polygonize diff --git a/src/implem/config.c b/src/implem/config.c index 0fcbd89d..adc347e2 100644 --- a/src/implem/config.c +++ b/src/implem/config.c @@ -8,17 +8,18 @@ /* */ /**************************************************************************/ +#include #include #include "config.h" -static impl_type_t impl_type = IMPL_NONE; +static impl_type_t +_impl_type = IMPL_NONE; void set_impl_type( impl_type_t it) { - assert(it != IMPL_CANVAS); #ifndef HAS_GDI assert(it != IMPL_GDI); #endif @@ -31,17 +32,26 @@ set_impl_type( #ifndef HAS_WAYLAND assert(it != IMPL_WAYLAND); #endif - impl_type = it; + _impl_type = it; } impl_type_t -get_impl_type() +get_impl_type( + void) { - return impl_type; + return _impl_type; +} + +bool +has_hardware_accel( + void) +{ + return false; } os_type_t -get_os_type() +get_os_type( + void) { #if defined(_WIN32) || defined(_WIN64) return OS_WIN32; diff --git a/src/implem/config.h b/src/implem/config.h index aa0e80cb..06100200 100644 --- a/src/implem/config.h +++ b/src/implem/config.h @@ -23,11 +23,10 @@ typedef enum os_type_t { typedef enum impl_type_t { IMPL_NONE = 0, - IMPL_CANVAS = 1, - IMPL_GDI = 2, - IMPL_QUARTZ = 3, - IMPL_X11 = 4, - IMPL_WAYLAND = 5 + IMPL_GDI = 1, + IMPL_QUARTZ = 2, + IMPL_X11 = 3, + IMPL_WAYLAND = 4 } impl_type_t; #define switch_IMPL() switch (get_impl_type()) @@ -59,9 +58,30 @@ typedef enum impl_type_t { #define default_fail() default: assert(!"Missing implementation"); break #define default_ignore() default: break -void set_impl_type(impl_type_t it); -impl_type_t get_impl_type(); +#ifdef HAS_ACCEL +#define switch_ACCEL() switch (has_hardware_accel()) +#define case_HW(s) case true: { s; } break +#define case_SW(s) case false: { s; } break +#else +#define switch_ACCEL() +#define case_HW(s) +#define case_SW(s) s +#endif + +void +set_impl_type( + impl_type_t it); + +impl_type_t +get_impl_type( + void); + +bool +has_hardware_accel( + void); -os_type_t get_os_type(); +os_type_t +get_os_type( + void); #endif /* __CONFIG_H */ diff --git a/src/implem/context.c b/src/implem/context.c index c7373414..6a50e7dd 100644 --- a/src/implem/context.c +++ b/src/implem/context.c @@ -17,31 +17,19 @@ #include "target.h" #include "pixmap.h" #include "color.h" -#include "context.h" -#include "context_internal.h" -#include "list.h" #include "rect.h" #include "polygon.h" -#include "state.h" // for shadow_t #include "transform.h" #include "draw_style.h" -#include "draw_instr.h" -#include "poly_render.h" -#include "impexp.h" +#include "list.h" +#include "state.h" // for shadow_t -#ifdef HAS_GDI -#include "gdi/gdi_context.h" -#endif -#ifdef HAS_QUARTZ -#include "quartz/qtz_context.h" -#endif -#ifdef HAS_X11 -#include "x11/x11_context.h" -#endif -#ifdef HAS_WAYLAND -#include "wayland/wl_context.h" +#ifdef HAS_ACCEL +#include "hw_context.h" #endif +#include "sw_context.h" +#include "context_internal.h" context_t * context_create( @@ -51,25 +39,10 @@ context_create( assert(width > 0); assert(height > 0); - color_t_ *data = (color_t_ *)calloc(width * height, sizeof(color_t_)); - if (data == NULL) { - return NULL; + switch_ACCEL() { + case_HW(return (context_t *)hw_context_create(width, height)); + case_SW(return (context_t *)sw_context_create(width, height)); } - - context_t *c = (context_t *)calloc(1, sizeof(context_t)); - if (c == NULL) { - free(data); - return NULL; - } - - c->offscreen = true; - c->data = data; - c->width = width; - c->height = height; - - c->clip_region = pixmap_null(); - - return c; } context_t * @@ -79,23 +52,10 @@ context_create_from_pixmap( assert(pixmap != NULL); assert(pixmap_valid(*pixmap) == true); - context_t *c = (context_t *)calloc(1, sizeof(context_t)); - if (c == NULL) { - return NULL; + switch_ACCEL() { + case_HW(return (context_t *)hw_context_create_from_pixmap(pixmap)); + case_SW(return (context_t *)sw_context_create_from_pixmap(pixmap)); } - - c->offscreen = true; - c->data = pixmap->data; - c->width = pixmap->width; - c->height = pixmap->height; - - c->clip_region = pixmap_null(); - - pixmap->data = NULL; - pixmap->width = 0; - pixmap->height = 0; - - return c; } context_t * @@ -108,26 +68,12 @@ context_create_onscreen( assert(width > 0); assert(height > 0); - context_t *c = NULL; - switch_IMPL() { - case_GDI(c = (context_t *)gdi_context_create((gdi_target_t *)target, - width, height)); - case_QUARTZ(c = (context_t *)qtz_context_create((qtz_target_t *)target, - width, height)); - case_X11(c = (context_t *)x11_context_create((x11_target_t *)target, - width, height)); - case_WAYLAND(c = (context_t *)wl_context_create((wl_target_t *)target, - width, height)); - default_fail(); + switch_ACCEL() { + case_HW( + return (context_t *)hw_context_create_onscreen(target, width, height)); + case_SW( + return (context_t *)sw_context_create_onscreen(target, width, height)); } - if (c == NULL) { - return NULL; - } - c->offscreen = false; - - c->clip_region = pixmap_null(); - - return c; } void @@ -135,47 +81,12 @@ context_destroy( context_t *c) { assert(c != NULL); - assert(c->data != NULL); - - if (pixmap_valid(c->clip_region) == true) { - pixmap_destroy(c->clip_region); - } - - if (c->offscreen == true) { - free(c->data); - free(c); - } else { - switch_IMPL() { - case_GDI(gdi_context_destroy((gdi_context_t *)c)); - case_QUARTZ(qtz_context_destroy((qtz_context_t *)c)); - case_X11(x11_context_destroy((x11_context_t *)c)); - case_WAYLAND(wl_context_destroy((wl_context_t *)c)); - default_fail(); - } - } -} - -void -_context_copy_to_buffer( - context_t *c, - color_t_ *data, - int32_t width, - int32_t height) -{ - assert(c != NULL); - assert(c->data != NULL); assert(c->width > 0); assert(c->height > 0); - assert(data != NULL); - assert(width > 0); - assert(height > 0); - uint32_t min_width = width < c->width ? width : c->width; - uint32_t min_height = height < c->height ? height : c->height; - for (size_t i = 0; i < min_height; ++i) { - for (size_t j = 0; j < min_width; ++j) { - data[i * width + j] = c->data[i * c->width + j]; - } + switch_ACCEL() { + case_HW(hw_context_destroy((hw_context_t *)c)); + case_SW(sw_context_destroy((sw_context_t *)c)); } } @@ -186,58 +97,12 @@ context_resize( int32_t height) { assert(c != NULL); - assert(c->data != NULL); assert(c->width > 0); assert(c->height > 0); - if ((width <= 0) || (height <= 0)) { - return false; - } - - if ((width == c->width) && (height == c->height)) { - return true; - } - - if (pixmap_valid(c->clip_region)) { - pixmap_destroy(c->clip_region); - } - -// TODO: fill extra data with background color - - if (c->offscreen == true) { - - color_t_ *data = (color_t_ *)calloc(width * height, sizeof(color_t_)); - if (data == NULL) { - return false; - } - - _context_copy_to_buffer(c, data, width, height); - - free(c->data); - - c->data = data; - c->width = width; - c->height = height; - - return true; - - } else { - - bool result = false; - - switch_IMPL() { - case_GDI(result = - gdi_context_resize((gdi_context_t *)c, width, height)); - case_QUARTZ(result = - qtz_context_resize((qtz_context_t *)c, width, height)); - case_X11(result = - x11_context_resize((x11_context_t *)c, width, height)); - case_WAYLAND(result = - wl_context_resize((wl_context_t *)c, width, height)); - default_fail(); - } - - return result; + switch_ACCEL() { + case_HW(return hw_context_resize((hw_context_t *)c, width, height)); + case_SW(return sw_context_resize((sw_context_t *)c, width, height)); } } @@ -247,61 +112,15 @@ context_present( { assert(c != NULL); assert(c->offscreen == false); - assert(c->data != NULL); assert(c->width > 0); assert(c->height > 0); - switch_IMPL() { - case_GDI(gdi_context_present((gdi_context_t *)c)); - case_QUARTZ(qtz_context_present((qtz_context_t *)c)); - case_X11(x11_context_present((x11_context_t *)c)); - case_WAYLAND(wl_context_present((wl_context_t *)c)); - default_fail(); + switch_ACCEL() { + case_HW(hw_context_present((hw_context_t *)c)); + case_SW(sw_context_present((sw_context_t *)c)); } } -// Direct access to the context pixels -// Do NOT free the data pointer ! -static pixmap_t -_context_get_raw_pixmap( - context_t *c) -{ - assert(c != NULL); - assert(c->data != NULL); - assert(c->width > 0); - assert(c->height > 0); - - return pixmap(c->width, c->height, c->data); -} - - - -static void -_context_clip_fill_instr( - context_t *c, - const path_fill_instr_t *instr, - const transform_t *transform) -{ - assert(c != NULL); - assert(pixmap_valid(c->clip_region) == true); - assert(instr != NULL); - assert(instr->poly != NULL); - assert(transform != NULL); - - draw_style_t white = (draw_style_t){ .type = DRAW_STYLE_COLOR, - .content.color = color_white }; - shadow_t noshadow = (shadow_t){ - .offset_x = 0, .offset_y = 0, .blur = 0, - .color = color_transparent_black }; - -// TODO: could store bounding box with polygon - rect_t bbox = rect(point(0.0, 0.0), - point((double)c->width, (double)c->height)); - - poly_render(&(c->clip_region), instr->poly, &bbox, white, 1.0, &noshadow, - ONE_MINUS_SRC, NULL, instr->non_zero, transform); -} - bool context_clip( context_t *c, @@ -312,34 +131,10 @@ context_clip( assert(clip_path != NULL); assert(transform != NULL); - if ((pixmap_valid(c->clip_region) == true) && - ((c->clip_region.width != c->width) || - (c->clip_region.height != c->height))) { - pixmap_destroy(c->clip_region); - } - - if (pixmap_valid(c->clip_region) == false) { - c->clip_region = pixmap(c->width, c->height, NULL); - if (pixmap_valid(c->clip_region) == false) { - return false; - } - } - - pixmap_clear(c->clip_region); - - list_iterator_t *it = list_get_iterator(clip_path); - if (it == NULL) { - return false; - } - - path_fill_instr_t *instr = NULL; - while ((instr = (path_fill_instr_t *)list_iterator_next(it)) != NULL) { - _context_clip_fill_instr(c, instr, transform); + switch_ACCEL() { + case_HW(return hw_context_clip((hw_context_t *)c, clip_path, transform)); + case_SW(return sw_context_clip((sw_context_t *)c, clip_path, transform)); } - - list_free_iterator(it); - - return true; } void @@ -348,13 +143,12 @@ context_clear_clip( { assert(c != NULL); - if (pixmap_valid(c->clip_region) == true) { - pixmap_destroy(c->clip_region); + switch_ACCEL() { + case_HW(hw_context_clear_clip((hw_context_t *)c)); + case_SW(sw_context_clear_clip((sw_context_t *)c)); } } - - void context_render_polygon( context_t *c, @@ -367,12 +161,21 @@ context_render_polygon( bool non_zero, const transform_t *transform) { - pixmap_t pm = pixmap(c->width, c->height, c->data); - poly_render(&pm, p, bbox, draw_style, global_alpha, shadow, compose_op, - &(c->clip_region), non_zero, transform); -} - + assert(c != NULL); + assert(p != NULL); + assert(bbox != NULL); + assert(shadow != NULL); + assert(transform != NULL); + switch_ACCEL() { + case_HW(hw_context_render_polygon((hw_context_t *)c, p, bbox, + draw_style, global_alpha, shadow, + compose_op, non_zero, transform)); + case_SW(sw_context_render_polygon((sw_context_t *)c, p, bbox, + draw_style, global_alpha, shadow, + compose_op, non_zero, transform)); + } +} void context_blit( @@ -384,7 +187,6 @@ context_blit( int32_t sy, int32_t width, int32_t height, - double global_alpha, const shadow_t *shadow, composite_operation_t compose_op, @@ -392,96 +194,19 @@ context_blit( { assert(dc != NULL); assert(sc != NULL); + assert(shadow != NULL); + assert(transform != NULL); - bool draw_shadows = - (shadow->blur > 0.0 || - shadow->offset_x != 0.0 || shadow->offset_y != 0.0) && - compose_op != COPY && shadow->color.a != 0; - - const pixmap_t sp = _context_get_raw_pixmap((context_t *)sc); - pixmap_t dp = _context_get_raw_pixmap(dc); - -// TODO: global_alpha ? - if ((transform_is_pure_translation(transform) == true) && - (draw_shadows == false)) { - - double tx = 0.0, ty = 0.0; - transform_extract_translation(transform, &tx, &ty); - - int32_t lo_x = max(dx + (int32_t)tx, 0); - int32_t hi_x = min(dx + (int32_t)tx + width, dc->width); // canvas wd - int32_t lo_y = max(dy + (int32_t)ty, 0); - int32_t hi_y = min(dy + (int32_t)ty + height, dc->height); //canvas ht - - for (int32_t i = lo_x; i < hi_x; i++) { - for (int32_t j = lo_y; j < hi_y; j++) { - - int32_t uvx = i + sx - dx - (int32_t)tx; - int32_t uvy = j + sy - dy - (int32_t)ty; - if (uvx < 0 || uvx >= sc->width || // canvas wd - uvy < 0 || uvy >= sc->height) { // canvas ht - continue; - } - - color_t_ fill_color = pixmap_at(sp, uvy, uvx); - int draw_alpha = fill_color.a; - if (pixmap_valid(dc->clip_region) == true) { - draw_alpha *= 255 - pixmap_at(dc->clip_region, j, i).a; - draw_alpha /= 255; - } - - pixmap_at(dp, j, i) = - comp_compose(fill_color, pixmap_at(dp, j, i), - draw_alpha, compose_op); - } - } - - } else { - - draw_style_t draw_style = - (draw_style_t){ .type = DRAW_STYLE_PIXMAP, .content.pixmap = &sp }; - - polygon_t *p = polygon_create(8, 1); - if (p == NULL) { - return; - } - - point_t p1 = point((double)dx, (double)dy); - point_t p2 = point((double)(dx + width), (double)dy); - point_t p3 = point((double)(dx + width), (double)(dy + height)); - point_t p4 = point((double)dx, (double)(dy + height)); - - transform_apply(transform, &p1); - transform_apply(transform, &p2); - transform_apply(transform, &p3); - transform_apply(transform, &p4); - - polygon_add_point(p, p1); - polygon_add_point(p, p2); - polygon_add_point(p, p3); - polygon_add_point(p, p4); - polygon_end_subpoly(p, true); - - rect_t bbox = rect(point(min4(p1.x, p2.x, p3.x, p4.x), - min4(p1.y, p2.y, p3.y, p4.y)), - point(max4(p1.x, p2.x, p3.x, p4.x), - max4(p1.y, p2.y, p3.y, p4.y))); - - transform_t *temp_transform = transform_copy(transform); - transform_translate(temp_transform, dx - sx, dy - sy); - - pixmap_t pm = _context_get_raw_pixmap(dc); - poly_render(&pm, p, &bbox, draw_style, global_alpha, shadow, compose_op, - &(dc->clip_region), false, temp_transform); - - transform_destroy(temp_transform); - - polygon_destroy(p); + switch_ACCEL() { + case_HW(hw_context_blit((hw_context_t *)dc, dx, dy, + (hw_context_t *)sc, sx, sy, width, height, + global_alpha, shadow, compose_op, transform)); + case_SW(sw_context_blit((sw_context_t *)dc, dx, dy, + (sw_context_t *)sc, sx, sy, width, height, + global_alpha, shadow, compose_op, transform)); } } - - color_t_ context_get_pixel( const context_t *c, @@ -490,16 +215,10 @@ context_get_pixel( { assert(c != NULL); - color_t_ color = color_black; - - const pixmap_t pm = _context_get_raw_pixmap((context_t *)c); - if (pixmap_valid(pm) == true) { - if ((x >= 0) && (x < pm.width) && (y >= 0) && (y < pm.height)) { - color = pixmap_at(pm, y, x); - } + switch_ACCEL() { + case_HW(return hw_context_get_pixel((hw_context_t *)c, x, y)); + case_SW(return sw_context_get_pixel((sw_context_t *)c, x, y)); } - - return color; } void @@ -511,11 +230,9 @@ context_put_pixel( { assert(c != NULL); - pixmap_t pm = _context_get_raw_pixmap((context_t *)c); - if (pixmap_valid(pm) == true) { - if ((x >= 0) && (x < pm.width) && (y >= 0) && (y < pm.height)) { - pixmap_at(pm, y, x) = color; - } + switch_ACCEL() { + case_HW(hw_context_put_pixel((hw_context_t *)c, x, y, color)); + case_SW(sw_context_put_pixel((sw_context_t *)c, x, y, color)); } } @@ -527,17 +244,14 @@ context_get_pixmap( int32_t width, int32_t height) { - assert(context != NULL); - - pixmap_t dp = pixmap_null(); - const pixmap_t sp = _context_get_raw_pixmap((context_t *)c); - if (pixmap_valid(sp) == true) { - dp = pixmap(width, height, NULL); - if (pixmap_valid(dp) == true) { - pixmap_blit(&dp, 0, 0, &sp, sx, sy, width, height); - } + assert(c != NULL); + + switch_ACCEL() { + case_HW(return hw_context_get_pixmap((hw_context_t *)c, + sx, sy, width, height)); + case_SW(return sw_context_get_pixmap((sw_context_t *)c, + sx, sy, width, height)); } - return dp; } void @@ -555,9 +269,11 @@ context_put_pixmap( assert(sp != NULL); assert(pixmap_valid(*sp) == true); - pixmap_t dp = _context_get_raw_pixmap(c); - if (pixmap_valid(dp) == true) { - pixmap_blit(&dp, dx, dy, sp, sx, sy, width, height); + switch_ACCEL() { + case_HW(hw_context_put_pixmap((hw_context_t *)c, dx, dy, + sp, sx, sy, width, height)); + case_SW(sw_context_put_pixmap((sw_context_t *)c, dx, dy, + sp, sx, sy, width, height)); } } @@ -569,11 +285,10 @@ context_export_png( assert(c != NULL); assert(filename != NULL); - const pixmap_t pm = _context_get_raw_pixmap((context_t *)c); - if (pixmap_valid(pm) == false) { - return false; + switch_ACCEL() { + case_HW(return hw_context_export_png((hw_context_t *)c, filename)); + case_SW(return sw_context_export_png((sw_context_t *)c, filename)); } - return impexp_export_png(&pm, filename); } bool @@ -586,9 +301,8 @@ context_import_png( assert(c != NULL); assert(filename != NULL); - pixmap_t pm = _context_get_raw_pixmap(c); - if (pixmap_valid(pm) == false) { - return false; + switch_ACCEL() { + case_HW(return hw_context_import_png((hw_context_t *)c, x, y, filename)); + case_SW(return sw_context_import_png((sw_context_t *)c, x, y, filename)); } - return impexp_import_png(&pm, x, y, filename); } diff --git a/src/implem/context.h b/src/implem/context.h index cc79c524..875bd975 100644 --- a/src/implem/context.h +++ b/src/implem/context.h @@ -17,12 +17,12 @@ #include "target.h" #include "pixmap.h" -//#include "list.h" -//#include "rect.h" +#include "rect.h" #include "polygon.h" -#include "state.h" #include "transform.h" #include "draw_style.h" +#include "list.h" +#include "state.h" // for shadow_t typedef struct context_t context_t; @@ -59,8 +59,6 @@ void context_present( context_t *c); - - bool context_clip( context_t *c, @@ -83,8 +81,6 @@ context_render_polygon( bool non_zero, const transform_t *transform); - - void context_blit( context_t *dc, @@ -95,14 +91,11 @@ context_blit( int32_t sy, int32_t width, int32_t height, - double global_alpha, const shadow_t *shadow, composite_operation_t compose_op, const transform_t *transform); - - color_t_ context_get_pixel( const context_t *c, diff --git a/src/implem/context_internal.h b/src/implem/context_internal.h index 0ed2c80c..dd7b7119 100644 --- a/src/implem/context_internal.h +++ b/src/implem/context_internal.h @@ -14,23 +14,10 @@ #include #include -#include "color.h" -#include "pixmap.h" - typedef struct context_t { bool offscreen; - color_t_ *data; int32_t width; int32_t height; - - pixmap_t clip_region; // temporary } context_t; -void -_context_copy_to_buffer( - context_t *c, - color_t_ *data, - int32_t width, - int32_t height); - #endif /* __CONTEXT_INTERNAL_H */ diff --git a/src/implem/gdi/gdi_hw_context.c b/src/implem/gdi/gdi_hw_context.c new file mode 100644 index 00000000..de5d6fcc --- /dev/null +++ b/src/implem/gdi/gdi_hw_context.c @@ -0,0 +1,95 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef HAS_GDI + +#include +#include +#include +#include +#include + +#include + +#include "../config.h" +#include "../color.h" +#include "../context_internal.h" +#include "../hw_context_internal.h" +#include "gdi_target.h" + +typedef struct gdi_hw_context_t { + hw_context_t base; +} gdi_hw_context_t; + +gdi_hw_context_t * +gdi_hw_context_create( + gdi_target_t *target, + int32_t width, + int32_t height) +{ + assert(target != NULL); + assert(target->hwnd != NULL); + assert(width > 0); + assert(height > 0); + + gdi_hw_context_t *context = + (gdi_hw_context_t *)calloc(1, sizeof(gdi_hw_context_t)); + if (context == NULL) { + return NULL; + } + + context->base.base.width = width; + context->base.base.height = height; + + return context; +} + +void +gdi_hw_context_destroy( + gdi_hw_context_t *context) +{ + assert(context != NULL); + + free(context); +} + +bool +gdi_hw_context_resize( + gdi_hw_context_t *context, + int32_t width, + int32_t height) +{ + assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); + assert(width > 0); + assert(height > 0); + + context->base.base.width = width; + context->base.base.height = height; + + return true; +} + +void +gdi_hw_context_present( + gdi_hw_context_t *context) +{ + assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); + +} + +#else + +const int gdi_hw_context = 0; + +#endif /* HAS_GDI */ diff --git a/src/implem/gdi/gdi_context.h b/src/implem/gdi/gdi_hw_context.h similarity index 72% rename from src/implem/gdi/gdi_context.h rename to src/implem/gdi/gdi_hw_context.h index 6bf4da6e..c1c3b42e 100644 --- a/src/implem/gdi/gdi_context.h +++ b/src/implem/gdi/gdi_hw_context.h @@ -8,35 +8,34 @@ /* */ /**************************************************************************/ -#ifndef __GDI_CONTEXT_H -#define __GDI_CONTEXT_H +#ifndef __GDI_HW_CONTEXT_H +#define __GDI_HW_CONTEXT_H #include #include -#include "../color.h" #include "gdi_target.h" -typedef struct gdi_context_t gdi_context_t; +typedef struct gdi_hw_context_t gdi_hw_context_t; -gdi_context_t * -gdi_context_create( +gdi_hw_context_t * +gdi_hw_context_create( gdi_target_t *target, int32_t width, int32_t height); void -gdi_context_destroy( - gdi_context_t *context); +gdi_hw_context_destroy( + gdi_hw_context_t *context); bool -gdi_context_resize( - gdi_context_t *context, +gdi_hw_context_resize( + gdi_hw_context_t *context, int32_t width, int32_t height); void -gdi_context_present( - gdi_context_t *context); +gdi_hw_context_present( + gdi_hw_context_t *context); -#endif /* __GDI_CONTEXT_H */ +#endif /* __GDI_HW_CONTEXT_H */ diff --git a/src/implem/gdi/gdi_context.c b/src/implem/gdi/gdi_sw_context.c similarity index 77% rename from src/implem/gdi/gdi_context.c rename to src/implem/gdi/gdi_sw_context.c index edbe4e1e..a4e67353 100644 --- a/src/implem/gdi/gdi_context.c +++ b/src/implem/gdi/gdi_sw_context.c @@ -21,17 +21,18 @@ #include "../config.h" #include "../color.h" #include "../context_internal.h" +#include "../sw_context_internal.h" #include "gdi_target.h" -typedef struct gdi_context_t { - context_t base; +typedef struct gdi_sw_context_t { + sw_context_t base; HBITMAP bmp; HDC hdc; HWND hwnd; -} gdi_context_t; +} gdi_sw_context_t; static HBITMAP -_context_create_gdi_bitmap( +_gdi_sw_context_create_bitmap( HDC hdc, int32_t width, int32_t height, @@ -72,8 +73,8 @@ _context_create_gdi_bitmap( return bmp; } -gdi_context_t * -gdi_context_create( +gdi_sw_context_t * +gdi_sw_context_create( gdi_target_t *target, int32_t width, int32_t height) @@ -83,8 +84,8 @@ gdi_context_create( assert(width > 0); assert(height > 0); - gdi_context_t *context = - (gdi_context_t *)calloc(1, sizeof(gdi_context_t)); + gdi_sw_context_t *context = + (gdi_sw_context_t *)calloc(1, sizeof(gdi_sw_context_t)); if (context == NULL) { return NULL; } @@ -103,7 +104,7 @@ gdi_context_create( } color_t_ *data = NULL; - HBITMAP bmp = _context_create_gdi_bitmap(hdc, width, height, &data); + HBITMAP bmp = _gdi_sw_context_create_bitmap(hdc, width, height, &data); if (bmp == NULL) { assert(data == NULL); DeleteDC(hdc); @@ -112,9 +113,9 @@ gdi_context_create( } assert(data != NULL); + context->base.base.width = width; + context->base.base.height = height; context->base.data = data; - context->base.width = width; - context->base.height = height; context->bmp = bmp; context->hdc = hdc; context->hwnd = target->hwnd; @@ -123,8 +124,8 @@ gdi_context_create( } void -gdi_context_destroy( - gdi_context_t *context) +gdi_sw_context_destroy( + gdi_sw_context_t *context) { assert(context != NULL); @@ -140,15 +141,15 @@ gdi_context_destroy( } bool -gdi_context_resize( - gdi_context_t *context, +gdi_sw_context_resize( + gdi_sw_context_t *context, int32_t width, int32_t height) { assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); assert(context->base.data != NULL); - assert(context->base.width > 0); - assert(context->base.height > 0); assert(context->bmp != NULL); assert(context->hdc != NULL); assert(width > 0); @@ -156,38 +157,40 @@ gdi_context_resize( color_t_ *data = NULL; HBITMAP bmp = - _context_create_gdi_bitmap(context->hdc, width, height, &data); + _gdi_sw_context_create_bitmap(context->hdc, width, height, &data); if (bmp == NULL) { assert(data == NULL); return false; } assert(data != NULL); - _context_copy_to_buffer(&context->base, data, width, height); + _sw_context_copy_to_buffer(&context->base, data, width, height); DeleteObject(context->bmp); + context->base.base.width = width; + context->base.base.height = height; context->base.data = data; - context->base.width = width; - context->base.height = height; context->bmp = bmp; return true; } void -gdi_context_present( - gdi_context_t *context) +gdi_sw_context_present( + gdi_sw_context_t *context) { assert(context != NULL); - assert(context->base.width > 0); - assert(context->base.height > 0); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); assert(context->bmp != NULL); assert(context->hdc != NULL); assert(context->hwnd != NULL); HDC hdc = GetDC(context->hwnd); - BitBlt(hdc, 0, 0, context->base.width, context->base.height, + BitBlt(hdc, 0, 0, + context->base.base.width, + context->base.base.height, context->hdc, 0, 0, SRCCOPY); ReleaseDC(context->hwnd, hdc); GdiFlush(); @@ -196,6 +199,6 @@ gdi_context_present( #else -const int gdi_context = 0; +const int gdi_sw_context = 0; #endif /* HAS_GDI */ diff --git a/src/implem/gdi/gdi_sw_context.h b/src/implem/gdi/gdi_sw_context.h new file mode 100644 index 00000000..a20358ba --- /dev/null +++ b/src/implem/gdi/gdi_sw_context.h @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __GDI_SW_CONTEXT_H +#define __GDI_SW_CONTEXT_H + +#include +#include + +#include "gdi_target.h" + +typedef struct gdi_sw_context_t gdi_sw_context_t; + +gdi_sw_context_t * +gdi_sw_context_create( + gdi_target_t *target, + int32_t width, + int32_t height); + +void +gdi_sw_context_destroy( + gdi_sw_context_t *context); + +bool +gdi_sw_context_resize( + gdi_sw_context_t *context, + int32_t width, + int32_t height); + +void +gdi_sw_context_present( + gdi_sw_context_t *context); + +#endif /* __GDI_SW_CONTEXT_H */ diff --git a/src/implem/hw_context.c b/src/implem/hw_context.c new file mode 100644 index 00000000..8fbb8e49 --- /dev/null +++ b/src/implem/hw_context.c @@ -0,0 +1,389 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef HAS_ACCEL + +#include +#include +#include +#include + +#include "config.h" +#include "target.h" +#include "pixmap.h" +#include "color.h" + +#include "rect.h" +#include "polygon.h" +#include "transform.h" +#include "draw_style.h" +#include "list.h" +#include "state.h" // for shadow_t + +#include "draw_instr.h" +#include "poly_render.h" +#include "impexp.h" + +#ifdef HAS_GDI +#include "gdi/gdi_hw_context.h" +#endif +#ifdef HAS_QUARTZ +#include "quartz/qtz_hw_context.h" +#endif +#ifdef HAS_X11 +#include "x11/x11_hw_context.h" +#endif +#ifdef HAS_WAYLAND +#include "wayland/wl_hw_context.h" +#endif + +#include "context_internal.h" +#include "hw_context_internal.h" + +hw_context_t * +hw_context_create( + int32_t width, + int32_t height) +{ + assert(width > 0); + assert(height > 0); + + hw_context_t *c = (hw_context_t *)calloc(1, sizeof(hw_context_t)); + if (c == NULL) { + return NULL; + } + + c->base.offscreen = true; + c->base.width = width; + c->base.height = height; + + return c; +} + +hw_context_t * +hw_context_create_from_pixmap( + pixmap_t *pixmap) +{ + assert(pixmap != NULL); + assert(pixmap_valid(*pixmap) == true); + + hw_context_t *c = (hw_context_t *)calloc(1, sizeof(hw_context_t)); + if (c == NULL) { + return NULL; + } + + c->base.offscreen = true; + c->base.width = pixmap->width; + c->base.height = pixmap->height; + + free(pixmap->data); + pixmap->data = NULL; + pixmap->width = 0; + pixmap->height = 0; + + return c; +} + +hw_context_t * +hw_context_create_onscreen( + target_t *target, + int32_t width, + int32_t height) +{ + assert(target != NULL); + assert(width > 0); + assert(height > 0); + + hw_context_t *c = NULL; + switch_IMPL() { + case_GDI( + c = (hw_context_t *)gdi_hw_context_create((gdi_target_t *)target, + width, height)); + case_QUARTZ( + c = (hw_context_t *)qtz_hw_context_create((qtz_target_t *)target, + width, height)); + case_X11( + c = (hw_context_t *)x11_hw_context_create((x11_target_t *)target, + width, height)); + case_WAYLAND( + c = (hw_context_t *)wl_hw_context_create((wl_target_t *)target, + width, height)); + default_fail(); + } + if (c == NULL) { + return NULL; + } + + c->base.offscreen = false; + + return c; +} + +void +hw_context_destroy( + hw_context_t *c) +{ + assert(c != NULL); + assert(c->data != NULL); + + if (c->base.offscreen == true) { + free(c); + } else { + switch_IMPL() { + case_GDI(gdi_hw_context_destroy((gdi_hw_context_t *)c)); + case_QUARTZ(qtz_hw_context_destroy((qtz_hw_context_t *)c)); + case_X11(x11_hw_context_destroy((x11_hw_context_t *)c)); + case_WAYLAND(wl_hw_context_destroy((wl_hw_context_t *)c)); + default_fail(); + } + } +} + +bool +hw_context_resize( + hw_context_t *c, + int32_t width, + int32_t height) +{ + assert(c != NULL); + assert(c->base.width > 0); + assert(c->base.height > 0); + + if ((width <= 0) || (height <= 0)) { + return false; + } + + if ((width == c->base.width) && (height == c->base.height)) { + return true; + } + +// TODO: fill extra data with background color + + if (c->base.offscreen == true) { + + c->base.width = width; + c->base.height = height; + + return true; + + } else { + bool result = false; + switch_IMPL() { + case_GDI(result = + gdi_hw_context_resize((gdi_hw_context_t *)c, width, height)); + case_QUARTZ(result = + qtz_hw_context_resize((qtz_hw_context_t *)c, width, height)); + case_X11(result = + x11_hw_context_resize((x11_hw_context_t *)c, width, height)); + case_WAYLAND(result = + wl_hw_context_resize((wl_hw_context_t *)c, width, height)); + default_fail(); + } + + return result; + } +} + +void +hw_context_present( + hw_context_t *c) +{ + assert(c != NULL); + assert(c->base.offscreen == false); + assert(c->base.width > 0); + assert(c->base.height > 0); + + switch_IMPL() { + case_GDI(gdi_hw_context_present((gdi_hw_context_t *)c)); + case_QUARTZ(qtz_hw_context_present((qtz_hw_context_t *)c)); + case_X11(x11_hw_context_present((x11_hw_context_t *)c)); + case_WAYLAND(wl_hw_context_present((wl_hw_context_t *)c)); + default_fail(); + } +} + +static void +_hw_context_clip_fill_instr( + hw_context_t *c, + const path_fill_instr_t *instr, + const transform_t *transform) +{ + assert(c != NULL); + assert(instr != NULL); + assert(instr->poly != NULL); + assert(transform != NULL); + +} + +bool +hw_context_clip( + hw_context_t *c, + list_t *clip_path, + const transform_t *transform) +{ + assert(c != NULL); + assert(clip_path != NULL); + assert(transform != NULL); + + list_iterator_t *it = list_get_iterator(clip_path); + if (it == NULL) { + return false; + } + + path_fill_instr_t *instr = NULL; + while ((instr = (path_fill_instr_t *)list_iterator_next(it)) != NULL) { + _hw_context_clip_fill_instr(c, instr, transform); + } + + list_free_iterator(it); + + return true; +} + +void +hw_context_clear_clip( + hw_context_t *c) +{ + assert(c != NULL); + +} + +void +hw_context_render_polygon( + hw_context_t *c, + const polygon_t *p, + const rect_t *bbox, + draw_style_t draw_style, + double global_alpha, + const shadow_t *shadow, + composite_operation_t compose_op, + bool non_zero, + const transform_t *transform) +{ + assert(c != NULL); + assert(p != NULL); + assert(bbox != NULL); + assert(shadow != NULL); + assert(transform != NULL); + +} + +void +hw_context_blit( + hw_context_t *dc, + int32_t dx, + int32_t dy, + const hw_context_t *sc, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height, + + double global_alpha, + const shadow_t *shadow, + composite_operation_t compose_op, + const transform_t *transform) +{ + assert(dc != NULL); + assert(sc != NULL); + assert(shadow != NULL); + assert(transform != NULL); + +} + +color_t_ +hw_context_get_pixel( + const hw_context_t *c, + int32_t x, + int32_t y) +{ + assert(c != NULL); + + color_t_ color = color_black; + + return color; +} + +void +hw_context_put_pixel( + hw_context_t *c, + int32_t x, + int32_t y, + color_t_ color) +{ + assert(c != NULL); + +} + +pixmap_t +hw_context_get_pixmap( + const hw_context_t *c, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height) +{ + assert(c != NULL); + + pixmap_t dp = pixmap_null(); + + return dp; +} + +void +hw_context_put_pixmap( + hw_context_t *c, + int32_t dx, + int32_t dy, + const pixmap_t *sp, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height) +{ + assert(c != NULL); + assert(sp != NULL); + assert(pixmap_valid(*sp) == true); + +} + +bool +hw_context_export_png( + const hw_context_t *c, + const char *filename) // as UTF-8 +{ + assert(c != NULL); + assert(filename != NULL); + + const pixmap_t pm = pixmap_null(); + + return impexp_export_png(&pm, filename); +} + +bool +hw_context_import_png( + hw_context_t *c, + int32_t x, + int32_t y, + const char *filename) // as UTF-8 +{ + assert(c != NULL); + assert(filename != NULL); + + pixmap_t pm = pixmap_null(); + + return impexp_import_png(&pm, x, y, filename); +} + +#else + +const int hw_context = 0; + +#endif /* HAS_ACCEL */ diff --git a/src/implem/hw_context.h b/src/implem/hw_context.h new file mode 100644 index 00000000..8d4b58f1 --- /dev/null +++ b/src/implem/hw_context.h @@ -0,0 +1,143 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __HW_CONTEXT_H +#define __HW_CONTEXT_H + +#include +#include + +#include "target.h" +#include "pixmap.h" + +#include "rect.h" +#include "polygon.h" +#include "transform.h" +#include "draw_style.h" +#include "list.h" +#include "state.h" // for shadow_t + +typedef struct hw_context_t hw_context_t; + +hw_context_t * +hw_context_create( + int32_t width, + int32_t height); + +// Creates a context from a pixmap +// The data pointer is transfered to the context +// (thus removed from the pixmap); if you kept +// a copy, do NOT free it ! +hw_context_t * +hw_context_create_from_pixmap( + pixmap_t *pixmap); + +hw_context_t * +hw_context_create_onscreen( + target_t *target, + int32_t width, + int32_t height); + +void +hw_context_destroy( + hw_context_t *c); + +bool +hw_context_resize( + hw_context_t *c, + int32_t width, + int32_t height); + +void +hw_context_present( + hw_context_t *c); + +bool +hw_context_clip( + hw_context_t *c, + list_t *clip_path, + const transform_t *transform); + +void +hw_context_clear_clip( + hw_context_t *c); + +void +hw_context_render_polygon( + hw_context_t *c, + const polygon_t *p, + const rect_t *bbox, + draw_style_t draw_style, + double global_alpha, + const shadow_t *shadow, + composite_operation_t compose_op, + bool non_zero, + const transform_t *transform); + +void +hw_context_blit( + hw_context_t *dc, + int32_t dx, + int32_t dy, + const hw_context_t *sc, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height, + double global_alpha, + const shadow_t *shadow, + composite_operation_t compose_op, + const transform_t *transform); + +color_t_ +hw_context_get_pixel( + const hw_context_t *c, + int32_t x, + int32_t y); + +void +hw_context_put_pixel( + hw_context_t *c, + int32_t x, + int32_t y, + color_t_ color); + +pixmap_t +hw_context_get_pixmap( + const hw_context_t *c, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height); + +void +hw_context_put_pixmap( + hw_context_t *c, + int32_t dx, + int32_t dy, + const pixmap_t *sp, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height); + +bool +hw_context_export_png( + const hw_context_t *c, + const char *filename); // as UTF-8 + +bool +hw_context_import_png( + hw_context_t *c, + int32_t x, + int32_t y, + const char *filename); // as UTF-8 + +#endif /* __HW_CONTEXT_H */ diff --git a/src/implem/hw_context_internal.h b/src/implem/hw_context_internal.h new file mode 100644 index 00000000..aaa8aaff --- /dev/null +++ b/src/implem/hw_context_internal.h @@ -0,0 +1,20 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __HW_CONTEXT_INTERNAL_H +#define __HW_CONTEXT_INTERNAL_H + +#include "context_internal.h" + +typedef struct hw_context_t { + context_t base; +} hw_context_t; + +#endif /* __HW_CONTEXT_INTERNAL_H */ diff --git a/src/implem/quartz/qtz_hw_context.c b/src/implem/quartz/qtz_hw_context.c new file mode 100644 index 00000000..d7a97f44 --- /dev/null +++ b/src/implem/quartz/qtz_hw_context.c @@ -0,0 +1,153 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef HAS_QUARTZ + +#include +#include +#include +#include +#include + +#include + +#include "../config.h" +#include "../color.h" +#include "../context_internal.h" +#include "../hw_context_internal.h" +#include "qtz_hw_context.h" +#include "qtz_target.h" +#include "qtz_util.h" + +@class CanvasHWView; + +typedef struct qtz_hw_context_t { + hw_context_t base; + CanvasHWView *nsview; +} qtz_hw_context_t; + +@interface CanvasHWView : NSView +{ + @public qtz_hw_context_t *context; +} +@end + +@implementation CanvasHWView { } + +- (BOOL)isFlipped +{ + return FALSE; +} + +- (BOOL)preservesContentDuringLiveResize +{ + return TRUE; +} + +- (void)drawRect:(NSRect)rect // called after setNeedsDisplay:YES +{ +/* + qtz_window_t *w = qtz_backend_get_window([self window]); + if (w != NULL) { + event_t evt; + evt.type = EVENT_PRESENT; // not needed + evt.time = qtz_get_time(); + evt.target = (void *)w; + event_notify(qtz_back->listener, &evt); + } +*/ + + qtz_hw_context_present(self->context); + +} + +@end + +qtz_hw_context_t * +qtz_hw_context_create( + qtz_target_t *target, + int32_t width, + int32_t height) +{ + assert(target != NULL); + assert(target->nhwin != NULL); + assert(width > 0); + assert(height > 0); + + qtz_hw_context_t *context = + (qtz_hw_context_t *)calloc(1, sizeof(qtz_hw_context_t)); + if (context == NULL) { + return NULL; + } + + ALLOC_POOL; // don't know if necessary here + + CanvasHWView *nsview = + [[CanvasHWView alloc] initWithFrame:[target->nswin frame]]; + [nsview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [target->nswin setContentView:nsview]; + nsview->context = context; + + RELEASE_POOL; + + context->base.base.width = width; + context->base.base.height = height; + context->nsview = nsview; + + return context; +} + +void +qtz_hw_context_destroy( + qtz_hw_context_t *context) +{ + assert(context != NULL); + + if (context->nsview != NULL) { +// [[context->nsview window] setContentView:nil]; + [context->nsview release]; + } + +} + +bool +qtz_hw_context_resize( + qtz_hw_context_t *context, + int32_t width, + int32_t height) +{ + assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); + assert(width > 0); + assert(height > 0); + + context->base.base.width = width; + context->base.base.height = height; + + return true; +} + +void +qtz_hw_context_present( + qtz_hw_context_t *context) +{ + assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); + assert(context->nsview != NULL); + +} + +#else + +const int qtz_hw_context = 0; + +#endif /* HAS_QUARTZ */ diff --git a/src/implem/quartz/qtz_context.h b/src/implem/quartz/qtz_hw_context.h similarity index 71% rename from src/implem/quartz/qtz_context.h rename to src/implem/quartz/qtz_hw_context.h index 2143fc59..af901b55 100644 --- a/src/implem/quartz/qtz_context.h +++ b/src/implem/quartz/qtz_hw_context.h @@ -8,36 +8,34 @@ /* */ /**************************************************************************/ -#ifndef __QTZ_CONTEXT_H -#define __QTZ_CONTEXT_H +#ifndef __QTZ_HW_CONTEXT_H +#define __QTZ_HW_CONTEXT_H #include #include -#include "../color.h" -#include "../context_internal.h" #include "qtz_target.h" -typedef struct qtz_context_t qtz_context_t; +typedef struct qtz_hw_context_t qtz_hw_context_t; -qtz_context_t * -qtz_context_create( +qtz_hw_context_t * +qtz_hw_context_create( qtz_target_t *target, int32_t width, int32_t height); void -qtz_context_destroy( - qtz_context_t *context); +qtz_hw_context_destroy( + qtz_hw_context_t *context); bool -qtz_context_resize( - qtz_context_t *context, +qtz_hw_context_resize( + qtz_hw_context_t *context, int32_t width, int32_t height); void -qtz_context_present( - qtz_context_t *context); +qtz_hw_context_present( + qtz_hw_context_t *context); -#endif /* __QTZ_CONTEXT_H */ +#endif /* __QTZ_HW_CONTEXT_H */ diff --git a/src/implem/quartz/qtz_context.c b/src/implem/quartz/qtz_sw_context.c similarity index 79% rename from src/implem/quartz/qtz_context.c rename to src/implem/quartz/qtz_sw_context.c index 71e18e8d..91cda941 100644 --- a/src/implem/quartz/qtz_context.c +++ b/src/implem/quartz/qtz_sw_context.c @@ -21,23 +21,25 @@ #include "../config.h" #include "../color.h" #include "../context_internal.h" -#include "qtz_util.h" -//#include "qtz_backend.h" +#include "../sw_context_internal.h" +#include "qtz_sw_context.h" #include "qtz_target.h" -#include "qtz_context.h" +#include "qtz_util.h" + +@class CanvasView; + +typedef struct qtz_sw_context_t { + sw_context_t base; + CGContextRef ctxt; + CanvasView *nsview; +} qtz_sw_context_t; @interface CanvasView : NSView { - @public qtz_context_t *context; + @public qtz_sw_context_t *context; } @end -typedef struct qtz_context_t { - context_t base; - CGContextRef ctxt; - CanvasView *nsview; -} qtz_context_t; - @implementation CanvasView { } - (BOOL)isFlipped @@ -63,14 +65,14 @@ typedef struct qtz_context_t { } */ - qtz_context_present(self->context); + qtz_sw_context_present(self->context); } @end static CGContextRef -_qtz_context_create_bitmap_context( +_qtz_sw_context_create_bitmap_context( int32_t width, int32_t height, color_t_ **data) @@ -107,8 +109,8 @@ _qtz_context_create_bitmap_context( return ctxt; } -qtz_context_t * -qtz_context_create( +qtz_sw_context_t * +qtz_sw_context_create( qtz_target_t *target, int32_t width, int32_t height) @@ -118,15 +120,15 @@ qtz_context_create( assert(width > 0); assert(height > 0); - qtz_context_t *context = - (qtz_context_t *)calloc(1, sizeof(qtz_context_t)); + qtz_sw_context_t *context = + (qtz_sw_context_t *)calloc(1, sizeof(qtz_sw_context_t)); if (context == NULL) { return NULL; } color_t_ *data = NULL; CGContextRef ctxt = - _qtz_context_create_bitmap_context(width, height, &data); + _qtz_sw_context_create_bitmap_context(width, height, &data); if (ctxt == NULL) { assert(data == NULL); free(context); @@ -144,9 +146,9 @@ qtz_context_create( RELEASE_POOL; + context->base.base.width = width; + context->base.base.height = height; context->base.data = data; - context->base.width = width; - context->base.height = height; context->ctxt = ctxt; context->nsview = nsview; @@ -154,8 +156,8 @@ qtz_context_create( } void -qtz_context_destroy( - qtz_context_t *context) +qtz_sw_context_destroy( + qtz_sw_context_t *context) { assert(context != NULL); @@ -172,47 +174,47 @@ qtz_context_destroy( } bool -qtz_context_resize( - qtz_context_t *context, +qtz_sw_context_resize( + qtz_sw_context_t *context, int32_t width, int32_t height) { assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); assert(context->base.data != NULL); - assert(context->base.width > 0); - assert(context->base.height > 0); assert(context->ctxt != NULL); assert(width > 0); assert(height > 0); color_t_ *data = NULL; CGContextRef ctxt = - _qtz_context_create_bitmap_context(width, height, &data); + _qtz_sw_context_create_bitmap_context(width, height, &data); if (ctxt == NULL) { assert(data == NULL); return false; } assert(data != NULL); - _context_copy_to_buffer(&context->base, data, width, height); + _sw_context_copy_to_buffer(&context->base, data, width, height); CGContextRelease(context->ctxt); + context->base.base.width = width; + context->base.base.height = height; context->base.data = data; - context->base.width = width; - context->base.height = height; context->ctxt = ctxt; return true; } void -qtz_context_present( - qtz_context_t *context) +qtz_sw_context_present( + qtz_sw_context_t *context) { assert(context != NULL); - assert(context->base.width > 0); - assert(context->base.height > 0); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); assert(context->ctxt != NULL); assert(context->nsview != NULL); @@ -229,8 +231,8 @@ qtz_context_present( CGImageRef img = CGBitmapContextCreateImage(context->ctxt); CGRect rect = - CGRectMake(0, context->nsview.frame.size.height - context->base.height, - context->base.width, context->base.height); + CGRectMake(0, context->nsview.frame.size.height - context->base.base.height, + context->base.base.width, context->base.base.height); CGContextDrawImage(ctxt, rect, img); [[NSGraphicsContext currentContext] flushGraphics]; @@ -242,6 +244,6 @@ qtz_context_present( #else -const int qtz_context = 0; +const int qtz_sw_context = 0; #endif /* HAS_QUARTZ */ diff --git a/src/implem/quartz/qtz_sw_context.h b/src/implem/quartz/qtz_sw_context.h new file mode 100644 index 00000000..c77d5536 --- /dev/null +++ b/src/implem/quartz/qtz_sw_context.h @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __QTZ_SW_CONTEXT_H +#define __QTZ_SW_CONTEXT_H + +#include +#include + +#include "qtz_target.h" + +typedef struct qtz_sw_context_t qtz_sw_context_t; + +qtz_sw_context_t * +qtz_sw_context_create( + qtz_target_t *target, + int32_t width, + int32_t height); + +void +qtz_sw_context_destroy( + qtz_sw_context_t *context); + +bool +qtz_sw_context_resize( + qtz_sw_context_t *context, + int32_t width, + int32_t height); + +void +qtz_sw_context_present( + qtz_sw_context_t *context); + +#endif /* __QTZ_SW_CONTEXT_H */ diff --git a/src/implem/sw_context.c b/src/implem/sw_context.c new file mode 100644 index 00000000..b6a13340 --- /dev/null +++ b/src/implem/sw_context.c @@ -0,0 +1,597 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#include +#include +#include +#include + +#include "config.h" +#include "target.h" +#include "pixmap.h" +#include "color.h" + +#include "rect.h" +#include "polygon.h" +#include "transform.h" +#include "draw_style.h" +#include "list.h" +#include "state.h" // for shadow_t + +#include "draw_instr.h" +#include "poly_render.h" +#include "impexp.h" + +#ifdef HAS_GDI +#include "gdi/gdi_sw_context.h" +#endif +#ifdef HAS_QUARTZ +#include "quartz/qtz_sw_context.h" +#endif +#ifdef HAS_X11 +#include "x11/x11_sw_context.h" +#endif +#ifdef HAS_WAYLAND +#include "wayland/wl_sw_context.h" +#endif + +#include "context_internal.h" +#include "sw_context_internal.h" + +sw_context_t * +sw_context_create( + int32_t width, + int32_t height) +{ + assert(width > 0); + assert(height > 0); + + color_t_ *data = (color_t_ *)calloc(width * height, sizeof(color_t_)); + if (data == NULL) { + return NULL; + } + + sw_context_t *c = (sw_context_t *)calloc(1, sizeof(sw_context_t)); + if (c == NULL) { + free(data); + return NULL; + } + + c->base.offscreen = true; + c->base.width = width; + c->base.height = height; + c->data = data; + c->clip_region = pixmap_null(); + + return c; +} + +sw_context_t * +sw_context_create_from_pixmap( + pixmap_t *pixmap) +{ + assert(pixmap != NULL); + assert(pixmap_valid(*pixmap) == true); + + sw_context_t *c = (sw_context_t *)calloc(1, sizeof(sw_context_t)); + if (c == NULL) { + return NULL; + } + + c->base.offscreen = true; + c->base.width = pixmap->width; + c->base.height = pixmap->height; + c->data = pixmap->data; + c->clip_region = pixmap_null(); + + pixmap->data = NULL; + pixmap->width = 0; + pixmap->height = 0; + + return c; +} + +sw_context_t * +sw_context_create_onscreen( + target_t *target, + int32_t width, + int32_t height) +{ + assert(target != NULL); + assert(width > 0); + assert(height > 0); + + sw_context_t *c = NULL; + switch_IMPL() { + case_GDI( + c = (sw_context_t *)gdi_sw_context_create((gdi_target_t *)target, + width, height)); + case_QUARTZ( + c = (sw_context_t *)qtz_sw_context_create((qtz_target_t *)target, + width, height)); + case_X11( + c = (sw_context_t *)x11_sw_context_create((x11_target_t *)target, + width, height)); + case_WAYLAND( + c = (sw_context_t *)wl_sw_context_create((wl_target_t *)target, + width, height)); + default_fail(); + } + if (c == NULL) { + return NULL; + } + + c->base.offscreen = false; + c->clip_region = pixmap_null(); + + return c; +} + +void +sw_context_destroy( + sw_context_t *c) +{ + assert(c != NULL); + assert(c->data != NULL); + + if (pixmap_valid(c->clip_region) == true) { + pixmap_destroy(c->clip_region); + } + + if (c->base.offscreen == true) { + free(c->data); + free(c); + } else { + switch_IMPL() { + case_GDI(gdi_sw_context_destroy((gdi_sw_context_t *)c)); + case_QUARTZ(qtz_sw_context_destroy((qtz_sw_context_t *)c)); + case_X11(x11_sw_context_destroy((x11_sw_context_t *)c)); + case_WAYLAND(wl_sw_context_destroy((wl_sw_context_t *)c)); + default_fail(); + } + } +} + +void +_sw_context_copy_to_buffer( + sw_context_t *c, + color_t_ *data, + int32_t width, + int32_t height) +{ + assert(c != NULL); + assert(c->base.width > 0); + assert(c->base.height > 0); + assert(c->data != NULL); + assert(data != NULL); + assert(width > 0); + assert(height > 0); + + uint32_t min_width = width < c->base.width ? width : c->base.width; + uint32_t min_height = height < c->base.height ? height : c->base.height; + for (size_t i = 0; i < min_height; ++i) { + for (size_t j = 0; j < min_width; ++j) { + data[i * width + j] = c->data[i * c->base.width + j]; + } + } +} + +bool +sw_context_resize( + sw_context_t *c, + int32_t width, + int32_t height) +{ + assert(c != NULL); + assert(c->base.width > 0); + assert(c->base.height > 0); + assert(c->data != NULL); + + if ((width <= 0) || (height <= 0)) { + return false; + } + + if ((width == c->base.width) && (height == c->base.height)) { + return true; + } + + if (pixmap_valid(c->clip_region)) { + pixmap_destroy(c->clip_region); + } + +// TODO: fill extra data with background color + + if (c->base.offscreen == true) { + + color_t_ *data = (color_t_ *)calloc(width * height, sizeof(color_t_)); + if (data == NULL) { + return false; + } + + _sw_context_copy_to_buffer(c, data, width, height); + + free(c->data); + + c->base.width = width; + c->base.height = height; + c->data = data; + + return true; + + } else { + bool result = false; + switch_IMPL() { + case_GDI(result = + gdi_sw_context_resize((gdi_sw_context_t *)c, width, height)); + case_QUARTZ(result = + qtz_sw_context_resize((qtz_sw_context_t *)c, width, height)); + case_X11(result = + x11_sw_context_resize((x11_sw_context_t *)c, width, height)); + case_WAYLAND(result = + wl_sw_context_resize((wl_sw_context_t *)c, width, height)); + default_fail(); + } + + return result; + } +} + +void +sw_context_present( + sw_context_t *c) +{ + assert(c != NULL); + assert(c->base.offscreen == false); + assert(c->base.width > 0); + assert(c->base.height > 0); + assert(c->data != NULL); + + switch_IMPL() { + case_GDI(gdi_sw_context_present((gdi_sw_context_t *)c)); + case_QUARTZ(qtz_sw_context_present((qtz_sw_context_t *)c)); + case_X11(x11_sw_context_present((x11_sw_context_t *)c)); + case_WAYLAND(wl_sw_context_present((wl_sw_context_t *)c)); + default_fail(); + } +} + +// Direct access to the context pixels +// Do NOT free the data pointer ! +static pixmap_t +_sw_context_get_raw_pixmap( + sw_context_t *c) +{ + assert(c != NULL); + assert(c->base.width > 0); + assert(c->base.height > 0); + assert(c->data != NULL); + + return pixmap(c->base.width, c->base.height, c->data); +} + +static void +_sw_context_clip_fill_instr( + sw_context_t *c, + const path_fill_instr_t *instr, + const transform_t *transform) +{ + assert(c != NULL); + assert(pixmap_valid(c->clip_region) == true); + assert(instr != NULL); + assert(instr->poly != NULL); + assert(transform != NULL); + + draw_style_t white = (draw_style_t){ .type = DRAW_STYLE_COLOR, + .content.color = color_white }; + shadow_t noshadow = (shadow_t){ + .offset_x = 0, .offset_y = 0, .blur = 0, + .color = color_transparent_black }; + +// TODO: could store bounding box with polygon + rect_t bbox = rect(point(0.0, 0.0), + point((double)c->base.width, + (double)c->base.height)); + + poly_render(&(c->clip_region), instr->poly, &bbox, white, 1.0, &noshadow, + ONE_MINUS_SRC, NULL, instr->non_zero, transform); +} + +bool +sw_context_clip( + sw_context_t *c, + list_t *clip_path, + const transform_t *transform) +{ + assert(c != NULL); + assert(clip_path != NULL); + assert(transform != NULL); + + if ((pixmap_valid(c->clip_region) == true) && + ((c->clip_region.width != c->base.width) || + (c->clip_region.height != c->base.height))) { + pixmap_destroy(c->clip_region); + } + + if (pixmap_valid(c->clip_region) == false) { + c->clip_region = pixmap(c->base.width, c->base.height, NULL); + if (pixmap_valid(c->clip_region) == false) { + return false; + } + } + + pixmap_clear(c->clip_region); + + list_iterator_t *it = list_get_iterator(clip_path); + if (it == NULL) { + return false; + } + + path_fill_instr_t *instr = NULL; + while ((instr = (path_fill_instr_t *)list_iterator_next(it)) != NULL) { + _sw_context_clip_fill_instr(c, instr, transform); + } + + list_free_iterator(it); + + return true; +} + +void +sw_context_clear_clip( + sw_context_t *c) +{ + assert(c != NULL); + + if (pixmap_valid(c->clip_region) == true) { + pixmap_destroy(c->clip_region); + } +} + +void +sw_context_render_polygon( + sw_context_t *c, + const polygon_t *p, + const rect_t *bbox, + draw_style_t draw_style, + double global_alpha, + const shadow_t *shadow, + composite_operation_t compose_op, + bool non_zero, + const transform_t *transform) +{ + assert(c != NULL); + assert(p != NULL); + assert(bbox != NULL); + assert(shadow != NULL); + assert(transform != NULL); + + pixmap_t pm = pixmap(c->base.width, c->base.height, c->data); + poly_render(&pm, p, bbox, draw_style, global_alpha, shadow, compose_op, + &(c->clip_region), non_zero, transform); +} + +void +sw_context_blit( + sw_context_t *dc, + int32_t dx, + int32_t dy, + const sw_context_t *sc, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height, + + double global_alpha, + const shadow_t *shadow, + composite_operation_t compose_op, + const transform_t *transform) +{ + assert(dc != NULL); + assert(sc != NULL); + assert(shadow != NULL); + assert(transform != NULL); + + bool draw_shadows = + (shadow->blur > 0.0 || + shadow->offset_x != 0.0 || shadow->offset_y != 0.0) && + compose_op != COPY && shadow->color.a != 0; + + const pixmap_t sp = _sw_context_get_raw_pixmap((sw_context_t *)sc); + pixmap_t dp = _sw_context_get_raw_pixmap(dc); + +// TODO: global_alpha ? + if ((transform_is_pure_translation(transform) == true) && + (draw_shadows == false)) { + + double tx = 0.0, ty = 0.0; + transform_extract_translation(transform, &tx, &ty); + + int32_t lo_x = max(dx + (int32_t)tx, 0); + int32_t hi_x = min(dx + (int32_t)tx + width, dc->base.width); // canvas wd + int32_t lo_y = max(dy + (int32_t)ty, 0); + int32_t hi_y = min(dy + (int32_t)ty + height, dc->base.height); //canvas ht + + for (int32_t i = lo_x; i < hi_x; i++) { + for (int32_t j = lo_y; j < hi_y; j++) { + + int32_t uvx = i + sx - dx - (int32_t)tx; + int32_t uvy = j + sy - dy - (int32_t)ty; + if (uvx < 0 || uvx >= sc->base.width || // canvas wd + uvy < 0 || uvy >= sc->base.height) { // canvas ht + continue; + } + + color_t_ fill_color = pixmap_at(sp, uvy, uvx); + int draw_alpha = fill_color.a; + if (pixmap_valid(dc->clip_region) == true) { + draw_alpha *= 255 - pixmap_at(dc->clip_region, j, i).a; + draw_alpha /= 255; + } + + pixmap_at(dp, j, i) = + comp_compose(fill_color, pixmap_at(dp, j, i), + draw_alpha, compose_op); + } + } + + } else { + + draw_style_t draw_style = + (draw_style_t){ .type = DRAW_STYLE_PIXMAP, .content.pixmap = &sp }; + + polygon_t *p = polygon_create(8, 1); + if (p == NULL) { + return; + } + + point_t p1 = point((double)dx, (double)dy); + point_t p2 = point((double)(dx + width), (double)dy); + point_t p3 = point((double)(dx + width), (double)(dy + height)); + point_t p4 = point((double)dx, (double)(dy + height)); + + transform_apply(transform, &p1); + transform_apply(transform, &p2); + transform_apply(transform, &p3); + transform_apply(transform, &p4); + + polygon_add_point(p, p1); + polygon_add_point(p, p2); + polygon_add_point(p, p3); + polygon_add_point(p, p4); + polygon_end_subpoly(p, true); + + rect_t bbox = rect(point(min4(p1.x, p2.x, p3.x, p4.x), + min4(p1.y, p2.y, p3.y, p4.y)), + point(max4(p1.x, p2.x, p3.x, p4.x), + max4(p1.y, p2.y, p3.y, p4.y))); + + transform_t *temp_transform = transform_copy(transform); + transform_translate(temp_transform, dx - sx, dy - sy); + + pixmap_t pm = _sw_context_get_raw_pixmap(dc); + poly_render(&pm, p, &bbox, draw_style, global_alpha, shadow, compose_op, + &(dc->clip_region), false, temp_transform); + + transform_destroy(temp_transform); + + polygon_destroy(p); + } +} + +color_t_ +sw_context_get_pixel( + const sw_context_t *c, + int32_t x, + int32_t y) +{ + assert(c != NULL); + + color_t_ color = color_black; + + const pixmap_t pm = _sw_context_get_raw_pixmap((sw_context_t *)c); + if (pixmap_valid(pm) == true) { + if ((x >= 0) && (x < pm.width) && (y >= 0) && (y < pm.height)) { + color = pixmap_at(pm, y, x); + } + } + + return color; +} + +void +sw_context_put_pixel( + sw_context_t *c, + int32_t x, + int32_t y, + color_t_ color) +{ + assert(c != NULL); + + pixmap_t pm = _sw_context_get_raw_pixmap((sw_context_t *)c); + if (pixmap_valid(pm) == true) { + if ((x >= 0) && (x < pm.width) && (y >= 0) && (y < pm.height)) { + pixmap_at(pm, y, x) = color; + } + } +} + +pixmap_t +sw_context_get_pixmap( + const sw_context_t *c, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height) +{ + assert(c != NULL); + + pixmap_t dp = pixmap_null(); + const pixmap_t sp = _sw_context_get_raw_pixmap((sw_context_t *)c); + if (pixmap_valid(sp) == true) { + dp = pixmap(width, height, NULL); + if (pixmap_valid(dp) == true) { + pixmap_blit(&dp, 0, 0, &sp, sx, sy, width, height); + } + } + return dp; +} + +void +sw_context_put_pixmap( + sw_context_t *c, + int32_t dx, + int32_t dy, + const pixmap_t *sp, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height) +{ + assert(c != NULL); + assert(sp != NULL); + assert(pixmap_valid(*sp) == true); + + pixmap_t dp = _sw_context_get_raw_pixmap(c); + if (pixmap_valid(dp) == true) { + pixmap_blit(&dp, dx, dy, sp, sx, sy, width, height); + } +} + +bool +sw_context_export_png( + const sw_context_t *c, + const char *filename) // as UTF-8 +{ + assert(c != NULL); + assert(filename != NULL); + + const pixmap_t pm = _sw_context_get_raw_pixmap((sw_context_t *)c); + if (pixmap_valid(pm) == false) { + return false; + } + return impexp_export_png(&pm, filename); +} + +bool +sw_context_import_png( + sw_context_t *c, + int32_t x, + int32_t y, + const char *filename) // as UTF-8 +{ + assert(c != NULL); + assert(filename != NULL); + + pixmap_t pm = _sw_context_get_raw_pixmap(c); + if (pixmap_valid(pm) == false) { + return false; + } + return impexp_import_png(&pm, x, y, filename); +} diff --git a/src/implem/sw_context.h b/src/implem/sw_context.h new file mode 100644 index 00000000..349119fa --- /dev/null +++ b/src/implem/sw_context.h @@ -0,0 +1,143 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __SW_CONTEXT_H +#define __SW_CONTEXT_H + +#include +#include + +#include "target.h" +#include "pixmap.h" + +#include "rect.h" +#include "polygon.h" +#include "transform.h" +#include "draw_style.h" +#include "list.h" +#include "state.h" // for shadow_t + +typedef struct sw_context_t sw_context_t; + +sw_context_t * +sw_context_create( + int32_t width, + int32_t height); + +// Creates a context from a pixmap +// The data pointer is transfered to the context +// (thus removed from the pixmap); if you kept +// a copy, do NOT free it ! +sw_context_t * +sw_context_create_from_pixmap( + pixmap_t *pixmap); + +sw_context_t * +sw_context_create_onscreen( + target_t *target, + int32_t width, + int32_t height); + +void +sw_context_destroy( + sw_context_t *c); + +bool +sw_context_resize( + sw_context_t *c, + int32_t width, + int32_t height); + +void +sw_context_present( + sw_context_t *c); + +bool +sw_context_clip( + sw_context_t *c, + list_t *clip_path, + const transform_t *transform); + +void +sw_context_clear_clip( + sw_context_t *c); + +void +sw_context_render_polygon( + sw_context_t *c, + const polygon_t *p, + const rect_t *bbox, + draw_style_t draw_style, + double global_alpha, + const shadow_t *shadow, + composite_operation_t compose_op, + bool non_zero, + const transform_t *transform); + +void +sw_context_blit( + sw_context_t *dc, + int32_t dx, + int32_t dy, + const sw_context_t *sc, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height, + double global_alpha, + const shadow_t *shadow, + composite_operation_t compose_op, + const transform_t *transform); + +color_t_ +sw_context_get_pixel( + const sw_context_t *c, + int32_t x, + int32_t y); + +void +sw_context_put_pixel( + sw_context_t *c, + int32_t x, + int32_t y, + color_t_ color); + +pixmap_t +sw_context_get_pixmap( + const sw_context_t *c, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height); + +void +sw_context_put_pixmap( + sw_context_t *c, + int32_t dx, + int32_t dy, + const pixmap_t *sp, + int32_t sx, + int32_t sy, + int32_t width, + int32_t height); + +bool +sw_context_export_png( + const sw_context_t *c, + const char *filename); // as UTF-8 + +bool +sw_context_import_png( + sw_context_t *c, + int32_t x, + int32_t y, + const char *filename); // as UTF-8 + +#endif /* __SW_CONTEXT_H */ diff --git a/src/implem/sw_context_internal.h b/src/implem/sw_context_internal.h new file mode 100644 index 00000000..52f31591 --- /dev/null +++ b/src/implem/sw_context_internal.h @@ -0,0 +1,33 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __SW_CONTEXT_INTERNAL_H +#define __SW_CONTEXT_INTERNAL_H + +#include + +#include "color.h" +#include "pixmap.h" +#include "context_internal.h" + +typedef struct sw_context_t { + context_t base; + color_t_ *data; + pixmap_t clip_region; // temporary +} sw_context_t; + +void +_sw_context_copy_to_buffer( + sw_context_t *c, + color_t_ *data, + int32_t width, + int32_t height); + +#endif /* __SW_CONTEXT_INTERNAL_H */ diff --git a/src/implem/wayland/wl_context.c b/src/implem/wayland/wl_hw_context.c similarity index 76% rename from src/implem/wayland/wl_context.c rename to src/implem/wayland/wl_hw_context.c index b7486d6d..578c5adc 100644 --- a/src/implem/wayland/wl_context.c +++ b/src/implem/wayland/wl_hw_context.c @@ -16,14 +16,15 @@ #include "../config.h" #include "../context_internal.h" +#include "../hw_context_internal.h" #include "wl_target.h" -typedef struct wl_context_t { - context_t base; -} wl_context_t; +typedef struct wl_hw_context_t { + hw_context_t base; +} wl_hw_context_t; -wl_context_t * -wl_context_create( +wl_hw_context_t * +wl_hw_context_create( wl_target_t *target, int32_t width, int32_t height) @@ -32,14 +33,14 @@ wl_context_create( } void -wl_context_destroy( - wl_context_t *context) +wl_hw_context_destroy( + wl_hw_context_t *context) { } bool -wl_context_resize( - wl_context_t *context, +wl_hw_context_resize( + wl_hw_context_t *context, int32_t width, int32_t height) { @@ -47,13 +48,13 @@ wl_context_resize( } void -wl_context_present( - wl_context_t *context) +wl_hw_context_present( + wl_hw_context_t *context) { } #else -const int wl_context = 0; +const int wl_hw_context = 0; #endif /* HAS_WAYLAND */ diff --git a/src/implem/wayland/wl_context.h b/src/implem/wayland/wl_hw_context.h similarity index 72% rename from src/implem/wayland/wl_context.h rename to src/implem/wayland/wl_hw_context.h index af2723e5..93ab90af 100644 --- a/src/implem/wayland/wl_context.h +++ b/src/implem/wayland/wl_hw_context.h @@ -8,35 +8,34 @@ /* */ /**************************************************************************/ -#ifndef __WL_CONTEXT_H -#define __WL_CONTEXT_H +#ifndef __WL_HW_CONTEXT_H +#define __WL_HW_CONTEXT_H #include #include -#include "../color.h" #include "wl_target.h" -typedef struct wl_context_t wl_context_t; +typedef struct wl_hw_context_t wl_hw_context_t; -wl_context_t * -wl_context_create( +wl_hw_context_t * +wl_hw_context_create( wl_target_t *target, int32_t width, int32_t height); void -wl_context_destroy( - wl_context_t *context); +wl_hw_context_destroy( + wl_hw_context_t *context); bool -wl_context_resize( - wl_context_t *context, +wl_hw_context_resize( + wl_hw_context_t *context, int32_t width, int32_t height); void -wl_context_present( - wl_context_t *context); +wl_hw_context_present( + wl_hw_context_t *context); -#endif /* __WL_CONTEXT_H */ +#endif /* __WL_HW_CONTEXT_H */ diff --git a/src/implem/wayland/wl_sw_context.c b/src/implem/wayland/wl_sw_context.c new file mode 100644 index 00000000..8eefe361 --- /dev/null +++ b/src/implem/wayland/wl_sw_context.c @@ -0,0 +1,60 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef HAS_WAYLAND + +#include +#include +#include + +#include "../config.h" +#include "../context_internal.h" +#include "../sw_context_internal.h" +#include "wl_target.h" + +typedef struct wl_sw_context_t { + sw_context_t base; +} wl_sw_context_t; + +wl_sw_context_t * +wl_sw_context_create( + wl_target_t *target, + int32_t width, + int32_t height) +{ + return NULL; +} + +void +wl_sw_context_destroy( + wl_sw_context_t *context) +{ +} + +bool +wl_sw_context_resize( + wl_sw_context_t *context, + int32_t width, + int32_t height) +{ + return false; +} + +void +wl_sw_context_present( + wl_sw_context_t *context) +{ +} + +#else + +const int wl_sw_context = 0; + +#endif /* HAS_WAYLAND */ diff --git a/src/implem/wayland/wl_sw_context.h b/src/implem/wayland/wl_sw_context.h new file mode 100644 index 00000000..5672cc69 --- /dev/null +++ b/src/implem/wayland/wl_sw_context.h @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __WL_SW_CONTEXT_H +#define __WL_SW_CONTEXT_H + +#include +#include + +#include "wl_target.h" + +typedef struct wl_sw_context_t wl_sw_context_t; + +wl_sw_context_t * +wl_sw_context_create( + wl_target_t *target, + int32_t width, + int32_t height); + +void +wl_sw_context_destroy( + wl_sw_context_t *context); + +bool +wl_sw_context_resize( + wl_sw_context_t *context, + int32_t width, + int32_t height); + +void +wl_sw_context_present( + wl_sw_context_t *context); + +#endif /* __WL_SW_CONTEXT_H */ diff --git a/src/implem/x11/x11_hw_context.c b/src/implem/x11/x11_hw_context.c new file mode 100644 index 00000000..d8e47fe1 --- /dev/null +++ b/src/implem/x11/x11_hw_context.c @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifdef HAS_X11 + +#include +#include +#include +#include +#include + +#include + +#include "../config.h" +#include "../color.h" +#include "../context_internal.h" +#include "../hw_context_internal.h" +#include "x11_backend_internal.h" +#include "x11_target.h" + +typedef struct x11_hw_context_t { + hw_context_t base; + xcb_window_t wid; +} x11_hw_context_t; + +x11_hw_context_t * +x11_hw_context_create( + x11_target_t *target, + int32_t width, + int32_t height) +{ + assert(target != NULL); + assert(target->wid != XCB_WINDOW_NONE); + assert(width > 0); + assert(height > 0); + + x11_hw_context_t *context = + (x11_hw_context_t *)calloc(1, sizeof(x11_hw_context_t)); + if (context == NULL) { + return NULL; + } + + context->base.base.width = width; + context->base.base.height = height; + context->wid = target->wid; + + return context; +} + +void +x11_hw_context_destroy( + x11_hw_context_t *context) +{ + assert(context != NULL); + + free(context); +} + +bool +x11_hw_context_resize( + x11_hw_context_t *context, + int32_t width, + int32_t height) +{ + assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); + assert(width > 0); + assert(height > 0); + + context->base.base.width = width; + context->base.base.height = height; + + return true; +} + +void +x11_hw_context_present( + x11_hw_context_t *context) +{ + assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); + assert(context->wid != XCB_WINDOW_NONE); + +} + +#else + +const int x11_hw_context = 0; + +#endif /* HAS_X11 */ diff --git a/src/implem/x11/x11_context.h b/src/implem/x11/x11_hw_context.h similarity index 72% rename from src/implem/x11/x11_context.h rename to src/implem/x11/x11_hw_context.h index 3d0c4bfb..b53d4a7a 100644 --- a/src/implem/x11/x11_context.h +++ b/src/implem/x11/x11_hw_context.h @@ -8,35 +8,34 @@ /* */ /**************************************************************************/ -#ifndef __X11_CONTEXT_H -#define __X11_CONTEXT_H +#ifndef __X11_HW_CONTEXT_H +#define __X11_HW_CONTEXT_H #include #include -#include "../color.h" #include "x11_target.h" -typedef struct x11_context_t x11_context_t; +typedef struct x11_hw_context_t x11_hw_context_t; -x11_context_t * -x11_context_create( +x11_hw_context_t * +x11_hw_context_create( x11_target_t *target, int32_t width, int32_t height); void -x11_context_destroy( - x11_context_t *context); +x11_hw_context_destroy( + x11_hw_context_t *context); bool -x11_context_resize( - x11_context_t *context, +x11_hw_context_resize( + x11_hw_context_t *context, int32_t width, int32_t height); void -x11_context_present( - x11_context_t *context); +x11_hw_context_present( + x11_hw_context_t *context); -#endif /* __X11_CONTEXT_H */ +#endif /* __X11_HW_CONTEXT_H */ diff --git a/src/implem/x11/x11_context.c b/src/implem/x11/x11_sw_context.c similarity index 76% rename from src/implem/x11/x11_context.c rename to src/implem/x11/x11_sw_context.c index 077fecdb..aa9a2f2a 100644 --- a/src/implem/x11/x11_context.c +++ b/src/implem/x11/x11_sw_context.c @@ -22,18 +22,19 @@ #include "../config.h" #include "../color.h" #include "../context_internal.h" +#include "../sw_context_internal.h" #include "x11_backend_internal.h" #include "x11_target.h" -typedef struct x11_context_t { - context_t base; +typedef struct x11_sw_context_t { + sw_context_t base; xcb_image_t *img; xcb_window_t wid; xcb_gcontext_t cid; -} x11_context_t; +} x11_sw_context_t; static xcb_image_t * -_x11_context_create_image( +_x11_sw_context_create_image( xcb_connection_t *c, uint8_t depth, int32_t width, @@ -64,8 +65,8 @@ _x11_context_create_image( return img; } -x11_context_t * -x11_context_create( +x11_sw_context_t * +x11_sw_context_create( x11_target_t *target, int32_t width, int32_t height) @@ -75,8 +76,8 @@ x11_context_create( assert(width > 0); assert(height > 0); - x11_context_t *context = - (x11_context_t *)calloc(1, sizeof(x11_context_t)); + x11_sw_context_t *context = + (x11_sw_context_t *)calloc(1, sizeof(x11_sw_context_t)); if (context == NULL) { return NULL; } @@ -84,7 +85,7 @@ x11_context_create( // TODO: allow xcb / SHM color_t_ *data = NULL; xcb_image_t *img = - _x11_context_create_image(x11_back->c, x11_back->screen->root_depth, + _x11_sw_context_create_image(x11_back->c, x11_back->screen->root_depth, width, height, &data); if (img == NULL) { assert(data == NULL); @@ -97,9 +98,9 @@ x11_context_create( xcb_create_gc(x11_back->c, cid, target->wid, XCB_GC_GRAPHICS_EXPOSURES, (uint32_t[]){ 1 }); + context->base.base.width = width; + context->base.base.height = height; context->base.data = data; - context->base.width = width; - context->base.height = height; context->img = img; context->wid = target->wid; context->cid = cid; @@ -108,8 +109,8 @@ x11_context_create( } void -x11_context_destroy( - x11_context_t *context) +x11_sw_context_destroy( + x11_sw_context_t *context) { assert(context != NULL); @@ -126,48 +127,48 @@ x11_context_destroy( } bool -x11_context_resize( - x11_context_t *context, +x11_sw_context_resize( + x11_sw_context_t *context, int32_t width, int32_t height) { assert(context != NULL); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); assert(context->base.data != NULL); - assert(context->base.width > 0); - assert(context->base.height > 0); assert(context->img != NULL); assert(width > 0); assert(height > 0); color_t_ *data = NULL; xcb_image_t *img = - _x11_context_create_image(x11_back->c, x11_back->screen->root_depth, - width, height, &data); + _x11_sw_context_create_image(x11_back->c, x11_back->screen->root_depth, + width, height, &data); if (img == NULL) { assert(data == NULL); return false; } assert(data != NULL); - _context_copy_to_buffer(&context->base, data, width, height); + _sw_context_copy_to_buffer(&context->base, data, width, height); xcb_image_destroy(context->img); + context->base.base.width = width; + context->base.base.height = height; context->base.data = data; - context->base.width = width; - context->base.height = height; context->img = img; return true; } void -x11_context_present( - x11_context_t *context) +x11_sw_context_present( + x11_sw_context_t *context) { assert(context != NULL); - assert(context->base.width > 0); - assert(context->base.height > 0); + assert(context->base.base.width > 0); + assert(context->base.base.height > 0); assert(context->img != NULL); assert(context->wid != XCB_WINDOW_NONE); assert(context->cid != XCB_NONE); @@ -179,6 +180,6 @@ x11_context_present( #else -const int x11_context = 0; +const int x11_sw_context = 0; #endif /* HAS_X11 */ diff --git a/src/implem/x11/x11_sw_context.h b/src/implem/x11/x11_sw_context.h new file mode 100644 index 00000000..ead42101 --- /dev/null +++ b/src/implem/x11/x11_sw_context.h @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* */ +/* Copyright 2022 OCamlPro */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#ifndef __X11_SW_CONTEXT_H +#define __X11_SW_CONTEXT_H + +#include +#include + +#include "x11_target.h" + +typedef struct x11_sw_context_t x11_sw_context_t; + +x11_sw_context_t * +x11_sw_context_create( + x11_target_t *target, + int32_t width, + int32_t height); + +void +x11_sw_context_destroy( + x11_sw_context_t *context); + +bool +x11_sw_context_resize( + x11_sw_context_t *context, + int32_t width, + int32_t height); + +void +x11_sw_context_present( + x11_sw_context_t *context); + +#endif /* __X11_SW_CONTEXT_H */ diff --git a/src/stubs/ml_tags.h b/src/stubs/ml_tags.h index ae28d6f9..729b954c 100644 --- a/src/stubs/ml_tags.h +++ b/src/stubs/ml_tags.h @@ -260,12 +260,4 @@ typedef enum comp_op_tag_t { TAG_OP_LUMINOSITY = 25 } comp_op_tag_t; -typedef enum backend_tag_t { - TAG_CANVAS = 0, - TAG_GDI = 1, - TAG_QUARTZ = 2, - TAG_X11 = 3, - TAG_WAYLAND = 4 -} backend_tag_t; - #endif /* __ML_TAGS_H */