A fifth Python plugin capability type, ResourceTexture, contributes
height-map textures to the Texture Displacement picker. A pack returns a
directory of images; the host validates it once at load and lists the
images under a section of their own.
- New capability type ResourceTexture, type string "resource-texture",
exposed to plugin authors as
orca.resource_texture.ResourceTexturePluginCapabilityBase with one
required method, get_texture_dir().
- The directory is resolved once on the load worker, under the GIL, and
cached as a plain string: the picker runs inside the ImGui frame, where
a trampoline call would block on the GIL behind a load/unload worker, or
throw past EndPopup.
- Validation resolves the directory and requires containment in the plugin
root, re-checked per file so a symlink inside the pack cannot resolve
outside it. Containment is the only security control here and it guards
exfiltration: layer bytes are embedded in every saved .3mf, so a pack
that could return ~/.ssh/id_rsa would leak it through any shared project.
- New host registry PluginResourceTextures, filled from both the plugin
and the capability lifecycle callbacks plus a startup sweep. It holds
strings only and never a capability reference, so nothing outlives
Py_Finalize.
- The picker lists pack textures read-only, one collapsible section per
pack, in a fixed-size scrolling popup whose height follows the window. A
generation counter invalidates the cached listing, and each gizmo's
cached thumbnails, when the set of packs changes.
- Tests in tests/slic3rutils/test_plugin_resource_texture.cpp cover the
validator (parent-directory and absolute escapes, an escaping symlink,
the extension whitelist, the 64-file cap), the listing and its
load/disable/re-enable/unload lifecycle, hostile get_texture_dir()
overrides, decode parity with hand-picked files, and a .3mf round trip
with the pack uninstalled.
No persistence work is needed: a layer carries its own image bytes and 3MF
writes them into the archive, so uninstalling a pack leaves existing
projects intact.
Behaviour change worth noting for review: the picker popup is now a fixed
size that scrolls, rather than sizing itself to its content, and it gains
one collapsible section per pack. That sizing applies to every user, not
only those with packs installed.