From 416dc8dc30391c331918831c0c6b3da8128afef8 Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 20:18:10 +0800 Subject: [PATCH 1/6] LATX, fix: Defer KZT binding until dynamic RELRO A guest loader may publish RT_CONSISTENT before it has finished applying a dynamically loaded object's relocations. Marking a successful KZT pass complete at that point lets the loader overwrite native bridges and prevents the existing pre-RELRO retry. For objects with PT_GNU_RELRO, wait for the intercepted writable RELRO boundary. Objects without RELRO still bind at RT_CONSISTENT because they have no later protection transition. Signed-off-by: Hanlu Li --- target/i386/latx/context/myalign.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) 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 && From ebb67bc043320318028c6fd4e22536d02272a843 Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 20:18:10 +0800 Subject: [PATCH 2/6] LATX, fix: Index guest SSE arguments by register Read and write scalar wrapper values from lane zero of the selected guest XMM register. The old expression indexed lanes within XMM0, which misrouted XMM1 and later arguments and overlapped double values. Signed-off-by: Hanlu Li --- target/i386/latx/context/wrapper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/latx/context/wrapper.c b/target/i386/latx/context/wrapper.c index 0696386d26..8490b9909d 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; From af8973914053803c13639d9f13ab24d6695c47fc Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 20:18:10 +0800 Subject: [PATCH 3/6] LATX, fix: Implement int32 two-argument wrapper The generic iFii signature was declared but had no callable wrapper, and its unused typedef used 64-bit integers. Cairo format-stride calculation is the first enabled native wrapper that requires this signature. Implement the wrapper with two int32 arguments and an int32 return so the generated Cairo symbol map can link with the public Cairo ABI. Signed-off-by: Hanlu Li --- target/i386/latx/context/wrapper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/latx/context/wrapper.c b/target/i386/latx/context/wrapper.c index 8490b9909d..d83bc057c0 100644 --- a/target/i386/latx/context/wrapper.c +++ b/target/i386/latx/context/wrapper.c @@ -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); From ad5f62568c364318c2ae6ebb6a1e22c741c667ba Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 20:18:10 +0800 Subject: [PATCH 4/6] LATX, feat: Add Cairo ABI wrapper catalog Add the Cairo 1.18 public symbol catalog together with the scalar, pointer, double, and XCB-aligned dispatch signatures it requires. Keep this mechanical ABI preparation separate from library activation, preflight policy, and callback behavior. Signed-off-by: Hanlu Li --- target/i386/latx/context/wrapper.c | 63 +++ .../latx/include/generated/wrappedcairodefs.h | 19 + .../include/generated/wrappedcairotypes.h | 76 +++ .../include/generated/wrappedcairoundefs.h | 19 + .../i386/latx/include/wrappedcairo_private.h | 436 ++++++++++++++++++ target/i386/latx/include/wrapper.h | 31 ++ 6 files changed, 644 insertions(+) create mode 100644 target/i386/latx/include/generated/wrappedcairodefs.h create mode 100644 target/i386/latx/include/generated/wrappedcairotypes.h create mode 100644 target/i386/latx/include/generated/wrappedcairoundefs.h create mode 100644 target/i386/latx/include/wrappedcairo_private.h diff --git a/target/i386/latx/context/wrapper.c b/target/i386/latx/context/wrapper.c index d83bc057c0..3cf3efc5cd 100644 --- a/target/i386/latx/context/wrapper.c +++ b/target/i386/latx/context/wrapper.c @@ -1485,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); @@ -3092,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/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/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_ From dd421cee49c8bc9b4dd5674cbdf1200d2047f56f Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 20:18:29 +0800 Subject: [PATCH 5/6] LATX, feat: Preflight guest Cairo symbol coverage Inspect the guest Cairo dynamic symbol table before native activation. Require every exported Cairo function to have a declared safe wrapper and a matching host symbol, and expose rejection reasons through opt-in KZT diagnostics so unsupported backends fail as a whole library. Signed-off-by: Hanlu Li --- target/i386/latx/context/kzt-groups.c | 10 + target/i386/latx/context/meson.build | 1 + .../latx/context/wrappedcairo-preflight.c | 249 ++++++++++++++++++ target/i386/latx/include/kzt-groups.h | 2 + .../latx/include/wrappedcairo-preflight.h | 17 ++ target/i386/latx/include/wrappedlib_init.h | 3 + 6 files changed, 282 insertions(+) create mode 100644 target/i386/latx/context/wrappedcairo-preflight.c create mode 100644 target/i386/latx/include/wrappedcairo-preflight.h diff --git a/target/i386/latx/context/kzt-groups.c b/target/i386/latx/context/kzt-groups.c index ca51d4e9d1..e532e5e84a 100644 --- a/target/i386/latx/context/kzt-groups.c +++ b/target/i386/latx/context/kzt-groups.c @@ -423,3 +423,13 @@ 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); +} diff --git a/target/i386/latx/context/meson.build b/target/i386/latx/context/meson.build index 4e832ffd94..601eb98b83 100644 --- a/target/i386/latx/context/meson.build +++ b/target/i386/latx/context/meson.build @@ -25,6 +25,7 @@ my_file = files( 'wrappedlibxcbutil.c', 'wrappedlibxcbxinerama.c', 'wrappedlibxcbxinput.c', + 'wrappedcairo-preflight.c', 'wrappedlibx11xcb.c', 'wrappedxkbcommon.c', 'wrappedxkbcommonx11.c', 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/include/kzt-groups.h b/target/i386/latx/include/kzt-groups.h index 0986c548e7..11299fe4f9 100644 --- a/target/i386/latx/include/kzt-groups.h +++ b/target/i386/latx/include/kzt-groups.h @@ -50,5 +50,7 @@ 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); #endif /* LATX_KZT_GROUPS_H */ 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/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 From 5b3e06bf97f2e6771e9b7b74905be72c0fe03da5 Mon Sep 17 00:00:00 2001 From: Hanlu Li Date: Thu, 13 Aug 2026 20:18:42 +0800 Subject: [PATCH 6/6] LATX, feat: Add experimental Cairo native wrapper Register Cairo as an opt-in library family and cover the complete public symbol set exported by the supported guest Cairo 1.18 runtime. Bridge destroy, stream, user-font, observer, MIME, and raster-source callbacks with typed guest argument marshalling, bounded reusable slots, locking, and object-lifetime tracking. Adapt XCB connection objects and reject native activation when whole-library preflight fails. Keep FreeType and Fontconfig interop memory-safe by returning an explicit font-type mismatch until those opaque object families have native wrappers. Signed-off-by: Hanlu Li --- target/i386/latx/context/kzt-groups.c | 10 + target/i386/latx/context/meson.build | 1 + target/i386/latx/context/wrappedcairo.c | 1350 +++++++++++++++++++++ target/i386/latx/include/kzt-group-list.h | 3 +- target/i386/latx/include/kzt-groups.h | 2 + target/i386/latx/include/library_list.h | 2 + 6 files changed, 1367 insertions(+), 1 deletion(-) create mode 100644 target/i386/latx/context/wrappedcairo.c diff --git a/target/i386/latx/context/kzt-groups.c b/target/i386/latx/context/kzt-groups.c index e532e5e84a..908a946c7c 100644 --- a/target/i386/latx/context/kzt-groups.c +++ b/target/i386/latx/context/kzt-groups.c @@ -433,3 +433,13 @@ void kzt_groups_log_wrapper_rejection(const char *soname, 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 601eb98b83..2586140630 100644 --- a/target/i386/latx/context/meson.build +++ b/target/i386/latx/context/meson.build @@ -26,6 +26,7 @@ my_file = files( 'wrappedlibxcbxinerama.c', 'wrappedlibxcbxinput.c', 'wrappedcairo-preflight.c', + 'wrappedcairo.c', 'wrappedlibx11xcb.c', 'wrappedxkbcommon.c', 'wrappedxkbcommonx11.c', 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/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 11299fe4f9..5010b069e2 100644 --- a/target/i386/latx/include/kzt-groups.h +++ b/target/i386/latx/include/kzt-groups.h @@ -52,5 +52,7 @@ 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