diff --git a/target/i386/latx/context/kzt-groups.c b/target/i386/latx/context/kzt-groups.c index ca51d4e9d1..908a946c7c 100644 --- a/target/i386/latx/context/kzt-groups.c +++ b/target/i386/latx/context/kzt-groups.c @@ -423,3 +423,23 @@ void kzt_groups_log_library(const char *soname, bool enabled) return; } } + +void kzt_groups_log_wrapper_rejection(const char *soname, + const char *reason) +{ + if (!group_log_enabled) { + return; + } + fprintf(stderr, "KZT: native wrapper rejected for %s: %s\n", + soname, reason); +} + +void kzt_groups_log_wrapper_limitation(const char *soname, + const char *reason) +{ + if (!group_log_enabled) { + return; + } + fprintf(stderr, "KZT: native wrapper limitation for %s: %s\n", + soname, reason); +} diff --git a/target/i386/latx/context/meson.build b/target/i386/latx/context/meson.build index 4e832ffd94..2586140630 100644 --- a/target/i386/latx/context/meson.build +++ b/target/i386/latx/context/meson.build @@ -25,6 +25,8 @@ my_file = files( 'wrappedlibxcbutil.c', 'wrappedlibxcbxinerama.c', 'wrappedlibxcbxinput.c', + 'wrappedcairo-preflight.c', + 'wrappedcairo.c', 'wrappedlibx11xcb.c', 'wrappedxkbcommon.c', 'wrappedxkbcommonx11.c', diff --git a/target/i386/latx/context/myalign.c b/target/i386/latx/context/myalign.c index 174b25b2b5..ac4aa00b15 100644 --- a/target/i386/latx/context/myalign.c +++ b/target/i386/latx/context/myalign.c @@ -2694,13 +2694,14 @@ static int kzt_try_bind_observed_object( (void)opaque; result = kzt_public_loader_object_has_relro( object, &kzt_public_loader_reader, &has_relro); - /* - * Loader ordering differs across glibc releases. Some publish - * RT_CONSISTENT before applying RELRO, so this callback can still be - * the last naturally writable point even when PT_GNU_RELRO exists. - * kzt_try_bind_loaded_object() rechecks every relocation target under - * mmap_lock and fails closed if protection was already applied. - */ + if (result == KZT_PUBLIC_LOADER_OK && has_relro) { + printf_log(LOG_DEBUG, + "KZT observed link_map=%p at a consistent loader state; " + "deferring relocation until its writable RELRO boundary\n", + object ? (void *)object->link_map_addr : NULL); + return 0; + } + /* Objects without RELRO have no later protection boundary to observe. */ if (result == KZT_PUBLIC_LOADER_OK && kzt_try_bind_loaded_object( object, KZT_AFTER_LOADER_CONSISTENT, &processed) == 0 && diff --git a/target/i386/latx/context/wrappedcairo-preflight.c b/target/i386/latx/context/wrappedcairo-preflight.c new file mode 100644 index 0000000000..0f4b614ce8 --- /dev/null +++ b/target/i386/latx/context/wrappedcairo-preflight.c @@ -0,0 +1,249 @@ +/* + * SPDX-FileCopyrightText: 2026 LAT Project Authors + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "wrappedcairo-preflight.h" + +#define GO(name, signature) #name, +#define GOM(name, signature) #name, +#define GOW(name, signature) #name, +#define GOWM(name, signature) #name, +#define GO2(name, signature, alias) #name, +#define GOS(name, signature) #name, +#define DATA(name, size) +#define DATAV(name, size) +#define DATAB(name, size) +#define DATAM(name, size) +static const char *const cairo_supported_symbols[] = { +#include "wrappedcairo_private.h" +}; +#undef GO +#undef GOM +#undef GOW +#undef GOWM +#undef GO2 +#undef GOS +#undef DATA +#undef DATAV +#undef DATAB +#undef DATAM + +static bool cairo_symbol_is_supported(const char *name) +{ + size_t count = sizeof(cairo_supported_symbols) / + sizeof(cairo_supported_symbols[0]); + + for (size_t i = 0; i < count; i++) { + if (!strcmp(name, cairo_supported_symbols[i])) { + return true; + } + } + return false; +} + +static bool read_exact(FILE *file, void *buffer, size_t size, long offset) +{ + return fseek(file, offset, SEEK_SET) == 0 && + fread(buffer, 1, size, file) == size; +} + +static bool range_is_valid(uint64_t offset, uint64_t size, + uint64_t file_size) +{ + return offset <= file_size && size <= file_size - offset; +} + +static bool reject(char *reason, size_t reason_size, const char *format, + const char *detail) +{ + snprintf(reason, reason_size, format, detail ? detail : ""); + return false; +} + +bool latx_cairo_preflight_guest(const char *guest_path, + const char *host_soname, + char *reason, size_t reason_size) +{ + Elf64_Ehdr ehdr; + Elf64_Shdr *sections = NULL; + FILE *file = NULL; + void *host = NULL; + bool found_dynsym = false; + bool found_cairo_symbol = false; + bool ok = false; + long file_size; + + if (!reason || !reason_size) { + return false; + } + reason[0] = '\0'; + if (!guest_path || !host_soname) { + return reject(reason, reason_size, + "guest or host Cairo path is unavailable%s", NULL); + } + + file = fopen(guest_path, "rb"); + if (!file) { + snprintf(reason, reason_size, "cannot open guest ELF '%s': %s", + guest_path, strerror(errno)); + goto out; + } + if (fseek(file, 0, SEEK_END) != 0 || + (file_size = ftell(file)) < 0 || + fseek(file, 0, SEEK_SET) != 0) { + reject(reason, reason_size, + "cannot determine guest Cairo ELF size%s", NULL); + goto out; + } + if (fread(&ehdr, 1, sizeof(ehdr), file) != sizeof(ehdr) || + memcmp(ehdr.e_ident, ELFMAG, SELFMAG) || + ehdr.e_ident[EI_CLASS] != ELFCLASS64 || + ehdr.e_ident[EI_DATA] != ELFDATA2LSB || + ehdr.e_type != ET_DYN || + ehdr.e_machine != EM_X86_64 || + ehdr.e_shentsize != sizeof(Elf64_Shdr) || + !ehdr.e_shoff || !ehdr.e_shnum || + !range_is_valid(ehdr.e_shoff, + (uint64_t)ehdr.e_shnum * sizeof(Elf64_Shdr), + file_size)) { + reject(reason, reason_size, + "guest Cairo is not a supported ELF64 little-endian shared object%s", + NULL); + goto out; + } + sections = calloc(ehdr.e_shnum, sizeof(*sections)); + if (!sections || + !read_exact(file, sections, ehdr.e_shnum * sizeof(*sections), + (long)ehdr.e_shoff)) { + reject(reason, reason_size, + "cannot read guest Cairo section table%s", NULL); + goto out; + } + + host = dlopen(host_soname, RTLD_LAZY | RTLD_LOCAL); + if (!host) { + reject(reason, reason_size, "cannot load host Cairo: %s", dlerror()); + goto out; + } + + for (size_t section_index = 0; section_index < ehdr.e_shnum; + section_index++) { + const Elf64_Shdr *dynsym = §ions[section_index]; + const Elf64_Shdr *strtab; + Elf64_Sym *symbols = NULL; + char *strings = NULL; + size_t symbol_count; + + if (dynsym->sh_type != SHT_DYNSYM) { + continue; + } + found_dynsym = true; + if (dynsym->sh_link >= ehdr.e_shnum || + dynsym->sh_entsize != sizeof(Elf64_Sym) || + dynsym->sh_size % sizeof(Elf64_Sym) || + !range_is_valid(dynsym->sh_offset, dynsym->sh_size, + file_size)) { + reject(reason, reason_size, + "guest Cairo has an invalid dynamic symbol table%s", NULL); + goto out; + } + strtab = §ions[dynsym->sh_link]; + if (strtab->sh_type != SHT_STRTAB || !strtab->sh_size || + !range_is_valid(strtab->sh_offset, strtab->sh_size, + file_size)) { + reject(reason, reason_size, + "guest Cairo has an invalid dynamic string table%s", + NULL); + goto out; + } + symbols = malloc(dynsym->sh_size); + strings = malloc(strtab->sh_size); + if (!symbols || !strings || + !read_exact(file, symbols, dynsym->sh_size, + (long)dynsym->sh_offset) || + !read_exact(file, strings, strtab->sh_size, + (long)strtab->sh_offset)) { + free(symbols); + free(strings); + reject(reason, reason_size, + "cannot read guest Cairo dynamic symbols%s", NULL); + goto out; + } + + symbol_count = dynsym->sh_size / sizeof(Elf64_Sym); + for (size_t i = 0; i < symbol_count; i++) { + const Elf64_Sym *symbol = &symbols[i]; + const char *name; + unsigned type = ELF64_ST_TYPE(symbol->st_info); + unsigned binding = ELF64_ST_BIND(symbol->st_info); + + if (symbol->st_shndx == SHN_UNDEF || + (type != STT_FUNC && type != STT_GNU_IFUNC) || + (binding != STB_GLOBAL && binding != STB_WEAK) || + symbol->st_name >= strtab->sh_size) { + continue; + } + name = strings + symbol->st_name; + if (!memchr(name, '\0', strtab->sh_size - symbol->st_name)) { + free(symbols); + free(strings); + reject(reason, reason_size, + "guest Cairo has an unterminated dynamic symbol%s", + NULL); + goto out; + } + if (strncmp(name, "cairo_", 6)) { + continue; + } + found_cairo_symbol = true; + if (!cairo_symbol_is_supported(name)) { + snprintf(reason, reason_size, + "guest symbol '%s' has no safe wrapper", name); + free(symbols); + free(strings); + goto out; + } + if (!dlsym(host, name)) { + snprintf(reason, reason_size, + "host Cairo is missing guest symbol '%s'", name); + free(symbols); + free(strings); + goto out; + } + } + free(symbols); + free(strings); + } + + if (!found_dynsym) { + reject(reason, reason_size, + "guest Cairo has no inspectable dynamic symbol table%s", NULL); + goto out; + } + if (!found_cairo_symbol) { + reject(reason, reason_size, + "guest Cairo exports no Cairo functions%s", NULL); + goto out; + } + ok = true; + +out: + if (host) { + dlclose(host); + } + free(sections); + if (file) { + fclose(file); + } + return ok; +} diff --git a/target/i386/latx/context/wrappedcairo.c b/target/i386/latx/context/wrappedcairo.c new file mode 100644 index 0000000000..08ce60051b --- /dev/null +++ b/target/i386/latx/context/wrappedcairo.c @@ -0,0 +1,1350 @@ +/* + * This file is derived from Box64. + * + * SPDX-FileCopyrightText: 2020 ptitSeb + * SPDX-FileCopyrightText: 2026 LAT Project Authors + * + * SPDX-License-Identifier: MIT + */ + +#include "qemu/osdep.h" + +#include +#include +#include +#include + +#include "wrappedlibs.h" + +#include "box64context.h" +#include "bridge.h" +#include "callback.h" +#include "debug.h" +#include "fileutils.h" +#include "kzt-groups.h" +#include "librarian.h" +#include "library_private.h" +#include "myalign.h" +#include "wrappedcairo-preflight.h" +#include "wrapper.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + +const char *cairoName = "libcairo.so.2"; +#define LIBNAME cairo + +#include "generated/wrappedcairotypes.h" + +#include "wrappercallback.h" + +enum { + CAIRO_STATUS_SUCCESS = 0, + CAIRO_STATUS_NO_MEMORY = 1, + CAIRO_STATUS_FONT_TYPE_MISMATCH = 27, +}; + +/* All public Cairo ABI structures are passed by pointer. */ +typedef struct { double xx, yx, xy, yy, x0, y0; } cairo_matrix_abi_t; +typedef struct { double x_bearing, y_bearing, width, height, x_advance, + y_advance; } cairo_text_extents_abi_t; +typedef struct { double ascent, descent, height, max_x_advance, + max_y_advance; } cairo_font_extents_abi_t; +typedef struct { double x, y, width, height; } cairo_rectangle_abi_t; +typedef struct { int32_t x, y, width, height; } cairo_rectangle_int_abi_t; +typedef struct { unsigned long index; double x, y; } cairo_glyph_abi_t; +typedef struct { int32_t num_bytes, num_glyphs; } cairo_text_cluster_abi_t; +typedef union { + struct { int32_t type, length; } header; + struct { double x, y; } point; +} cairo_path_data_abi_t; +typedef struct { + int32_t status; + cairo_path_data_abi_t *data; + int32_t num_data; +} cairo_path_abi_t; + +_Static_assert(sizeof(cairo_matrix_abi_t) == 48, "cairo_matrix_t ABI"); +_Static_assert(sizeof(cairo_text_extents_abi_t) == 48, + "cairo_text_extents_t ABI"); +_Static_assert(sizeof(cairo_font_extents_abi_t) == 40, + "cairo_font_extents_t ABI"); +_Static_assert(sizeof(cairo_rectangle_abi_t) == 32, + "cairo_rectangle_t ABI"); +_Static_assert(sizeof(cairo_rectangle_int_abi_t) == 16, + "cairo_rectangle_int_t ABI"); +_Static_assert(sizeof(cairo_glyph_abi_t) == 24, "cairo_glyph_t ABI"); +_Static_assert(sizeof(cairo_text_cluster_abi_t) == 8, + "cairo_text_cluster_t ABI"); +_Static_assert(sizeof(cairo_path_data_abi_t) == 16, + "cairo_path_data_t ABI"); +_Static_assert(sizeof(cairo_path_abi_t) == 24, "cairo_path_t ABI"); + +#define CAIRO_CALLBACK_SLOT_COUNT 16 +#define CAIRO_CALLBACK_SLOT_LIST(X) \ + X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) \ + X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) + +typedef struct CairoCallbackSlot { + uintptr_t guest; + unsigned int references; +} CairoCallbackSlot; + +typedef enum CairoBindingKind { + CAIRO_BINDING_SURFACE_STREAM, + CAIRO_BINDING_DEVICE_STREAM, + CAIRO_BINDING_USER_INIT, + CAIRO_BINDING_USER_RENDER, + CAIRO_BINDING_USER_RENDER_COLOR, + CAIRO_BINDING_USER_TEXT_TO_GLYPHS, + CAIRO_BINDING_USER_UNICODE_TO_GLYPH, + CAIRO_BINDING_OBSERVER, + CAIRO_BINDING_RASTER_ACQUIRE, + CAIRO_BINDING_RASTER_RELEASE, + CAIRO_BINDING_RASTER_SNAPSHOT, + CAIRO_BINDING_RASTER_COPY, + CAIRO_BINDING_RASTER_FINISH, +} CairoBindingKind; + +typedef struct CairoCallbackBinding { + void *object; + CairoBindingKind kind; + uintptr_t guest; + CairoCallbackSlot *slots; + struct CairoCallbackBinding *next; +} CairoCallbackBinding; + +typedef enum CairoObjectKind { + CAIRO_OBJECT_SURFACE, + CAIRO_OBJECT_DEVICE, + CAIRO_OBJECT_FONT_FACE, + CAIRO_OBJECT_PATTERN, +} CairoObjectKind; + +typedef struct CairoObjectTracker { + void *object; + CairoObjectKind kind; + struct CairoObjectTracker *next; +} CairoObjectTracker; + +static GMutex cairo_callback_lock; +static CairoCallbackBinding *cairo_bindings; +static CairoObjectTracker *cairo_trackers; +static char cairo_surface_tracker_key; +static char cairo_device_tracker_key; +static char cairo_font_face_tracker_key; +static char cairo_pattern_tracker_key; + +static CairoCallbackSlot cairo_destroy_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_io_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_user_init_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_user_render_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_user_text_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_user_unicode_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_observer_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_raster_acquire_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_raster_release_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_raster_snapshot_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_raster_copy_slots[CAIRO_CALLBACK_SLOT_COUNT]; +static CairoCallbackSlot cairo_raster_finish_slots[CAIRO_CALLBACK_SLOT_COUNT]; + +static void cairo_tracker_destroy(void *data); + +static CairoObjectKind cairo_binding_object_kind(CairoBindingKind kind) +{ + switch (kind) { + case CAIRO_BINDING_SURFACE_STREAM: + case CAIRO_BINDING_OBSERVER: + return CAIRO_OBJECT_SURFACE; + case CAIRO_BINDING_DEVICE_STREAM: + return CAIRO_OBJECT_DEVICE; + case CAIRO_BINDING_USER_INIT: + case CAIRO_BINDING_USER_RENDER: + case CAIRO_BINDING_USER_RENDER_COLOR: + case CAIRO_BINDING_USER_TEXT_TO_GLYPHS: + case CAIRO_BINDING_USER_UNICODE_TO_GLYPH: + return CAIRO_OBJECT_FONT_FACE; + default: + return CAIRO_OBJECT_PATTERN; + } +} + +static bool cairo_binding_needs_tracker(CairoBindingKind kind) +{ + return kind < CAIRO_BINDING_RASTER_ACQUIRE || + kind > CAIRO_BINDING_RASTER_FINISH; +} + +static void *cairo_tracker_key(CairoObjectKind kind) +{ + switch (kind) { + case CAIRO_OBJECT_SURFACE: + return &cairo_surface_tracker_key; + case CAIRO_OBJECT_DEVICE: + return &cairo_device_tracker_key; + case CAIRO_OBJECT_FONT_FACE: + return &cairo_font_face_tracker_key; + case CAIRO_OBJECT_PATTERN: + return &cairo_pattern_tracker_key; + } + g_assert_not_reached(); +} + +static uint32_t cairo_set_tracker(CairoObjectTracker *tracker, void *data, + void *destroy) +{ + void *key = cairo_tracker_key(tracker->kind); + + switch (tracker->kind) { + case CAIRO_OBJECT_SURFACE: + return my->cairo_surface_set_user_data(tracker->object, key, + data, destroy); + case CAIRO_OBJECT_DEVICE: + return my->cairo_device_set_user_data(tracker->object, key, + data, destroy); + case CAIRO_OBJECT_FONT_FACE: + return my->cairo_font_face_set_user_data(tracker->object, key, + data, destroy); + case CAIRO_OBJECT_PATTERN: + return my->cairo_pattern_set_user_data(tracker->object, key, + data, destroy); + } + g_assert_not_reached(); +} + +static bool cairo_track_object_locked(void *object, CairoObjectKind kind) +{ + CairoObjectTracker *tracker; + + for (tracker = cairo_trackers; tracker; tracker = tracker->next) { + if (tracker->object == object) { + return true; + } + } + tracker = calloc(1, sizeof(*tracker)); + if (!tracker) { + return false; + } + tracker->object = object; + tracker->kind = kind; + if (cairo_set_tracker(tracker, tracker, cairo_tracker_destroy) != + CAIRO_STATUS_SUCCESS) { + free(tracker); + return false; + } + tracker->next = cairo_trackers; + cairo_trackers = tracker; + return true; +} + +static uintptr_t cairo_slot_guest(CairoCallbackSlot *slots, size_t index) +{ + uintptr_t guest; + + g_mutex_lock(&cairo_callback_lock); + guest = slots[index].guest; + g_mutex_unlock(&cairo_callback_lock); + return guest; +} + +static void cairo_slot_release_locked(CairoCallbackSlot *slots, + uintptr_t guest) +{ + if (!slots || !guest) { + return; + } + for (size_t i = 0; i < CAIRO_CALLBACK_SLOT_COUNT; i++) { + if (slots[i].guest != guest) { + continue; + } + if (slots[i].references && --slots[i].references == 0) { + slots[i].guest = 0; + } + return; + } +} + +static void cairo_slot_release(CairoCallbackSlot *slots, uintptr_t guest) +{ + g_mutex_lock(&cairo_callback_lock); + cairo_slot_release_locked(slots, guest); + g_mutex_unlock(&cairo_callback_lock); +} + +static void *cairo_slot_acquire(CairoCallbackSlot *slots, + void *const *thunks, void *callback, + const char *kind, + CairoCallbackSlot **managed_slots) +{ + void *native; + uintptr_t guest = (uintptr_t)callback; + + *managed_slots = NULL; + if (!callback) { + return NULL; + } + native = GetNativeFnc(guest); + if (native) { + return native; + } + + g_mutex_lock(&cairo_callback_lock); + for (size_t i = 0; i < CAIRO_CALLBACK_SLOT_COUNT; i++) { + if (slots[i].guest == guest) { + slots[i].references++; + *managed_slots = slots; + native = thunks[i]; + g_mutex_unlock(&cairo_callback_lock); + return native; + } + } + for (size_t i = 0; i < CAIRO_CALLBACK_SLOT_COUNT; i++) { + if (!slots[i].guest) { + slots[i].guest = guest; + slots[i].references = 1; + *managed_slots = slots; + native = thunks[i]; + g_mutex_unlock(&cairo_callback_lock); + return native; + } + } + g_mutex_unlock(&cairo_callback_lock); + kzt_groups_log_wrapper_limitation(cairoName, kind); + return NULL; +} + +static void *cairo_slot_acquire_forced(CairoCallbackSlot *slots, + void *const *thunks, void *callback, + const char *kind, + CairoCallbackSlot **managed_slots) +{ + void *native; + uintptr_t guest = (uintptr_t)callback; + + *managed_slots = NULL; + if (!callback) { + return NULL; + } + g_mutex_lock(&cairo_callback_lock); + for (size_t i = 0; i < CAIRO_CALLBACK_SLOT_COUNT; i++) { + if (slots[i].guest == guest) { + slots[i].references++; + *managed_slots = slots; + native = thunks[i]; + g_mutex_unlock(&cairo_callback_lock); + return native; + } + } + for (size_t i = 0; i < CAIRO_CALLBACK_SLOT_COUNT; i++) { + if (!slots[i].guest) { + slots[i].guest = guest; + slots[i].references = 1; + *managed_slots = slots; + native = thunks[i]; + g_mutex_unlock(&cairo_callback_lock); + return native; + } + } + g_mutex_unlock(&cairo_callback_lock); + kzt_groups_log_wrapper_limitation(cairoName, kind); + return NULL; +} + +static void cairo_binding_replace(void *object, CairoBindingKind kind, + void *guest, CairoCallbackSlot *slots) +{ + CairoCallbackBinding **cursor; + CairoCallbackBinding *binding = guest ? calloc(1, sizeof(*binding)) : NULL; + bool tracked = !guest; + + if (binding) { + binding->object = object; + binding->kind = kind; + binding->guest = (uintptr_t)guest; + binding->slots = slots; + } + + g_mutex_lock(&cairo_callback_lock); + if (guest && binding && cairo_binding_needs_tracker(kind)) { + tracked = cairo_track_object_locked( + object, cairo_binding_object_kind(kind)); + } else if (guest && binding) { + tracked = true; + } + cursor = &cairo_bindings; + while (*cursor) { + CairoCallbackBinding *old = *cursor; + + if (old->object != object || old->kind != kind) { + cursor = &old->next; + continue; + } + *cursor = old->next; + cairo_slot_release_locked(old->slots, old->guest); + free(old); + } + if (binding && tracked) { + binding->next = cairo_bindings; + cairo_bindings = binding; + } else { + free(binding); + } + g_mutex_unlock(&cairo_callback_lock); + + if (guest && (!binding || !tracked)) { + kzt_groups_log_wrapper_limitation( + cairoName, "cannot track Cairo callback lifetime; retaining its " + "native thunk slot"); + } +} + +static void cairo_binding_add(void *object, CairoBindingKind kind, + void *guest, CairoCallbackSlot *slots) +{ + CairoCallbackBinding *binding; + + if (!guest) { + return; + } + binding = calloc(1, sizeof(*binding)); + if (!binding) { + kzt_groups_log_wrapper_limitation( + cairoName, "cannot track Cairo callback lifetime"); + return; + } + binding->object = object; + binding->kind = kind; + binding->guest = (uintptr_t)guest; + binding->slots = slots; + + g_mutex_lock(&cairo_callback_lock); + if (cairo_binding_needs_tracker(kind) && + !cairo_track_object_locked(object, + cairo_binding_object_kind(kind))) { + g_mutex_unlock(&cairo_callback_lock); + free(binding); + kzt_groups_log_wrapper_limitation( + cairoName, "cannot track Cairo callback lifetime; retaining its " + "native thunk slot"); + return; + } + binding->next = cairo_bindings; + cairo_bindings = binding; + g_mutex_unlock(&cairo_callback_lock); +} + +static void *cairo_binding_guest(void *object, CairoBindingKind kind) +{ + uintptr_t guest = 0; + + g_mutex_lock(&cairo_callback_lock); + for (CairoCallbackBinding *binding = cairo_bindings; binding; + binding = binding->next) { + if (binding->object == object && binding->kind == kind) { + guest = binding->guest; + break; + } + } + g_mutex_unlock(&cairo_callback_lock); + return (void *)guest; +} + +static void cairo_binding_release_object(void *object) +{ + CairoCallbackBinding **cursor; + + g_mutex_lock(&cairo_callback_lock); + cursor = &cairo_bindings; + while (*cursor) { + CairoCallbackBinding *binding = *cursor; + + if (binding->object != object) { + cursor = &binding->next; + continue; + } + *cursor = binding->next; + cairo_slot_release_locked(binding->slots, binding->guest); + free(binding); + } + g_mutex_unlock(&cairo_callback_lock); +} + +static void cairo_tracker_destroy(void *data) +{ + CairoObjectTracker *tracker = data; + CairoObjectTracker **cursor; + + g_mutex_lock(&cairo_callback_lock); + cursor = &cairo_trackers; + while (*cursor && *cursor != tracker) { + cursor = &(*cursor)->next; + } + if (*cursor) { + *cursor = tracker->next; + } + g_mutex_unlock(&cairo_callback_lock); + cairo_binding_release_object(tracker->object); + free(tracker); +} + +static bool cairo_binding_is_raster(CairoBindingKind kind) +{ + return kind >= CAIRO_BINDING_RASTER_ACQUIRE && + kind <= CAIRO_BINDING_RASTER_FINISH; +} + +static bool cairo_binding_clone_raster(void *source, void *destination) +{ + CairoCallbackBinding *copies = NULL; + CairoCallbackBinding *copy; + + g_mutex_lock(&cairo_callback_lock); + for (CairoCallbackBinding *binding = cairo_bindings; binding; + binding = binding->next) { + if (binding->object != source || + !cairo_binding_is_raster(binding->kind)) { + continue; + } + /* + * The guest copy callback may replace a callback on the destination. + * Keep that replacement instead of cloning the source binding over it. + */ + for (copy = cairo_bindings; copy; copy = copy->next) { + if (copy->object == destination && + copy->kind == binding->kind) { + break; + } + } + if (copy) { + continue; + } + copy = calloc(1, sizeof(*copy)); + if (!copy) { + while ((copy = copies)) { + copies = copy->next; + free(copy); + } + g_mutex_unlock(&cairo_callback_lock); + kzt_groups_log_wrapper_limitation( + cairoName, "cannot clone raster callback lifetime"); + return false; + } + *copy = *binding; + copy->object = destination; + copy->next = copies; + copies = copy; + } + + while ((copy = copies)) { + copies = copy->next; + if (copy->slots) { + for (size_t i = 0; i < CAIRO_CALLBACK_SLOT_COUNT; i++) { + if (copy->slots[i].guest == copy->guest) { + copy->slots[i].references++; + break; + } + } + } + copy->next = cairo_bindings; + cairo_bindings = copy; + } + g_mutex_unlock(&cairo_callback_lock); + return true; +} + +#define DEFINE_DESTROY_THUNK(N) \ + static void cairo_destroy_thunk_##N(void *data) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_destroy_slots, N); \ + if (guest) { \ + RunFunctionFmt(guest, "p", data); \ + cairo_slot_release(cairo_destroy_slots, guest); \ + } \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_DESTROY_THUNK) +#undef DEFINE_DESTROY_THUNK + +#define DEFINE_IO_THUNK(N) \ + static uint32_t cairo_io_thunk_##N(void *closure, void *data, uint32_t length) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_io_slots, N); \ + return guest ? (uint32_t)RunFunctionFmt(guest, "ppu", closure, data, length) \ + : CAIRO_STATUS_NO_MEMORY; \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_IO_THUNK) +#undef DEFINE_IO_THUNK + +#define DEFINE_USER_INIT_THUNK(N) \ + static uint32_t cairo_user_init_thunk_##N(void *font, void *cr, void *extents) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_user_init_slots, N); \ + return guest ? (uint32_t)RunFunctionFmt(guest, "ppp", font, cr, extents) \ + : CAIRO_STATUS_NO_MEMORY; \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_USER_INIT_THUNK) +#undef DEFINE_USER_INIT_THUNK + +#define DEFINE_USER_RENDER_THUNK(N) \ + static uint32_t cairo_user_render_thunk_##N(void *font, unsigned long glyph, \ + void *cr, void *extents) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_user_render_slots, N); \ + return guest ? (uint32_t)RunFunctionFmt(guest, "pLpp", font, glyph, cr, extents) \ + : CAIRO_STATUS_NO_MEMORY; \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_USER_RENDER_THUNK) +#undef DEFINE_USER_RENDER_THUNK + +#define DEFINE_USER_TEXT_THUNK(N) \ + static uint32_t cairo_user_text_thunk_##N(void *font, void *utf8, int length, \ + void *glyphs, void *num_glyphs, \ + void *clusters, void *num_clusters, \ + void *flags) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_user_text_slots, N); \ + return guest ? (uint32_t)RunFunctionFmt(guest, "ppippppp", font, utf8, \ + length, glyphs, num_glyphs, clusters, \ + num_clusters, flags) \ + : CAIRO_STATUS_NO_MEMORY; \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_USER_TEXT_THUNK) +#undef DEFINE_USER_TEXT_THUNK + +#define DEFINE_USER_UNICODE_THUNK(N) \ + static uint32_t cairo_user_unicode_thunk_##N(void *font, unsigned long unicode, \ + void *glyph) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_user_unicode_slots, N); \ + return guest ? (uint32_t)RunFunctionFmt(guest, "pLp", font, unicode, glyph) \ + : CAIRO_STATUS_NO_MEMORY; \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_USER_UNICODE_THUNK) +#undef DEFINE_USER_UNICODE_THUNK + +#define DEFINE_OBSERVER_THUNK(N) \ + static void cairo_observer_thunk_##N(void *observer, void *target, void *data) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_observer_slots, N); \ + if (guest) RunFunctionFmt(guest, "ppp", observer, target, data); \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_OBSERVER_THUNK) +#undef DEFINE_OBSERVER_THUNK + +#define DEFINE_RASTER_ACQUIRE_THUNK(N) \ + static void *cairo_raster_acquire_thunk_##N(void *pattern, void *data, \ + void *target, void *extents) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_raster_acquire_slots, N); \ + return guest ? (void *)(uintptr_t)RunFunctionFmt(guest, "pppp", pattern, data, \ + target, extents) : NULL; \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_RASTER_ACQUIRE_THUNK) +#undef DEFINE_RASTER_ACQUIRE_THUNK + +#define DEFINE_RASTER_RELEASE_THUNK(N) \ + static void cairo_raster_release_thunk_##N(void *pattern, void *data, void *surface) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_raster_release_slots, N); \ + if (guest) RunFunctionFmt(guest, "ppp", pattern, data, surface); \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_RASTER_RELEASE_THUNK) +#undef DEFINE_RASTER_RELEASE_THUNK + +#define DEFINE_RASTER_SNAPSHOT_THUNK(N) \ + static uint32_t cairo_raster_snapshot_thunk_##N(void *pattern, void *data) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_raster_snapshot_slots, N); \ + return guest ? (uint32_t)RunFunctionFmt(guest, "pp", pattern, data) \ + : CAIRO_STATUS_NO_MEMORY; \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_RASTER_SNAPSHOT_THUNK) +#undef DEFINE_RASTER_SNAPSHOT_THUNK + +#define DEFINE_RASTER_COPY_THUNK(N) \ + static uint32_t cairo_raster_copy_thunk_##N(void *pattern, void *data, void *other) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_raster_copy_slots, N); \ + uint32_t status = guest \ + ? (uint32_t)RunFunctionFmt(guest, "ppp", pattern, data, other) \ + : CAIRO_STATUS_NO_MEMORY; \ + if (status == CAIRO_STATUS_SUCCESS && \ + !cairo_binding_clone_raster(other, pattern)) \ + status = CAIRO_STATUS_NO_MEMORY; \ + return status; \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_RASTER_COPY_THUNK) +#undef DEFINE_RASTER_COPY_THUNK + +static void cairo_raster_finish_cleanup(void *pattern, void *data) +{ + (void)data; + cairo_binding_release_object(pattern); +} + +#define DEFINE_RASTER_FINISH_THUNK(N) \ + static void cairo_raster_finish_thunk_##N(void *pattern, void *data) \ + { \ + uintptr_t guest = cairo_slot_guest(cairo_raster_finish_slots, N); \ + void *native = GetNativeFnc(guest); \ + if (native) \ + ((void (*)(void *, void *))native)(pattern, data); \ + else if (guest) \ + RunFunctionFmt(guest, "pp", pattern, data); \ + cairo_raster_finish_cleanup(pattern, data); \ + } +CAIRO_CALLBACK_SLOT_LIST(DEFINE_RASTER_FINISH_THUNK) +#undef DEFINE_RASTER_FINISH_THUNK + +#define DESTROY_THUNK_ADDRESS(N) (void *)cairo_destroy_thunk_##N, +static void *const cairo_destroy_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(DESTROY_THUNK_ADDRESS) +}; +#undef DESTROY_THUNK_ADDRESS +#define IO_THUNK_ADDRESS(N) (void *)cairo_io_thunk_##N, +static void *const cairo_io_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(IO_THUNK_ADDRESS) +}; +#undef IO_THUNK_ADDRESS +#define USER_INIT_THUNK_ADDRESS(N) (void *)cairo_user_init_thunk_##N, +static void *const cairo_user_init_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(USER_INIT_THUNK_ADDRESS) +}; +#undef USER_INIT_THUNK_ADDRESS +#define USER_RENDER_THUNK_ADDRESS(N) (void *)cairo_user_render_thunk_##N, +static void *const cairo_user_render_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(USER_RENDER_THUNK_ADDRESS) +}; +#undef USER_RENDER_THUNK_ADDRESS +#define USER_TEXT_THUNK_ADDRESS(N) (void *)cairo_user_text_thunk_##N, +static void *const cairo_user_text_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(USER_TEXT_THUNK_ADDRESS) +}; +#undef USER_TEXT_THUNK_ADDRESS +#define USER_UNICODE_THUNK_ADDRESS(N) (void *)cairo_user_unicode_thunk_##N, +static void *const cairo_user_unicode_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(USER_UNICODE_THUNK_ADDRESS) +}; +#undef USER_UNICODE_THUNK_ADDRESS +#define OBSERVER_THUNK_ADDRESS(N) (void *)cairo_observer_thunk_##N, +static void *const cairo_observer_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(OBSERVER_THUNK_ADDRESS) +}; +#undef OBSERVER_THUNK_ADDRESS +#define RASTER_ACQUIRE_THUNK_ADDRESS(N) (void *)cairo_raster_acquire_thunk_##N, +static void *const cairo_raster_acquire_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(RASTER_ACQUIRE_THUNK_ADDRESS) +}; +#undef RASTER_ACQUIRE_THUNK_ADDRESS +#define RASTER_RELEASE_THUNK_ADDRESS(N) (void *)cairo_raster_release_thunk_##N, +static void *const cairo_raster_release_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(RASTER_RELEASE_THUNK_ADDRESS) +}; +#undef RASTER_RELEASE_THUNK_ADDRESS +#define RASTER_SNAPSHOT_THUNK_ADDRESS(N) (void *)cairo_raster_snapshot_thunk_##N, +static void *const cairo_raster_snapshot_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(RASTER_SNAPSHOT_THUNK_ADDRESS) +}; +#undef RASTER_SNAPSHOT_THUNK_ADDRESS +#define RASTER_COPY_THUNK_ADDRESS(N) (void *)cairo_raster_copy_thunk_##N, +static void *const cairo_raster_copy_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(RASTER_COPY_THUNK_ADDRESS) +}; +#undef RASTER_COPY_THUNK_ADDRESS +#define RASTER_FINISH_THUNK_ADDRESS(N) (void *)cairo_raster_finish_thunk_##N, +static void *const cairo_raster_finish_thunks[] = { + CAIRO_CALLBACK_SLOT_LIST(RASTER_FINISH_THUNK_ADDRESS) +}; +#undef RASTER_FINISH_THUNK_ADDRESS + +static void *cairo_acquire_destroy(void *callback, CairoCallbackSlot **slots) +{ + return cairo_slot_acquire(cairo_destroy_slots, cairo_destroy_thunks, + callback, "destroy callback slots exhausted", + slots); +} + +static void *cairo_acquire_io(void *callback, CairoCallbackSlot **slots) +{ + return cairo_slot_acquire(cairo_io_slots, cairo_io_thunks, callback, + "read/write callback slots exhausted", slots); +} + +#define DEFINE_USER_CALLBACK_ACCESSOR(name, slot_array, thunk_array, message) \ + static void *cairo_acquire_##name(void *callback, CairoCallbackSlot **slots) \ + { \ + return cairo_slot_acquire(slot_array, thunk_array, callback, message, slots); \ + } +DEFINE_USER_CALLBACK_ACCESSOR(user_init, cairo_user_init_slots, + cairo_user_init_thunks, + "user-font init callback slots exhausted") +DEFINE_USER_CALLBACK_ACCESSOR(user_render, cairo_user_render_slots, + cairo_user_render_thunks, + "user-font render callback slots exhausted") +DEFINE_USER_CALLBACK_ACCESSOR(user_text, cairo_user_text_slots, + cairo_user_text_thunks, + "user-font text callback slots exhausted") +DEFINE_USER_CALLBACK_ACCESSOR(user_unicode, cairo_user_unicode_slots, + cairo_user_unicode_thunks, + "user-font unicode callback slots exhausted") +DEFINE_USER_CALLBACK_ACCESSOR(observer, cairo_observer_slots, + cairo_observer_thunks, + "observer callback slots exhausted") +DEFINE_USER_CALLBACK_ACCESSOR(raster_acquire, cairo_raster_acquire_slots, + cairo_raster_acquire_thunks, + "raster acquire callback slots exhausted") +DEFINE_USER_CALLBACK_ACCESSOR(raster_release, cairo_raster_release_slots, + cairo_raster_release_thunks, + "raster release callback slots exhausted") +DEFINE_USER_CALLBACK_ACCESSOR(raster_snapshot, cairo_raster_snapshot_slots, + cairo_raster_snapshot_thunks, + "raster snapshot callback slots exhausted") +DEFINE_USER_CALLBACK_ACCESSOR(raster_copy, cairo_raster_copy_slots, + cairo_raster_copy_thunks, + "raster copy callback slots exhausted") +#undef DEFINE_USER_CALLBACK_ACCESSOR + +static void *cairo_acquire_raster_finish(void *callback, + CairoCallbackSlot **slots) +{ + return cairo_slot_acquire_forced( + cairo_raster_finish_slots, cairo_raster_finish_thunks, callback, + "raster finish callback slots exhausted", slots); +} + +static void cairo_ensure_raster_cleanup(void *pattern) +{ + void *finish = my->cairo_raster_source_pattern_get_finish(pattern); + + if (!finish) { + my->cairo_raster_source_pattern_set_finish( + pattern, cairo_raster_finish_cleanup); + } +} + +static void cairo_release_sync_callback(CairoCallbackSlot *slots, void *guest) +{ + if (slots) { + cairo_slot_release(slots, (uintptr_t)guest); + } +} + +static uint32_t cairo_io_failure(void *closure, void *data, uint32_t length) +{ + (void)closure; + (void)data; + (void)length; + return CAIRO_STATUS_NO_MEMORY; +} + +static uint32_t cairo_ft_interop_failure(void *font, void *cr, void *extents) +{ + (void)font; + (void)cr; + (void)extents; + return CAIRO_STATUS_FONT_TYPE_MISMATCH; +} + +/* + * LAT does not yet wrap FreeType or Fontconfig. Their opaque guest objects + * cannot be passed to host Cairo, and a host FT_Face cannot be returned to + * guest code. Return a valid host Cairo face that fails explicitly on use. + */ +static void *cairo_ft_unsupported_font_face(void) +{ + void *font_face = my->cairo_user_font_face_create(); + + if (font_face) { + my->cairo_user_font_face_set_init_func(font_face, + cairo_ft_interop_failure); + } + kzt_groups_log_wrapper_limitation( + cairoName, "Cairo FreeType/Fontconfig interop requires native " + "FreeType and Fontconfig wrappers"); + return font_face; +} + +EXPORT void *my_cairo_user_font_face_create(void) +{ + return my->cairo_user_font_face_create(); +} + +EXPORT void *my_cairo_ft_font_face_create_for_ft_face(void *face, + int32_t load_flags) +{ + (void)face; + (void)load_flags; + return cairo_ft_unsupported_font_face(); +} + +EXPORT void *my_cairo_ft_font_face_create_for_pattern(void *pattern) +{ + (void)pattern; + return cairo_ft_unsupported_font_face(); +} + +EXPORT void my_cairo_ft_font_options_substitute(void *pattern, void *options) +{ + (void)pattern; + (void)options; + kzt_groups_log_wrapper_limitation( + cairoName, "Cairo Fontconfig interop requires a native Fontconfig " + "wrapper"); +} + +EXPORT void *my_cairo_ft_scaled_font_lock_face(void *scaled_font) +{ + (void)scaled_font; + kzt_groups_log_wrapper_limitation( + cairoName, "returning a host FT_Face to guest code is unsupported"); + return NULL; +} + +EXPORT void my_cairo_ft_scaled_font_unlock_face(void *scaled_font) +{ + (void)scaled_font; +} + +#define DEFINE_USER_DATA_WRAPPER(name, object_type) \ + EXPORT uint32_t my_##name(void *object, void *key, void *data, void *destroy) \ + { \ + CairoCallbackSlot *slots; \ + void *native = cairo_acquire_destroy(destroy, &slots); \ + uint32_t status; \ + if (destroy && !native) return CAIRO_STATUS_NO_MEMORY; \ + status = my->name(object, key, data, native); \ + if (status != CAIRO_STATUS_SUCCESS) \ + cairo_release_sync_callback(slots, destroy); \ + return status; \ + } +DEFINE_USER_DATA_WRAPPER(cairo_device_set_user_data, device) +DEFINE_USER_DATA_WRAPPER(cairo_font_face_set_user_data, font_face) +DEFINE_USER_DATA_WRAPPER(cairo_pattern_set_user_data, pattern) +DEFINE_USER_DATA_WRAPPER(cairo_scaled_font_set_user_data, scaled_font) +DEFINE_USER_DATA_WRAPPER(cairo_set_user_data, context) +DEFINE_USER_DATA_WRAPPER(cairo_surface_set_user_data, surface) +#undef DEFINE_USER_DATA_WRAPPER + +EXPORT uint32_t my_cairo_surface_set_mime_data(void *surface, void *mime, + void *data, uintptr_t length, + void *destroy, void *closure) +{ + CairoCallbackSlot *slots; + void *native = cairo_acquire_destroy(destroy, &slots); + uint32_t status; + + if (destroy && !native) { + return CAIRO_STATUS_NO_MEMORY; + } + status = my->cairo_surface_set_mime_data(surface, mime, data, length, + native, closure); + if (status != CAIRO_STATUS_SUCCESS) { + cairo_release_sync_callback(slots, destroy); + } + return status; +} + +static void *cairo_stream_surface(void *(*create)(void *, void *, double, double), + void *callback, void *closure, + double width, double height) +{ + CairoCallbackSlot *slots; + void *native = cairo_acquire_io(callback, &slots); + void *surface; + + if (callback && !native) { + return create(cairo_io_failure, NULL, width, height); + } + surface = create(native, closure, width, height); + if (surface && slots) { + cairo_binding_add(surface, CAIRO_BINDING_SURFACE_STREAM, + callback, slots); + } else { + cairo_release_sync_callback(slots, callback); + } + return surface; +} + +EXPORT void *my_cairo_pdf_surface_create_for_stream(void *callback, + void *closure, + double width, + double height) +{ + return cairo_stream_surface(my->cairo_pdf_surface_create_for_stream, + callback, closure, width, height); +} + +EXPORT void *my_cairo_ps_surface_create_for_stream(void *callback, + void *closure, + double width, + double height) +{ + return cairo_stream_surface(my->cairo_ps_surface_create_for_stream, + callback, closure, width, height); +} + +EXPORT void *my_cairo_svg_surface_create_for_stream(void *callback, + void *closure, + double width, + double height) +{ + return cairo_stream_surface(my->cairo_svg_surface_create_for_stream, + callback, closure, width, height); +} + +EXPORT void *my_cairo_script_create_for_stream(void *callback, void *closure) +{ + CairoCallbackSlot *slots; + void *native = cairo_acquire_io(callback, &slots); + void *device; + + if (callback && !native) { + return my->cairo_script_create_for_stream(cairo_io_failure, NULL); + } + device = my->cairo_script_create_for_stream(native, closure); + if (device && slots) { + cairo_binding_add(device, CAIRO_BINDING_DEVICE_STREAM, + callback, slots); + } else { + cairo_release_sync_callback(slots, callback); + } + return device; +} + +EXPORT void *my_cairo_image_surface_create_from_png_stream(void *callback, + void *closure) +{ + CairoCallbackSlot *slots; + void *native = cairo_acquire_io(callback, &slots); + void *surface; + + if (callback && !native) { + return my->cairo_image_surface_create_from_png_stream( + cairo_io_failure, NULL); + } + surface = my->cairo_image_surface_create_from_png_stream(native, closure); + cairo_release_sync_callback(slots, callback); + return surface; +} + +EXPORT uint32_t my_cairo_surface_write_to_png_stream(void *surface, + void *callback, + void *closure) +{ + CairoCallbackSlot *slots; + void *native = cairo_acquire_io(callback, &slots); + uint32_t status; + + if (callback && !native) { + return CAIRO_STATUS_NO_MEMORY; + } + status = my->cairo_surface_write_to_png_stream(surface, native, closure); + cairo_release_sync_callback(slots, callback); + return status; +} + +EXPORT uint32_t my_cairo_surface_observer_print(void *surface, + void *callback, + void *closure) +{ + CairoCallbackSlot *slots; + void *native = cairo_acquire_io(callback, &slots); + uint32_t status; + + if (callback && !native) { + return CAIRO_STATUS_NO_MEMORY; + } + status = my->cairo_surface_observer_print(surface, native, closure); + cairo_release_sync_callback(slots, callback); + return status; +} + +EXPORT uint32_t my_cairo_device_observer_print(void *device, + void *callback, + void *closure) +{ + CairoCallbackSlot *slots; + void *native = cairo_acquire_io(callback, &slots); + uint32_t status; + + if (callback && !native) { + return CAIRO_STATUS_NO_MEMORY; + } + status = my->cairo_device_observer_print(device, native, closure); + cairo_release_sync_callback(slots, callback); + return status; +} + +#define DEFINE_OBSERVER_ADD_WRAPPER(name) \ + EXPORT uint32_t my_##name(void *surface, void *callback, void *data) \ + { \ + CairoCallbackSlot *slots; \ + void *native = cairo_acquire_observer(callback, &slots); \ + uint32_t status; \ + if (callback && !native) return CAIRO_STATUS_NO_MEMORY; \ + status = my->name(surface, native, data); \ + if (status == CAIRO_STATUS_SUCCESS && slots) \ + cairo_binding_add(surface, CAIRO_BINDING_OBSERVER, callback, slots); \ + else \ + cairo_release_sync_callback(slots, callback); \ + return status; \ + } +DEFINE_OBSERVER_ADD_WRAPPER(cairo_surface_observer_add_fill_callback) +DEFINE_OBSERVER_ADD_WRAPPER(cairo_surface_observer_add_finish_callback) +DEFINE_OBSERVER_ADD_WRAPPER(cairo_surface_observer_add_flush_callback) +DEFINE_OBSERVER_ADD_WRAPPER(cairo_surface_observer_add_glyphs_callback) +DEFINE_OBSERVER_ADD_WRAPPER(cairo_surface_observer_add_mask_callback) +DEFINE_OBSERVER_ADD_WRAPPER(cairo_surface_observer_add_paint_callback) +DEFINE_OBSERVER_ADD_WRAPPER(cairo_surface_observer_add_stroke_callback) +#undef DEFINE_OBSERVER_ADD_WRAPPER + +static void cairo_set_user_callback(void *font_face, void *callback, + CairoBindingKind kind, + void *(*acquire)(void *, CairoCallbackSlot **), + void (*setter)(void *, void *)) +{ + CairoCallbackSlot *slots; + void *native = acquire(callback, &slots); + + if (callback && !native) { + return; + } + setter(font_face, native); + cairo_binding_replace(font_face, kind, callback, slots); +} + +EXPORT void my_cairo_user_font_face_set_init_func(void *font_face, + void *callback) +{ + cairo_set_user_callback(font_face, callback, CAIRO_BINDING_USER_INIT, + cairo_acquire_user_init, + my->cairo_user_font_face_set_init_func); +} + +EXPORT void my_cairo_user_font_face_set_render_glyph_func(void *font_face, + void *callback) +{ + cairo_set_user_callback(font_face, callback, CAIRO_BINDING_USER_RENDER, + cairo_acquire_user_render, + my->cairo_user_font_face_set_render_glyph_func); +} + +EXPORT void my_cairo_user_font_face_set_render_color_glyph_func( + void *font_face, void *callback) +{ + cairo_set_user_callback( + font_face, callback, CAIRO_BINDING_USER_RENDER_COLOR, + cairo_acquire_user_render, + my->cairo_user_font_face_set_render_color_glyph_func); +} + +EXPORT void my_cairo_user_font_face_set_text_to_glyphs_func( + void *font_face, void *callback) +{ + cairo_set_user_callback( + font_face, callback, CAIRO_BINDING_USER_TEXT_TO_GLYPHS, + cairo_acquire_user_text, + my->cairo_user_font_face_set_text_to_glyphs_func); +} + +EXPORT void my_cairo_user_font_face_set_unicode_to_glyph_func( + void *font_face, void *callback) +{ + cairo_set_user_callback( + font_face, callback, CAIRO_BINDING_USER_UNICODE_TO_GLYPH, + cairo_acquire_user_unicode, + my->cairo_user_font_face_set_unicode_to_glyph_func); +} + +EXPORT void *my_cairo_user_font_face_get_init_func(void *font_face) +{ + return cairo_binding_guest(font_face, CAIRO_BINDING_USER_INIT); +} + +EXPORT void *my_cairo_user_font_face_get_render_glyph_func(void *font_face) +{ + return cairo_binding_guest(font_face, CAIRO_BINDING_USER_RENDER); +} + +EXPORT void *my_cairo_user_font_face_get_render_color_glyph_func( + void *font_face) +{ + return cairo_binding_guest(font_face, CAIRO_BINDING_USER_RENDER_COLOR); +} + +EXPORT void *my_cairo_user_font_face_get_text_to_glyphs_func(void *font_face) +{ + return cairo_binding_guest(font_face, + CAIRO_BINDING_USER_TEXT_TO_GLYPHS); +} + +EXPORT void *my_cairo_user_font_face_get_unicode_to_glyph_func(void *font_face) +{ + return cairo_binding_guest(font_face, + CAIRO_BINDING_USER_UNICODE_TO_GLYPH); +} + +EXPORT void my_cairo_raster_source_pattern_set_acquire(void *pattern, + void *acquire, + void *release) +{ + CairoCallbackSlot *acquire_slots; + CairoCallbackSlot *release_slots; + void *native_acquire = cairo_acquire_raster_acquire(acquire, + &acquire_slots); + void *native_release = cairo_acquire_raster_release(release, + &release_slots); + + if ((acquire && !native_acquire) || (release && !native_release)) { + cairo_release_sync_callback(acquire_slots, acquire); + cairo_release_sync_callback(release_slots, release); + return; + } + cairo_ensure_raster_cleanup(pattern); + my->cairo_raster_source_pattern_set_acquire(pattern, native_acquire, + native_release); + cairo_binding_replace(pattern, CAIRO_BINDING_RASTER_ACQUIRE, + acquire, acquire_slots); + cairo_binding_replace(pattern, CAIRO_BINDING_RASTER_RELEASE, + release, release_slots); +} + +EXPORT void my_cairo_raster_source_pattern_get_acquire(void *pattern, + void **acquire, + void **release) +{ + if (acquire) { + *acquire = cairo_binding_guest(pattern, + CAIRO_BINDING_RASTER_ACQUIRE); + } + if (release) { + *release = cairo_binding_guest(pattern, + CAIRO_BINDING_RASTER_RELEASE); + } +} + +#define DEFINE_RASTER_SETTER(name, kind, acquire_callback) \ + EXPORT void my_##name(void *pattern, void *callback) \ + { \ + CairoCallbackSlot *slots; \ + void *native = acquire_callback(callback, &slots); \ + if (callback && !native) return; \ + cairo_ensure_raster_cleanup(pattern); \ + my->name(pattern, native); \ + cairo_binding_replace(pattern, kind, callback, slots); \ + } +DEFINE_RASTER_SETTER(cairo_raster_source_pattern_set_snapshot, + CAIRO_BINDING_RASTER_SNAPSHOT, + cairo_acquire_raster_snapshot) +DEFINE_RASTER_SETTER(cairo_raster_source_pattern_set_copy, + CAIRO_BINDING_RASTER_COPY, + cairo_acquire_raster_copy) +#undef DEFINE_RASTER_SETTER + +EXPORT void my_cairo_raster_source_pattern_set_finish(void *pattern, + void *callback) +{ + CairoCallbackSlot *slots; + void *native = cairo_acquire_raster_finish(callback, &slots); + + if (callback && !native) { + return; + } + my->cairo_raster_source_pattern_set_finish( + pattern, native ? native : cairo_raster_finish_cleanup); + cairo_binding_replace(pattern, CAIRO_BINDING_RASTER_FINISH, + callback, slots); +} + +EXPORT void *my_cairo_raster_source_pattern_get_snapshot(void *pattern) +{ + return cairo_binding_guest(pattern, CAIRO_BINDING_RASTER_SNAPSHOT); +} + +EXPORT void *my_cairo_raster_source_pattern_get_copy(void *pattern) +{ + return cairo_binding_guest(pattern, CAIRO_BINDING_RASTER_COPY); +} + +EXPORT void *my_cairo_raster_source_pattern_get_finish(void *pattern) +{ + return cairo_binding_guest(pattern, CAIRO_BINDING_RASTER_FINISH); +} + +EXPORT void *my_cairo_xcb_device_get_connection(void *device) +{ + void *native = my->cairo_xcb_device_get_connection(device); + void *guest = add_xcb_connection(native); + + if (native && guest == native) { + kzt_groups_log_wrapper_limitation( + cairoName, "cannot represent host XCB connection in guest"); + return NULL; + } + return guest; +} + +static void cairo_callbacks_clear(void) +{ + CairoCallbackBinding *binding; + CairoObjectTracker *tracker; + + for (;;) { + g_mutex_lock(&cairo_callback_lock); + tracker = cairo_trackers; + g_mutex_unlock(&cairo_callback_lock); + if (!tracker) { + break; + } + if (cairo_set_tracker(tracker, NULL, NULL) != + CAIRO_STATUS_SUCCESS) { + kzt_groups_log_wrapper_limitation( + cairoName, "cannot detach Cairo callback lifetime tracker"); + return; + } + } + + g_mutex_lock(&cairo_callback_lock); + while ((binding = cairo_bindings)) { + cairo_bindings = binding->next; + free(binding); + } + memset(cairo_destroy_slots, 0, sizeof(cairo_destroy_slots)); + memset(cairo_io_slots, 0, sizeof(cairo_io_slots)); + memset(cairo_user_init_slots, 0, sizeof(cairo_user_init_slots)); + memset(cairo_user_render_slots, 0, sizeof(cairo_user_render_slots)); + memset(cairo_user_text_slots, 0, sizeof(cairo_user_text_slots)); + memset(cairo_user_unicode_slots, 0, sizeof(cairo_user_unicode_slots)); + memset(cairo_observer_slots, 0, sizeof(cairo_observer_slots)); + memset(cairo_raster_acquire_slots, 0, + sizeof(cairo_raster_acquire_slots)); + memset(cairo_raster_release_slots, 0, + sizeof(cairo_raster_release_slots)); + memset(cairo_raster_snapshot_slots, 0, + sizeof(cairo_raster_snapshot_slots)); + memset(cairo_raster_copy_slots, 0, sizeof(cairo_raster_copy_slots)); + memset(cairo_raster_finish_slots, 0, + sizeof(cairo_raster_finish_slots)); + g_mutex_unlock(&cairo_callback_lock); +} + +#define PRE_INIT_GUEST \ + do { \ + char reason[256]; \ + char *guest_path = ResolveFile(lib->path, &box64->box64_ld_lib); \ + bool safe = latx_cairo_preflight_guest(guest_path, cairoName, reason, \ + sizeof(reason)); \ + box_free(guest_path); \ + if (!safe) { \ + kzt_groups_log_wrapper_rejection(cairoName, reason); \ + return -1; \ + } \ + } while (0); + +#define CUSTOM_INIT \ + getMy(lib); + +#define CUSTOM_FINI \ + cairo_callbacks_clear(); \ + freeMy(); + +#include "wrappedlib_init.h" diff --git a/target/i386/latx/context/wrapper.c b/target/i386/latx/context/wrapper.c index 0696386d26..3cf3efc5cd 100644 --- a/target/i386/latx/context/wrapper.c +++ b/target/i386/latx/context/wrapper.c @@ -79,8 +79,8 @@ extern void* my__IO_2_1_stderr_; #define R_R8 cpu->regs[R_R8] #define R_R9 cpu->regs[R_R9] #define R_RSP cpu->regs[R_ESP] -#define R_XMMD(r) (*(double*)&cpu->xmm_regs->ZMM_D(r)) -#define R_XMMS(r) (*(float*)&cpu->xmm_regs->ZMM_S(r)) +#define R_XMMD(r) (*(double *)&cpu->xmm_regs[(r)].ZMM_Q(0)) +#define R_XMMS(r) (*(float *)&cpu->xmm_regs[(r)].ZMM_L(0)) #define ST0val (cpu->fpregs[cpu->fpstt].d) #else #define __CPU CPUX86State *cpu = (CPUX86State *)lsenv->cpu_state; @@ -96,7 +96,7 @@ extern void* my__IO_2_1_stderr_; #endif typedef uintptr_t (*vFE_t)(void); -typedef int64_t (*iFii_t)(int64_t, int64_t); +typedef int32_t (*iFii_t)(int32_t, int32_t); typedef void* (*pFpiL_t)(void*, int64_t, uintptr_t); typedef void* (*pFppl_t)(void*, void*, intptr_t); typedef void* (*pFppL_t)(void*, void*, uintptr_t); @@ -122,6 +122,7 @@ void vFppiip(uintptr_t fcn) { __CPU; vFppiip_t fn = (vFppiip_t)fcn; fn((void*)R_ void vFppiiip(uintptr_t fcn) { __CPU; vFppiiip_t fn = (vFppiiip_t)fcn; fn((void*)R_RDI, (void*)R_RSI, (int32_t)R_RDX, (int32_t)R_RCX, (int32_t)R_R8, (void*)R_R9); DEBUG_LOG; (void)cpu; } void vFppii(uintptr_t fcn) { __CPU; vFppii_t fn = (vFppii_t)fcn; fn((void*)R_RDI, (void*)R_RSI, (int32_t)R_RDX, (int32_t)R_RCX); DEBUG_LOG; (void)cpu; } void vFE(uintptr_t fcn) { __CPU; vFE_t fn = (vFE_t)fcn; fn(); DEBUG_LOG; (void)cpu; } +void iFii(uintptr_t fcn) { __CPU; iFii_t fn = (iFii_t)fcn; R_RAX=(int32_t)fn((int32_t)R_RDI, (int32_t)R_RSI); DEBUG_LOG; (void)cpu; } void pFppL(uintptr_t fcn) { __CPU; pFppL_t fn = (pFppL_t)fcn; R_RAX = (uintptr_t)fn((void*)R_RDI, (void*)R_RSI, (uintptr_t)R_RDX); DEBUG_LOG; (void)cpu; } typedef void (*vFv_t)(void); @@ -1484,6 +1485,38 @@ typedef uint32_t (*uFbuuWW_t)(void*, uint32_t, uint32_t, uint16_t, uint16_t); typedef uint32_t (*uFbuuuup_t)(void*, uint32_t, uint32_t, uint32_t, uint32_t, void*); typedef void* (*pFbuuUUU_t)(void*, uint32_t, uint32_t, uint64_t, uint64_t, uint64_t); typedef void* (*pFbuuuuuwwuuuuUUUup_t)(void*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, int16_t, int16_t, uint32_t, uint32_t, uint32_t, uint32_t, uint64_t, uint64_t, uint64_t, uint32_t, void*); +/* Cairo public ABI signatures. */ +typedef int32_t (*iFpdd_t)(void*, double, double); +typedef void* (*pFiii_t)(int32_t, int32_t, int32_t); +typedef void* (*pFpdd_t)(void*, double, double); +typedef void (*vFpuii_t)(void*, uint32_t, int32_t, int32_t); +typedef void (*vFpudd_t)(void*, uint32_t, double, double); +typedef void (*vFpLii_t)(void*, uintptr_t, int32_t, int32_t); +typedef void (*vFppid_t)(void*, void*, int32_t, double); +typedef void* (*pFdddd_t)(double, double, double, double); +typedef void* (*pFpuii_t)(void*, uint32_t, int32_t, int32_t); +typedef void* (*pFpudd_t)(void*, uint32_t, double, double); +typedef void (*vFpuddd_t)(void*, uint32_t, double, double, double); +typedef void (*vFpdddd_t)(void*, double, double, double, double); +typedef uint32_t (*uFpuupp_t)(void*, uint32_t, uint32_t, void*, void*); +typedef uint32_t (*uFppppp_t)(void*, void*, void*, void*, void*); +typedef void* (*pFpiiii_t)(void*, int32_t, int32_t, int32_t, int32_t); +typedef void* (*pFpdddd_t)(void*, double, double, double, double); +typedef void* (*pFpLpii_t)(void*, uintptr_t, void*, int32_t, int32_t); +typedef void* (*pFbupii_t)(void*, uint32_t, void*, int32_t, int32_t); +typedef void* (*pFbpuii_t)(void*, void*, uint32_t, int32_t, int32_t); +typedef void (*vFpudddd_t)(void*, uint32_t, double, double, double, double); +typedef void (*vFpddddd_t)(void*, double, double, double, double, double); +typedef uint32_t (*uFpppLpp_t)(void*, void*, void*, uintptr_t, void*, void*); +typedef void* (*pFpLppii_t)(void*, uintptr_t, void*, void*, int32_t, int32_t); +typedef void* (*pFbpupii_t)(void*, void*, uint32_t, void*, int32_t, int32_t); +typedef uint32_t (*uFpippppp_t)(void*, int32_t, void*, void*, void*, void*, void*); +typedef uint32_t (*uFpuupppp_t)(void*, uint32_t, uint32_t, void*, void*, void*, void*); +typedef uint32_t (*uFppppppp_t)(void*, void*, void*, void*, void*, void*, void*); +typedef void (*vFppipipiu_t)(void*, void*, int32_t, void*, int32_t, void*, int32_t, uint32_t); +typedef uint32_t (*uFpddpippppp_t)(void*, double, double, void*, int32_t, void*, void*, void*, void*, void*); +typedef int32_t (*iFpippu_t)(void*, int32_t, void*, void*, uint32_t); +typedef uint32_t (*uFpupppp_t)(void*, uint32_t, void*, void*, void*, void*); //endxcbV2 typedef void (*vFpLi_t)(void*, uintptr_t, int32_t); typedef void (*vFpLL_t)(void*, uintptr_t, uintptr_t); @@ -3091,6 +3124,37 @@ void uFbuuWW(uintptr_t fcn) { __CPU; uFbuuWW_t fn = (uFbuuWW_t)fcn; void *aligne void uFbuuuup(uintptr_t fcn) { __CPU; uFbuuuup_t fn = (uFbuuuup_t)fcn; void *aligned_xcb = align_xcb_connection((void*)R_RDI); R_RAX=(uint32_t)fn(aligned_xcb, (uint32_t)R_RSI, (uint32_t)R_RDX, (uint32_t)R_RCX, (uint32_t)R_R8, (void*)R_R9); unalign_xcb_connection(aligned_xcb, (void*)R_RDI); DEBUG_LOG; (void)cpu; } void pFbuuUUU(uintptr_t fcn) { __CPU; pFbuuUUU_t fn = (pFbuuUUU_t)fcn; void *aligned_xcb = align_xcb_connection((void*)R_RDI); R_RAX=(uintptr_t)fn(aligned_xcb, (uint32_t)R_RSI, (uint32_t)R_RDX, (uint64_t)R_RCX, (uint64_t)R_R8, (uint64_t)R_R9); unalign_xcb_connection(aligned_xcb, (void*)R_RDI); DEBUG_LOG; (void)cpu; } void pFbuuuuuwwuuuuUUUup(uintptr_t fcn) { __CPU; pFbuuuuuwwuuuuUUUup_t fn = (pFbuuuuuwwuuuuUUUup_t)fcn; void *aligned_xcb = align_xcb_connection((void*)R_RDI); R_RAX=(uintptr_t)fn(aligned_xcb, (uint32_t)R_RSI, (uint32_t)R_RDX, (uint32_t)R_RCX, (uint32_t)R_R8, (uint32_t)R_R9, *(int16_t*)(R_RSP + 8), *(int16_t*)(R_RSP + 16), *(uint32_t*)(R_RSP + 24), *(uint32_t*)(R_RSP + 32), *(uint32_t*)(R_RSP + 40), *(uint32_t*)(R_RSP + 48), *(uint64_t*)(R_RSP + 56), *(uint64_t*)(R_RSP + 64), *(uint64_t*)(R_RSP + 72), *(uint32_t*)(R_RSP + 80), *(void**)(R_RSP + 88)); unalign_xcb_connection(aligned_xcb, (void*)R_RDI); DEBUG_LOG; (void)cpu; } +void iFpdd(uintptr_t fcn) { __CPU; iFpdd_t fn = (iFpdd_t)fcn; R_RAX=(int32_t)fn((void*)R_RDI, R_XMMD(0), R_XMMD(1)); DEBUG_LOG; (void)cpu; } +void pFiii(uintptr_t fcn) { __CPU; pFiii_t fn = (pFiii_t)fcn; R_RAX=(uintptr_t)fn((int32_t)R_RDI, (int32_t)R_RSI, (int32_t)R_RDX); DEBUG_LOG; (void)cpu; } +void pFpdd(uintptr_t fcn) { __CPU; pFpdd_t fn = (pFpdd_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, R_XMMD(0), R_XMMD(1)); DEBUG_LOG; (void)cpu; } +void vFpuii(uintptr_t fcn) { __CPU; vFpuii_t fn = (vFpuii_t)fcn; fn((void*)R_RDI, (uint32_t)R_RSI, (int32_t)R_RDX, (int32_t)R_RCX); DEBUG_LOG; (void)cpu; } +void vFpudd(uintptr_t fcn) { __CPU; vFpudd_t fn = (vFpudd_t)fcn; fn((void*)R_RDI, (uint32_t)R_RSI, R_XMMD(0), R_XMMD(1)); DEBUG_LOG; (void)cpu; } +void vFpLii(uintptr_t fcn) { __CPU; vFpLii_t fn = (vFpLii_t)fcn; fn((void*)R_RDI, (uintptr_t)R_RSI, (int32_t)R_RDX, (int32_t)R_RCX); DEBUG_LOG; (void)cpu; } +void vFppid(uintptr_t fcn) { __CPU; vFppid_t fn = (vFppid_t)fcn; fn((void*)R_RDI, (void*)R_RSI, (int32_t)R_RDX, R_XMMD(0)); DEBUG_LOG; (void)cpu; } +void pFdddd(uintptr_t fcn) { __CPU; pFdddd_t fn = (pFdddd_t)fcn; R_RAX=(uintptr_t)fn(R_XMMD(0), R_XMMD(1), R_XMMD(2), R_XMMD(3)); DEBUG_LOG; (void)cpu; } +void pFpuii(uintptr_t fcn) { __CPU; pFpuii_t fn = (pFpuii_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (uint32_t)R_RSI, (int32_t)R_RDX, (int32_t)R_RCX); DEBUG_LOG; (void)cpu; } +void pFpudd(uintptr_t fcn) { __CPU; pFpudd_t fn = (pFpudd_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (uint32_t)R_RSI, R_XMMD(0), R_XMMD(1)); DEBUG_LOG; (void)cpu; } +void vFpuddd(uintptr_t fcn) { __CPU; vFpuddd_t fn = (vFpuddd_t)fcn; fn((void*)R_RDI, (uint32_t)R_RSI, R_XMMD(0), R_XMMD(1), R_XMMD(2)); DEBUG_LOG; (void)cpu; } +void vFpdddd(uintptr_t fcn) { __CPU; vFpdddd_t fn = (vFpdddd_t)fcn; fn((void*)R_RDI, R_XMMD(0), R_XMMD(1), R_XMMD(2), R_XMMD(3)); DEBUG_LOG; (void)cpu; } +void uFpuupp(uintptr_t fcn) { __CPU; uFpuupp_t fn = (uFpuupp_t)fcn; R_RAX=(uint32_t)fn((void*)R_RDI, (uint32_t)R_RSI, (uint32_t)R_RDX, (void*)R_RCX, (void*)R_R8); DEBUG_LOG; (void)cpu; } +void uFppppp(uintptr_t fcn) { __CPU; uFppppp_t fn = (uFppppp_t)fcn; R_RAX=(uint32_t)fn((void*)R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8); DEBUG_LOG; (void)cpu; } +void pFpiiii(uintptr_t fcn) { __CPU; pFpiiii_t fn = (pFpiiii_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (int32_t)R_RSI, (int32_t)R_RDX, (int32_t)R_RCX, (int32_t)R_R8); DEBUG_LOG; (void)cpu; } +void pFpdddd(uintptr_t fcn) { __CPU; pFpdddd_t fn = (pFpdddd_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, R_XMMD(0), R_XMMD(1), R_XMMD(2), R_XMMD(3)); DEBUG_LOG; (void)cpu; } +void pFpLpii(uintptr_t fcn) { __CPU; pFpLpii_t fn = (pFpLpii_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (uintptr_t)R_RSI, (void*)R_RDX, (int32_t)R_RCX, (int32_t)R_R8); DEBUG_LOG; (void)cpu; } +void pFbupii(uintptr_t fcn) { __CPU; pFbupii_t fn = (pFbupii_t)fcn; void *aligned_xcb = align_xcb_connection((void*)R_RDI); R_RAX=(uintptr_t)fn(aligned_xcb, (uint32_t)R_RSI, (void*)R_RDX, (int32_t)R_RCX, (int32_t)R_R8); unalign_xcb_connection(aligned_xcb, (void*)R_RDI); DEBUG_LOG; (void)cpu; } +void pFbpuii(uintptr_t fcn) { __CPU; pFbpuii_t fn = (pFbpuii_t)fcn; void *aligned_xcb = align_xcb_connection((void*)R_RDI); R_RAX=(uintptr_t)fn(aligned_xcb, (void*)R_RSI, (uint32_t)R_RDX, (int32_t)R_RCX, (int32_t)R_R8); unalign_xcb_connection(aligned_xcb, (void*)R_RDI); DEBUG_LOG; (void)cpu; } +void vFpudddd(uintptr_t fcn) { __CPU; vFpudddd_t fn = (vFpudddd_t)fcn; fn((void*)R_RDI, (uint32_t)R_RSI, R_XMMD(0), R_XMMD(1), R_XMMD(2), R_XMMD(3)); DEBUG_LOG; (void)cpu; } +void vFpddddd(uintptr_t fcn) { __CPU; vFpddddd_t fn = (vFpddddd_t)fcn; fn((void*)R_RDI, R_XMMD(0), R_XMMD(1), R_XMMD(2), R_XMMD(3), R_XMMD(4)); DEBUG_LOG; (void)cpu; } +void uFpppLpp(uintptr_t fcn) { __CPU; uFpppLpp_t fn = (uFpppLpp_t)fcn; R_RAX=(uint32_t)fn((void*)R_RDI, (void*)R_RSI, (void*)R_RDX, (uintptr_t)R_RCX, (void*)R_R8, (void*)R_R9); DEBUG_LOG; (void)cpu; } +void pFpLppii(uintptr_t fcn) { __CPU; pFpLppii_t fn = (pFpLppii_t)fcn; R_RAX=(uintptr_t)fn((void*)R_RDI, (uintptr_t)R_RSI, (void*)R_RDX, (void*)R_RCX, (int32_t)R_R8, (int32_t)R_R9); DEBUG_LOG; (void)cpu; } +void pFbpupii(uintptr_t fcn) { __CPU; pFbpupii_t fn = (pFbpupii_t)fcn; void *aligned_xcb = align_xcb_connection((void*)R_RDI); R_RAX=(uintptr_t)fn(aligned_xcb, (void*)R_RSI, (uint32_t)R_RDX, (void*)R_RCX, (int32_t)R_R8, (int32_t)R_R9); unalign_xcb_connection(aligned_xcb, (void*)R_RDI); DEBUG_LOG; (void)cpu; } +void uFpippppp(uintptr_t fcn) { __CPU; uFpippppp_t fn = (uFpippppp_t)fcn; R_RAX=(uint32_t)fn((void*)R_RDI, (int32_t)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9, *(void**)(R_RSP + 8)); DEBUG_LOG; (void)cpu; } +void uFpuupppp(uintptr_t fcn) { __CPU; uFpuupppp_t fn = (uFpuupppp_t)fcn; R_RAX=(uint32_t)fn((void*)R_RDI, (uint32_t)R_RSI, (uint32_t)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9, *(void**)(R_RSP + 8)); DEBUG_LOG; (void)cpu; } +void uFppppppp(uintptr_t fcn) { __CPU; uFppppppp_t fn = (uFppppppp_t)fcn; R_RAX=(uint32_t)fn((void*)R_RDI, (void*)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9, *(void**)(R_RSP + 8)); DEBUG_LOG; (void)cpu; } +void vFppipipiu(uintptr_t fcn) { __CPU; vFppipipiu_t fn = (vFppipipiu_t)fcn; fn((void*)R_RDI, (void*)R_RSI, (int32_t)R_RDX, (void*)R_RCX, (int32_t)R_R8, (void*)R_R9, *(int32_t*)(R_RSP + 8), *(uint32_t*)(R_RSP + 16)); DEBUG_LOG; (void)cpu; } +void uFpddpippppp(uintptr_t fcn) { __CPU; uFpddpippppp_t fn = (uFpddpippppp_t)fcn; R_RAX=(uint32_t)fn((void*)R_RDI, R_XMMD(0), R_XMMD(1), (void*)R_RSI, (int32_t)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9, *(void**)(R_RSP + 8), *(void**)(R_RSP + 16)); DEBUG_LOG; (void)cpu; } +void iFpippu(uintptr_t fcn) { __CPU; iFpippu_t fn = (iFpippu_t)fcn; R_RAX=(int32_t)fn((void*)R_RDI, (int32_t)R_RSI, (void*)R_RDX, (void*)R_RCX, (uint32_t)R_R8); DEBUG_LOG; (void)cpu; } +void uFpupppp(uintptr_t fcn) { __CPU; uFpupppp_t fn = (uFpupppp_t)fcn; R_RAX=(uint32_t)fn((void*)R_RDI, (uint32_t)R_RSI, (void*)R_RDX, (void*)R_RCX, (void*)R_R8, (void*)R_R9); DEBUG_LOG; (void)cpu; } //xcbV2end #undef R_RAX #undef R_RDI diff --git a/target/i386/latx/include/generated/wrappedcairodefs.h b/target/i386/latx/include/generated/wrappedcairodefs.h new file mode 100644 index 0000000000..53949694f4 --- /dev/null +++ b/target/i386/latx/include/generated/wrappedcairodefs.h @@ -0,0 +1,19 @@ +/******************************************************************* + * File automatically generated by rebuild_wrappers.py (v2.2.0.18) * + *******************************************************************/ +#ifndef __wrappedcairoDEFS_H_ +#define __wrappedcairoDEFS_H_ + +#define uFEppp uFppp +#define uFEpppp uFpppp +#define pFEpi pFpi +#define pFEpp pFpp +#define pFEppdd pFppdd +#define vFEppp vFppp +#define pFEp pFp +#define vFEpp vFpp +#define vFEp vFp +#define uFEpppLpp uFpppLpp +#define pFEv pFv + +#endif // __wrappedcairoDEFS_H_ diff --git a/target/i386/latx/include/generated/wrappedcairotypes.h b/target/i386/latx/include/generated/wrappedcairotypes.h new file mode 100644 index 0000000000..d9a5b9e54a --- /dev/null +++ b/target/i386/latx/include/generated/wrappedcairotypes.h @@ -0,0 +1,76 @@ +/******************************************************************* + * File automatically generated by rebuild_wrappers.py (v2.2.0.18) * + *******************************************************************/ +#ifndef __wrappedcairoTYPES_H_ +#define __wrappedcairoTYPES_H_ + +#ifndef LIBNAME +#error You should only #include this file inside a wrapped*.c file +#endif +#ifndef ADDED_FUNCTIONS +#define ADDED_FUNCTIONS() +#endif + +typedef uint32_t (*uFppp_t)(void*, void*, void*); +typedef uint32_t (*uFpppp_t)(void*, void*, void*, void*); +typedef void* (*pFpi_t)(void*, int32_t); +typedef void* (*pFpp_t)(void*, void*); +typedef void* (*pFppdd_t)(void*, void*, double, double); +typedef void* (*pFp_t)(void*); +typedef void (*vFppp_t)(void*, void*, void*); +typedef void (*vFpp_t)(void*, void*); +typedef void (*vFp_t)(void*); +typedef uint32_t (*uFpppLpp_t)(void*, void*, void*, uintptr_t, void*, void*); +typedef uint32_t (*uFp_t)(void*); +typedef void* (*pFv_t)(void); + +#define SUPER() ADDED_FUNCTIONS() \ + GO(cairo_device_observer_print, uFppp_t) \ + GO(cairo_device_set_user_data, uFpppp_t) \ + GO(cairo_font_face_set_user_data, uFpppp_t) \ + GO(cairo_ft_font_face_create_for_ft_face, pFpi_t) \ + GO(cairo_ft_font_face_create_for_pattern, pFp_t) \ + GO(cairo_ft_font_options_substitute, vFpp_t) \ + GO(cairo_ft_scaled_font_lock_face, pFp_t) \ + GO(cairo_ft_scaled_font_unlock_face, vFp_t) \ + GO(cairo_image_surface_create_from_png_stream, pFpp_t) \ + GO(cairo_pattern_set_user_data, uFpppp_t) \ + GO(cairo_pdf_surface_create_for_stream, pFppdd_t) \ + GO(cairo_ps_surface_create_for_stream, pFppdd_t) \ + GO(cairo_raster_source_pattern_get_acquire, vFppp_t) \ + GO(cairo_raster_source_pattern_get_copy, pFp_t) \ + GO(cairo_raster_source_pattern_get_finish, pFp_t) \ + GO(cairo_raster_source_pattern_get_snapshot, pFp_t) \ + GO(cairo_raster_source_pattern_set_acquire, vFppp_t) \ + GO(cairo_raster_source_pattern_set_copy, vFpp_t) \ + GO(cairo_raster_source_pattern_set_finish, vFpp_t) \ + GO(cairo_raster_source_pattern_set_snapshot, vFpp_t) \ + GO(cairo_scaled_font_set_user_data, uFpppp_t) \ + GO(cairo_script_create_for_stream, pFpp_t) \ + GO(cairo_set_user_data, uFpppp_t) \ + GO(cairo_surface_observer_add_fill_callback, uFppp_t) \ + GO(cairo_surface_observer_add_finish_callback, uFppp_t) \ + GO(cairo_surface_observer_add_flush_callback, uFppp_t) \ + GO(cairo_surface_observer_add_glyphs_callback, uFppp_t) \ + GO(cairo_surface_observer_add_mask_callback, uFppp_t) \ + GO(cairo_surface_observer_add_paint_callback, uFppp_t) \ + GO(cairo_surface_observer_add_stroke_callback, uFppp_t) \ + GO(cairo_surface_observer_print, uFppp_t) \ + GO(cairo_surface_set_mime_data, uFpppLpp_t) \ + GO(cairo_surface_set_user_data, uFpppp_t) \ + GO(cairo_surface_write_to_png_stream, uFppp_t) \ + GO(cairo_svg_surface_create_for_stream, pFppdd_t) \ + GO(cairo_user_font_face_create, pFv_t) \ + GO(cairo_user_font_face_get_init_func, pFp_t) \ + GO(cairo_user_font_face_get_render_color_glyph_func, pFp_t) \ + GO(cairo_user_font_face_get_render_glyph_func, pFp_t) \ + GO(cairo_user_font_face_get_text_to_glyphs_func, pFp_t) \ + GO(cairo_user_font_face_get_unicode_to_glyph_func, pFp_t) \ + GO(cairo_user_font_face_set_init_func, vFpp_t) \ + GO(cairo_user_font_face_set_render_color_glyph_func, vFpp_t) \ + GO(cairo_user_font_face_set_render_glyph_func, vFpp_t) \ + GO(cairo_user_font_face_set_text_to_glyphs_func, vFpp_t) \ + GO(cairo_user_font_face_set_unicode_to_glyph_func, vFpp_t) \ + GO(cairo_xcb_device_get_connection, pFp_t) + +#endif // __wrappedcairoTYPES_H_ diff --git a/target/i386/latx/include/generated/wrappedcairoundefs.h b/target/i386/latx/include/generated/wrappedcairoundefs.h new file mode 100644 index 0000000000..57bac1489d --- /dev/null +++ b/target/i386/latx/include/generated/wrappedcairoundefs.h @@ -0,0 +1,19 @@ +/******************************************************************* + * File automatically generated by rebuild_wrappers.py (v2.2.0.18) * + *******************************************************************/ +#ifndef __wrappedcairoUNDEFS_H_ +#define __wrappedcairoUNDEFS_H_ + +#undef uFEppp +#undef uFEpppp +#undef pFEpi +#undef pFEpp +#undef pFEppdd +#undef vFEppp +#undef pFEp +#undef vFEpp +#undef vFEp +#undef uFEpppLpp +#undef pFEv + +#endif // __wrappedcairoUNDEFS_H_ diff --git a/target/i386/latx/include/kzt-group-list.h b/target/i386/latx/include/kzt-group-list.h index 6c7caab659..69f02499db 100644 --- a/target/i386/latx/include/kzt-group-list.h +++ b/target/i386/latx/include/kzt-group-list.h @@ -23,6 +23,7 @@ X(X11, "x11", 1, STABLE, KZT_GROUP_CORE) \ X(GL, "gl", 2, STABLE, KZT_GROUP_CORE | KZT_GROUP_X11) \ X(VULKAN, "vulkan", 3, STABLE, KZT_GROUP_CORE | KZT_GROUP_X11) \ - X(VAAPI, "vaapi", 4, STABLE, KZT_GROUP_CORE | KZT_GROUP_X11) + X(VAAPI, "vaapi", 4, STABLE, KZT_GROUP_CORE | KZT_GROUP_X11) \ + X(CAIRO, "cairo", 5, EXPERIMENTAL, KZT_GROUP_CORE | KZT_GROUP_X11) #endif /* LATX_KZT_GROUP_LIST_H */ diff --git a/target/i386/latx/include/kzt-groups.h b/target/i386/latx/include/kzt-groups.h index 0986c548e7..5010b069e2 100644 --- a/target/i386/latx/include/kzt-groups.h +++ b/target/i386/latx/include/kzt-groups.h @@ -50,5 +50,9 @@ bool kzt_group_is_enabled(KztLibraryGroup group); bool kzt_library_is_enabled(const char *soname); const char *kzt_groups_last_error(void); void kzt_groups_log_library(const char *soname, bool enabled); +void kzt_groups_log_wrapper_rejection(const char *soname, + const char *reason); +void kzt_groups_log_wrapper_limitation(const char *soname, + const char *reason); #endif /* LATX_KZT_GROUPS_H */ diff --git a/target/i386/latx/include/library_list.h b/target/i386/latx/include/library_list.h index 35a1ed3e78..e80675e1bc 100755 --- a/target/i386/latx/include/library_list.h +++ b/target/i386/latx/include/library_list.h @@ -62,6 +62,7 @@ GO("libxcb-sync.so.1", libxcbsync, KZT_GROUP_X11) GO("libxcb-xinerama.so.0", libxcbxinerama, KZT_GROUP_X11) GO("libxcb-xinput.so.0", libxcbxinput, KZT_GROUP_X11) GO("libxcb-present.so.0", libxcbpresent, KZT_GROUP_X11) +GO("libcairo.so.2", cairo, KZT_GROUP_CAIRO) GOALIAS("libxcb-cursor.so", libxcbcursor, KZT_GROUP_X11) @@ -73,6 +74,7 @@ GOALIAS("libxcb-sync.so", libxcbsync, KZT_GROUP_X11) GOALIAS("libxcb-xinerama.so", libxcbxinerama, KZT_GROUP_X11) GOALIAS("libxcb-xinput.so", libxcbxinput, KZT_GROUP_X11) GOALIAS("libxcb-present.so", libxcbpresent, KZT_GROUP_X11) +GOALIAS("libcairo.so", cairo, KZT_GROUP_CAIRO) GOALIAS("libvulkan.so", vulkan, KZT_GROUP_VULKAN) GOALIAS("libEGL.so", libegl, KZT_GROUP_GL) #ifndef CONFIG_LOONGARCH_NEW_WORLD diff --git a/target/i386/latx/include/wrappedcairo-preflight.h b/target/i386/latx/include/wrappedcairo-preflight.h new file mode 100644 index 0000000000..9f60c2da26 --- /dev/null +++ b/target/i386/latx/include/wrappedcairo-preflight.h @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2026 LAT Project Authors + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#ifndef LATX_WRAPPEDCAIRO_PREFLIGHT_H +#define LATX_WRAPPEDCAIRO_PREFLIGHT_H + +#include +#include + +bool latx_cairo_preflight_guest(const char *guest_path, + const char *host_soname, + char *reason, size_t reason_size); + +#endif /* LATX_WRAPPEDCAIRO_PREFLIGHT_H */ diff --git a/target/i386/latx/include/wrappedcairo_private.h b/target/i386/latx/include/wrappedcairo_private.h new file mode 100644 index 0000000000..4d2f6d6383 --- /dev/null +++ b/target/i386/latx/include/wrappedcairo_private.h @@ -0,0 +1,436 @@ +/* + * This file is derived from Box64. + * + * SPDX-FileCopyrightText: 2020 ptitSeb + * + * SPDX-License-Identifier: MIT + */ + +#if !(defined(GO) && defined(GOM) && defined(GO2) && defined(DATA)) +#error Meh... +#endif + +GO(cairo_append_path, vFpp) +GO(cairo_arc, vFpddddd) +GO(cairo_arc_negative, vFpddddd) +GO(cairo_clip, vFp) +GO(cairo_clip_extents, vFppppp) +GO(cairo_clip_preserve, vFp) +GO(cairo_close_path, vFp) +GO(cairo_copy_clip_rectangle_list, pFp) +GO(cairo_copy_page, vFp) +GO(cairo_copy_path, pFp) +GO(cairo_copy_path_flat, pFp) +GO(cairo_create, pFp) +GO(cairo_curve_to, vFpdddddd) +GO(cairo_debug_reset_static_data, vFv) +GO(cairo_destroy, vFp) +GO(cairo_device_acquire, uFp) +GO(cairo_device_destroy, vFp) +GO(cairo_device_finish, vFp) +GO(cairo_device_flush, vFp) +GO(cairo_device_get_reference_count, uFp) +GO(cairo_device_get_type, iFp) +GO(cairo_device_get_user_data, pFpp) +GO(cairo_device_observer_elapsed, dFp) +GO(cairo_device_observer_fill_elapsed, dFp) +GO(cairo_device_observer_glyphs_elapsed, dFp) +GO(cairo_device_observer_mask_elapsed, dFp) +GO(cairo_device_observer_paint_elapsed, dFp) +GOM(cairo_device_observer_print, uFEppp) +GO(cairo_device_observer_stroke_elapsed, dFp) +GO(cairo_device_reference, pFp) +GO(cairo_device_release, vFp) +GOM(cairo_device_set_user_data, uFEpppp) +GO(cairo_device_status, uFp) +GO(cairo_device_to_user, vFppp) +GO(cairo_device_to_user_distance, vFppp) +GO(cairo_fill, vFp) +GO(cairo_fill_extents, vFppppp) +GO(cairo_fill_preserve, vFp) +GO(cairo_font_extents, vFpp) +GO(cairo_font_face_destroy, vFp) +GO(cairo_font_face_get_reference_count, uFp) +GO(cairo_font_face_get_type, uFp) +GO(cairo_font_face_get_user_data, pFpp) +GO(cairo_font_face_reference, pFp) +GOM(cairo_font_face_set_user_data, uFEpppp) +GO(cairo_font_face_status, uFp) +GO(cairo_font_options_copy, pFp) +GO(cairo_font_options_create, pFv) +GO(cairo_font_options_destroy, vFp) +GO(cairo_font_options_equal, iFpp) +GO(cairo_font_options_get_antialias, uFp) +GO(cairo_font_options_get_color_mode, uFp) +GO(cairo_font_options_get_color_palette, uFp) +GO(cairo_font_options_get_custom_palette_color, uFpupppp) +GO(cairo_font_options_get_hint_metrics, uFp) +GO(cairo_font_options_get_hint_style, uFp) +GO(cairo_font_options_get_subpixel_order, uFp) +GO(cairo_font_options_get_variations, pFp) +GO(cairo_font_options_hash, LFp) +GO(cairo_font_options_merge, vFpp) +GO(cairo_font_options_set_antialias, vFpu) +GO(cairo_font_options_set_color_mode, vFpu) +GO(cairo_font_options_set_color_palette, vFpu) +GO(cairo_font_options_set_custom_palette_color, vFpudddd) +GO(cairo_font_options_set_hint_metrics, vFpu) +GO(cairo_font_options_set_hint_style, vFpu) +GO(cairo_font_options_set_subpixel_order, vFpu) +GO(cairo_font_options_set_variations, vFpp) +GO(cairo_font_options_status, uFp) +GO(cairo_format_stride_for_width, iFii) +GOM(cairo_ft_font_face_create_for_ft_face, pFEpi) +GOM(cairo_ft_font_face_create_for_pattern, pFEp) +GO(cairo_ft_font_face_get_synthesize, uFp) +GO(cairo_ft_font_face_set_synthesize, vFpu) +GO(cairo_ft_font_face_unset_synthesize, vFpu) +GOM(cairo_ft_font_options_substitute, vFEpp) +GOM(cairo_ft_scaled_font_lock_face, pFEp) +GOM(cairo_ft_scaled_font_unlock_face, vFEp) +GO(cairo_get_antialias, uFp) +GO(cairo_get_current_point, vFppp) +GO(cairo_get_dash, vFppp) +GO(cairo_get_dash_count, iFp) +GO(cairo_get_fill_rule, uFp) +GO(cairo_get_font_face, pFp) +GO(cairo_get_font_matrix, vFpp) +GO(cairo_get_font_options, vFpp) +GO(cairo_get_group_target, pFp) +GO(cairo_get_hairline, iFp) +GO(cairo_get_line_cap, uFp) +GO(cairo_get_line_join, uFp) +GO(cairo_get_line_width, dFp) +GO(cairo_get_matrix, vFpp) +GO(cairo_get_miter_limit, dFp) +GO(cairo_get_operator, uFp) +GO(cairo_get_reference_count, uFp) +GO(cairo_get_scaled_font, pFp) +GO(cairo_get_source, pFp) +GO(cairo_get_target, pFp) +GO(cairo_get_tolerance, dFp) +GO(cairo_get_user_data, pFpp) +GO(cairo_glyph_allocate, pFi) +GO(cairo_glyph_extents, vFppip) +GO(cairo_glyph_free, vFp) +GO(cairo_glyph_path, vFppi) +GO(cairo_has_current_point, iFp) +GO(cairo_identity_matrix, vFp) +GO(cairo_image_surface_create, pFiii) +GO(cairo_image_surface_create_for_data, pFpiiii) +GO(cairo_image_surface_create_from_png, pFp) +GOM(cairo_image_surface_create_from_png_stream, pFEpp) +GO(cairo_image_surface_get_data, pFp) +GO(cairo_image_surface_get_format, iFp) +GO(cairo_image_surface_get_height, iFp) +GO(cairo_image_surface_get_stride, iFp) +GO(cairo_image_surface_get_width, iFp) +GO(cairo_in_clip, iFpdd) +GO(cairo_in_fill, iFpdd) +GO(cairo_in_stroke, iFpdd) +GO(cairo_line_to, vFpdd) +GO(cairo_mask, vFpp) +GO(cairo_mask_surface, vFppdd) +GO(cairo_matrix_init, vFpdddddd) +GO(cairo_matrix_init_identity, vFp) +GO(cairo_matrix_init_rotate, vFpd) +GO(cairo_matrix_init_scale, vFpdd) +GO(cairo_matrix_init_translate, vFpdd) +GO(cairo_matrix_invert, uFp) +GO(cairo_matrix_multiply, vFppp) +GO(cairo_matrix_rotate, vFpd) +GO(cairo_matrix_scale, vFpdd) +GO(cairo_matrix_transform_distance, vFppp) +GO(cairo_matrix_transform_point, vFppp) +GO(cairo_matrix_translate, vFpdd) +GO(cairo_mesh_pattern_begin_patch, vFp) +GO(cairo_mesh_pattern_curve_to, vFpdddddd) +GO(cairo_mesh_pattern_end_patch, vFp) +GO(cairo_mesh_pattern_get_control_point, uFpuupp) +GO(cairo_mesh_pattern_get_corner_color_rgba, uFpuupppp) +GO(cairo_mesh_pattern_get_patch_count, uFpp) +GO(cairo_mesh_pattern_get_path, pFpu) +GO(cairo_mesh_pattern_line_to, vFpdd) +GO(cairo_mesh_pattern_move_to, vFpdd) +GO(cairo_mesh_pattern_set_control_point, vFpudd) +GO(cairo_mesh_pattern_set_corner_color_rgb, vFpuddd) +GO(cairo_mesh_pattern_set_corner_color_rgba, vFpudddd) +GO(cairo_move_to, vFpdd) +GO(cairo_new_path, vFp) +GO(cairo_new_sub_path, vFp) +GO(cairo_paint, vFp) +GO(cairo_paint_with_alpha, vFpd) +GO(cairo_path_destroy, vFp) +GO(cairo_path_extents, vFppppp) +GO(cairo_pattern_add_color_stop_rgb, vFpdddd) +GO(cairo_pattern_add_color_stop_rgba, vFpddddd) +GO(cairo_pattern_create_for_surface, pFp) +GO(cairo_pattern_create_linear, pFdddd) +GO(cairo_pattern_create_mesh, pFv) +GO(cairo_pattern_create_radial, pFdddddd) +GO(cairo_pattern_create_raster_source, pFpuii) +GO(cairo_pattern_create_rgb, pFddd) +GO(cairo_pattern_create_rgba, pFdddd) +GO(cairo_pattern_destroy, vFp) +GO(cairo_pattern_get_color_stop_count, uFpp) +GO(cairo_pattern_get_color_stop_rgba, uFpippppp) +GO(cairo_pattern_get_dither, uFp) +GO(cairo_pattern_get_extend, uFp) +GO(cairo_pattern_get_filter, uFp) +GO(cairo_pattern_get_linear_points, uFppppp) +GO(cairo_pattern_get_matrix, vFpp) +GO(cairo_pattern_get_radial_circles, uFppppppp) +GO(cairo_pattern_get_reference_count, uFp) +GO(cairo_pattern_get_rgba, uFppppp) +GO(cairo_pattern_get_surface, uFpp) +GO(cairo_pattern_get_type, uFp) +GO(cairo_pattern_get_user_data, pFpp) +GO(cairo_pattern_reference, pFp) +GO(cairo_pattern_set_extend, vFpu) +GO(cairo_pattern_set_dither, vFpu) +GO(cairo_pattern_set_filter, vFpu) +GO(cairo_pattern_set_matrix, vFpp) +GOM(cairo_pattern_set_user_data, uFEpppp) +GO(cairo_pattern_status, uFp) +GO(cairo_pdf_get_versions, vFpp) +GO(cairo_pdf_surface_add_outline, iFpippu) +GO(cairo_pdf_surface_create, pFpdd) +GOM(cairo_pdf_surface_create_for_stream, pFEppdd) +GO(cairo_pdf_surface_restrict_to_version, vFpu) +GO(cairo_pdf_surface_set_size, vFpdd) +GO(cairo_pdf_surface_set_custom_metadata, vFppp) +GO(cairo_pdf_surface_set_metadata, vFpup) +GO(cairo_pdf_surface_set_page_label, vFpp) +GO(cairo_pdf_surface_set_thumbnail_size, vFpii) +GO(cairo_pdf_version_to_string, pFu) +GO(cairo_pop_group, pFp) +GO(cairo_pop_group_to_source, vFp) +GO(cairo_ps_get_levels, vFpp) +GO(cairo_ps_level_to_string, pFu) +GO(cairo_ps_surface_create, pFpdd) +GOM(cairo_ps_surface_create_for_stream, pFEppdd) +GO(cairo_ps_surface_dsc_begin_page_setup, vFp) +GO(cairo_ps_surface_dsc_begin_setup, vFp) +GO(cairo_ps_surface_dsc_comment, vFpp) +GO(cairo_ps_surface_get_eps, iFp) +GO(cairo_ps_surface_restrict_to_level, vFpu) +GO(cairo_ps_surface_set_eps, vFpi) +GO(cairo_ps_surface_set_size, vFpdd) +GO(cairo_push_group, vFp) +GO(cairo_push_group_with_content, vFpu) +GOM(cairo_raster_source_pattern_get_acquire, vFEppp) +GO(cairo_raster_source_pattern_get_callback_data, pFp) +GOM(cairo_raster_source_pattern_get_copy, pFEp) +GOM(cairo_raster_source_pattern_get_finish, pFEp) +GOM(cairo_raster_source_pattern_get_snapshot, pFEp) +GOM(cairo_raster_source_pattern_set_acquire, vFEppp) +GO(cairo_raster_source_pattern_set_callback_data, vFpp) +GOM(cairo_raster_source_pattern_set_copy, vFEpp) +GOM(cairo_raster_source_pattern_set_finish, vFEpp) +GOM(cairo_raster_source_pattern_set_snapshot, vFEpp) +GO(cairo_recording_surface_create, pFup) +GO(cairo_recording_surface_get_extents, iFpp) +GO(cairo_recording_surface_ink_extents, vFppppp) +GO(cairo_rectangle, vFpdddd) +GO(cairo_rectangle_list_destroy, vFp) +GO(cairo_reference, pFp) +GO(cairo_region_contains_point, iFpii) +GO(cairo_region_contains_rectangle, uFpp) +GO(cairo_region_copy, pFp) +GO(cairo_region_create, pFv) +GO(cairo_region_create_rectangle, pFp) +GO(cairo_region_create_rectangles, pFpi) +GO(cairo_region_destroy, vFp) +GO(cairo_region_equal, iFpp) +GO(cairo_region_get_extents, vFpp) +GO(cairo_region_get_rectangle, vFpip) +GO(cairo_region_intersect, uFpp) +GO(cairo_region_intersect_rectangle, uFpp) +GO(cairo_region_is_empty, iFp) +GO(cairo_region_num_rectangles, iFp) +GO(cairo_region_reference, pFp) +GO(cairo_region_status, uFp) +GO(cairo_region_subtract, uFpp) +GO(cairo_region_subtract_rectangle, uFpp) +GO(cairo_region_translate, vFpii) +GO(cairo_region_union, uFpp) +GO(cairo_region_union_rectangle, uFpp) +GO(cairo_region_xor, uFpp) +GO(cairo_region_xor_rectangle, uFpp) +GO(cairo_rel_curve_to, vFpdddddd) +GO(cairo_rel_line_to, vFpdd) +GO(cairo_rel_move_to, vFpdd) +GO(cairo_reset_clip, vFp) +GO(cairo_restore, vFp) +GO(cairo_rotate, vFpd) +GO(cairo_save, vFp) +GO(cairo_scale, vFpdd) +GO(cairo_scaled_font_create, pFpppp) +GO(cairo_scaled_font_destroy, vFp) +GO(cairo_scaled_font_extents, vFpp) +GO(cairo_scaled_font_get_ctm, vFpp) +GO(cairo_scaled_font_get_font_face, pFp) +GO(cairo_scaled_font_get_font_matrix, vFpp) +GO(cairo_scaled_font_get_font_options, vFpp) +GO(cairo_scaled_font_get_reference_count, uFp) +GO(cairo_scaled_font_get_scale_matrix, vFpp) +GO(cairo_scaled_font_get_type, uFp) +GO(cairo_scaled_font_get_user_data, pFpp) +GO(cairo_scaled_font_glyph_extents, vFppip) +GO(cairo_scaled_font_reference, pFp) +GOM(cairo_scaled_font_set_user_data, uFEpppp) +GO(cairo_scaled_font_status, uFp) +GO(cairo_scaled_font_text_extents, vFppp) +GO(cairo_scaled_font_text_to_glyphs, uFpddpippppp) +GO(cairo_script_create, pFp) +GOM(cairo_script_create_for_stream, pFEpp) +GO(cairo_script_from_recording_surface, uFpp) +GO(cairo_script_get_mode, uFp) +GO(cairo_script_set_mode, vFpu) +GO(cairo_script_surface_create, pFpudd) +GO(cairo_script_surface_create_for_target, pFpp) +GO(cairo_script_write_comment, vFppi) +GO(cairo_select_font_face, vFppuu) +GO(cairo_set_antialias, vFpu) +GO(cairo_set_dash, vFppid) +GO(cairo_set_fill_rule, vFpu) +GO(cairo_set_font_face, vFpp) +GO(cairo_set_font_matrix, vFpp) +GO(cairo_set_font_options, vFpp) +GO(cairo_set_font_size, vFpd) +GO(cairo_set_hairline, vFpi) +GO(cairo_set_line_cap, vFpu) +GO(cairo_set_line_join, vFpu) +GO(cairo_set_line_width, vFpd) +GO(cairo_set_matrix, vFpp) +GO(cairo_set_miter_limit, vFpd) +GO(cairo_set_operator, vFpu) +GO(cairo_set_scaled_font, vFpp) +GO(cairo_set_source, vFpp) +GO(cairo_set_source_rgb, vFpddd) +GO(cairo_set_source_rgba, vFpdddd) +GO(cairo_set_source_surface, vFppdd) +GO(cairo_set_tolerance, vFpd) +GOM(cairo_set_user_data, uFEpppp) +GO(cairo_show_glyphs, vFppi) +GO(cairo_show_page, vFp) +GO(cairo_show_text, vFpp) +GO(cairo_show_text_glyphs, vFppipipiu) +GO(cairo_status, uFp) +GO(cairo_status_to_string, pFu) +GO(cairo_stroke, vFp) +GO(cairo_stroke_extents, vFppppp) +GO(cairo_stroke_preserve, vFp) +GO(cairo_surface_copy_page, vFp) +GO(cairo_surface_create_for_rectangle, pFpdddd) +GO(cairo_surface_create_observer, pFpu) +GO(cairo_surface_create_similar, pFpuii) +GO(cairo_surface_create_similar_image, pFpiii) +GO(cairo_surface_destroy, vFp) +GO(cairo_surface_finish, vFp) +GO(cairo_surface_flush, vFp) +GO(cairo_surface_get_content, uFp) +GO(cairo_surface_get_device, pFp) +GO(cairo_surface_get_device_offset, vFppp) +GO(cairo_surface_get_device_scale, vFppp) +GO(cairo_surface_get_fallback_resolution, vFppp) +GO(cairo_surface_get_font_options, vFpp) +GO(cairo_surface_get_mime_data, vFpppp) +GO(cairo_surface_get_reference_count, uFp) +GO(cairo_surface_get_type, uFp) +GO(cairo_surface_get_user_data, pFpp) +GO(cairo_surface_has_show_text_glyphs, iFp) +GO(cairo_surface_map_to_image, pFpp) +GO(cairo_surface_mark_dirty, vFp) +GO(cairo_surface_mark_dirty_rectangle, vFpiiii) +GOM(cairo_surface_observer_add_fill_callback, uFEppp) +GOM(cairo_surface_observer_add_finish_callback, uFEppp) +GOM(cairo_surface_observer_add_flush_callback, uFEppp) +GOM(cairo_surface_observer_add_glyphs_callback, uFEppp) +GOM(cairo_surface_observer_add_mask_callback, uFEppp) +GOM(cairo_surface_observer_add_paint_callback, uFEppp) +GOM(cairo_surface_observer_add_stroke_callback, uFEppp) +GO(cairo_surface_observer_elapsed, dFp) +GOM(cairo_surface_observer_print, uFEppp) +GO(cairo_surface_reference, pFp) +GO(cairo_surface_set_device_offset, vFpdd) +GO(cairo_surface_set_device_scale, vFpdd) +GO(cairo_surface_set_fallback_resolution, vFpdd) +GOM(cairo_surface_set_mime_data, uFEpppLpp) +GOM(cairo_surface_set_user_data, uFEpppp) +GO(cairo_surface_show_page, vFp) +GO(cairo_surface_status, uFp) +GO(cairo_surface_supports_mime_type, iFpp) +GO(cairo_surface_unmap_image, vFpp) +GO(cairo_surface_write_to_png, uFpp) +GOM(cairo_surface_write_to_png_stream, uFEppp) +GO(cairo_svg_get_versions, vFpp) +GO(cairo_svg_surface_create, pFpdd) +GOM(cairo_svg_surface_create_for_stream, pFEppdd) +GO(cairo_svg_surface_get_document_unit, uFp) +GO(cairo_svg_surface_restrict_to_version, vFpu) +GO(cairo_svg_surface_set_document_unit, vFpu) +GO(cairo_svg_version_to_string, pFu) +GO(cairo_tag_begin, vFppp) +GO(cairo_tag_end, vFpp) +GO(cairo_tee_surface_add, vFpp) +GO(cairo_tee_surface_create, pFp) +GO(cairo_tee_surface_index, pFpu) +GO(cairo_tee_surface_remove, vFpp) +GO(cairo_text_cluster_allocate, pFi) +GO(cairo_text_cluster_free, vFp) +GO(cairo_text_extents, vFppp) +GO(cairo_text_path, vFpp) +GO(cairo_toy_font_face_create, pFpuu) +GO(cairo_toy_font_face_get_family, pFp) +GO(cairo_toy_font_face_get_slant, uFp) +GO(cairo_toy_font_face_get_weight, uFp) +GO(cairo_transform, vFpp) +GO(cairo_translate, vFpdd) +GOM(cairo_user_font_face_create, pFEv) +GOM(cairo_user_font_face_get_init_func, pFEp) +GOM(cairo_user_font_face_get_render_color_glyph_func, pFEp) +GOM(cairo_user_font_face_get_render_glyph_func, pFEp) +GOM(cairo_user_font_face_get_text_to_glyphs_func, pFEp) +GOM(cairo_user_font_face_get_unicode_to_glyph_func, pFEp) +GOM(cairo_user_font_face_set_init_func, vFEpp) +GOM(cairo_user_font_face_set_render_color_glyph_func, vFEpp) +GOM(cairo_user_font_face_set_render_glyph_func, vFEpp) +GOM(cairo_user_font_face_set_text_to_glyphs_func, vFEpp) +GOM(cairo_user_font_face_set_unicode_to_glyph_func, vFEpp) +GO(cairo_user_scaled_font_get_foreground_marker, pFp) +GO(cairo_user_scaled_font_get_foreground_source, pFp) +GO(cairo_user_to_device, vFppp) +GO(cairo_user_to_device_distance, vFppp) +GO(cairo_version, iFv) +GO(cairo_version_string, pFv) +GO(cairo_xcb_device_debug_cap_xrender_version, vFpii) +GO(cairo_xcb_device_debug_cap_xshm_version, vFpii) +GO(cairo_xcb_device_debug_get_precision, iFp) +GO(cairo_xcb_device_debug_set_precision, vFpi) +GOM(cairo_xcb_device_get_connection, pFEp) +GO(cairo_xcb_surface_create, pFbupii) +GO(cairo_xcb_surface_create_for_bitmap, pFbpuii) +GO(cairo_xcb_surface_create_with_xrender_format, pFbpupii) +GO(cairo_xcb_surface_set_drawable, vFpuii) +GO(cairo_xcb_surface_set_size, vFpii) +GO(cairo_xlib_device_debug_cap_xrender_version, vFpii) +GO(cairo_xlib_device_debug_get_precision, iFp) +GO(cairo_xlib_device_debug_set_precision, vFpi) +GO(cairo_xlib_surface_create, pFpLpii) +GO(cairo_xlib_surface_create_for_bitmap, pFpLpii) +GO(cairo_xlib_surface_create_with_xrender_format, pFpLppii) +GO(cairo_xlib_surface_get_depth, iFp) +GO(cairo_xlib_surface_get_display, pFp) +GO(cairo_xlib_surface_get_drawable, LFp) +GO(cairo_xlib_surface_get_height, iFp) +GO(cairo_xlib_surface_get_screen, pFp) +GO(cairo_xlib_surface_get_visual, pFp) +GO(cairo_xlib_surface_get_width, iFp) +GO(cairo_xlib_surface_get_xrender_format, pFp) +GO(cairo_xlib_surface_set_drawable, vFpLii) +GO(cairo_xlib_surface_set_size, vFpii) +//GO(cairo_xml_create, +//GO(cairo_xml_create_for_stream, +//GO(cairo_xml_for_recording_surface, +//GO(cairo_xml_surface_create, diff --git a/target/i386/latx/include/wrappedlib_init.h b/target/i386/latx/include/wrappedlib_init.h index 29ea77f48c..bc88e5cb95 100755 --- a/target/i386/latx/include/wrappedlib_init.h +++ b/target/i386/latx/include/wrappedlib_init.h @@ -116,6 +116,9 @@ int FUNC(_init)(library_t* lib, box64context_t* box64) { (void)box64; +#ifdef PRE_INIT_GUEST + PRE_INIT_GUEST +#endif // Init first free(lib->path); lib->path=NULL; #ifdef PRE_INIT diff --git a/target/i386/latx/include/wrapper.h b/target/i386/latx/include/wrapper.h index 05b4d58d50..5f66d739dd 100644 --- a/target/i386/latx/include/wrapper.h +++ b/target/i386/latx/include/wrapper.h @@ -1523,5 +1523,36 @@ void uFbuuWW(uintptr_t fcn); void uFbuuuup(uintptr_t fcn); void pFbuuUUU(uintptr_t fcn); void pFbuuuuuwwuuuuUUUup(uintptr_t fcn); +void iFpdd(uintptr_t fcn); +void pFiii(uintptr_t fcn); +void pFpdd(uintptr_t fcn); +void vFpuii(uintptr_t fcn); +void vFpudd(uintptr_t fcn); +void vFpLii(uintptr_t fcn); +void vFppid(uintptr_t fcn); +void pFdddd(uintptr_t fcn); +void pFpuii(uintptr_t fcn); +void pFpudd(uintptr_t fcn); +void vFpuddd(uintptr_t fcn); +void vFpdddd(uintptr_t fcn); +void uFpuupp(uintptr_t fcn); +void uFppppp(uintptr_t fcn); +void pFpiiii(uintptr_t fcn); +void pFpdddd(uintptr_t fcn); +void pFpLpii(uintptr_t fcn); +void pFbupii(uintptr_t fcn); +void pFbpuii(uintptr_t fcn); +void vFpudddd(uintptr_t fcn); +void vFpddddd(uintptr_t fcn); +void uFpppLpp(uintptr_t fcn); +void pFpLppii(uintptr_t fcn); +void pFbpupii(uintptr_t fcn); +void uFpippppp(uintptr_t fcn); +void uFpuupppp(uintptr_t fcn); +void uFppppppp(uintptr_t fcn); +void vFppipipiu(uintptr_t fcn); +void uFpddpippppp(uintptr_t fcn); +void iFpippu(uintptr_t fcn); +void uFpupppp(uintptr_t fcn); //endxcbV2 #endif // __WRAPPER_H_