diff --git a/CMakeLists.txt b/CMakeLists.txt index 4104a099d..0d8002b64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ else () endif () option (BUILD_TESTS "Build/enable tests" ON) option (BUILD_DEFS "Auto-generate C/C++ headers and documentation" OFF) -option (DISABLE_SSL "Disable built-in SSL support even if available on this system" OFF) +option (DISABLE_SSL "Disable built-in SSL support even if available on this system" ON) option (DISABLE_X11 "Disable X11 even if available on this system" OFF) option (DISABLE_AUDIO "Disable audio API" OFF) option (DISABLE_DISPLAY "Disable display API" OFF) diff --git a/docs/xml/modules/classes/svg.xml b/docs/xml/modules/classes/svg.xml index 5ff0b709c..629a5f303 100644 --- a/docs/xml/modules/classes/svg.xml +++ b/docs/xml/modules/classes/svg.xml @@ -91,7 +91,7 @@ Render - Render the scene to a target Bitamp. + Render the scene to a target Bitmap. ERR svg::Render(OBJECTPTR Object, objBitmap * Bitmap, LONG X, LONG Y, LONG Width, LONG Height) The target Bitmap. @@ -200,7 +200,7 @@

During the normal initialisation process, a new VectorViewport is created to host the SVG scene graph. By default, the viewport and its content is strictly owned by the SVG object unless a Target is defined to redirect the scene graph elsewhere.

The provided Target can be any object class, as long as it forms part of a scene graph owned by a VectorScene object. It is recommended that the chosen target is a VectorViewport.

-

The use of a Target will make the generated scene graph independent of the SVG object. Consequently, it is possible to terminate the SVG object without impacting the resources it created.

+

The use of a Target will make the generated scene graph independent of the SVG object. Consequently, it is possible to terminate the SVG object without impacting the resources it created. If tracking back to the SVG object is still required, use the ENFORCE_TRACKING option in Flags to ensure that SVG definitions are still terminated on object destruction.

@@ -229,6 +229,7 @@ Generate an alpha channel in the rendered image. In auto-resize mode, vector dimensions are scaled to the width and height of the vector page. The VectorScene.PageWidth and VectorScene.PageHeight must be set for this. + Enforce tracking of definition objects when a Target is used. diff --git a/include/parasol/modules/svg.h b/include/parasol/modules/svg.h index 1a0060b84..c23e75251 100644 --- a/include/parasol/modules/svg.h +++ b/include/parasol/modules/svg.h @@ -16,6 +16,7 @@ enum class SVF : ULONG { NIL = 0, AUTOSCALE = 0x00000001, ALPHA = 0x00000002, + ENFORCE_TRACKING = 0x00000004, }; DEFINE_ENUM_FLAG_OPERATORS(SVF) diff --git a/src/core/lib_objects.cpp b/src/core/lib_objects.cpp index 96d68939b..af57cdc3f 100644 --- a/src/core/lib_objects.cpp +++ b/src/core/lib_objects.cpp @@ -1397,7 +1397,7 @@ void NotifySubscribers(OBJECTPTR Object, AC ActionID, APTR Parameters, ERR Error glSubReadOnly--; if (!glSubReadOnly) { - if (!glDelayedSubscribe.empty()) { + if (!glDelayedSubscribe.empty()) { // Check if SubscribeAction() was called during the notification process for (auto &entry : glDelayedSubscribe) { glSubscriptions[entry.ObjectID][LONG(entry.ActionID)].emplace_back(entry.Callback.Context, entry.Callback.Routine, entry.Callback.Meta); } diff --git a/src/picture/picture.cpp b/src/picture/picture.cpp index b02dff720..9f192b021 100644 --- a/src/picture/picture.cpp +++ b/src/picture/picture.cpp @@ -326,10 +326,10 @@ static ERR PICTURE_Activate(extPicture *Self) static ERR PICTURE_Free(extPicture *Self) { - Self->~extPicture(); if (Self->prvFile) { FreeResource(Self->prvFile); Self->prvFile = NULL; } if (Self->Bitmap) { FreeResource(Self->Bitmap); Self->Bitmap = NULL; } if (Self->Mask) { FreeResource(Self->Mask); Self->Mask = NULL; } + Self->~extPicture(); return ERR::Okay; } diff --git a/src/svg/class_svg.cpp b/src/svg/class_svg.cpp index 58a4b717b..ea88b848b 100644 --- a/src/svg/class_svg.cpp +++ b/src/svg/class_svg.cpp @@ -86,8 +86,6 @@ static ERR SVG_DataFeed(extSVG *Self, struct acDataFeed *Args) static ERR SVG_Free(extSVG *Self) { - Self->~extSVG(); - if (Self->AnimationTimer) { UpdateTimer(Self->AnimationTimer, 0); Self->AnimationTimer = 0; @@ -108,6 +106,12 @@ static ERR SVG_Free(extSVG *Self) if (Self->Statement) { FreeResource(Self->Statement); Self->Statement = NULL; } if (Self->XML) { FreeResource(Self->XML); Self->XML = NULL; } + if (!Self->Resources.empty()) { + for (auto id : Self->Resources) FreeResource(id); + } + + Self->~extSVG(); + return ERR::Okay; } @@ -552,7 +556,9 @@ The provided Target can be any object class, as long as it forms part of a scene object. It is recommended that the chosen target is a @VectorViewport. The use of a Target will make the generated scene graph independent of the SVG object. Consequently, it is possible -to terminate the SVG object without impacting the resources it created. +to terminate the SVG object without impacting the resources it created. If tracking back to the SVG object is +still required, use the `ENFORCE_TRACKING` option in #Flags to ensure that SVG definitions are still terminated on +object destruction. *********************************************************************************************************************/ diff --git a/src/svg/class_svg_def.c b/src/svg/class_svg_def.c index e856e22bf..e84a18833 100644 --- a/src/svg/class_svg_def.c +++ b/src/svg/class_svg_def.c @@ -3,6 +3,7 @@ static const struct FieldDef clSVGFlags[] = { { "Autoscale", 0x00000001 }, { "Alpha", 0x00000002 }, + { "EnforceTracking", 0x00000004 }, { NULL, 0 } }; diff --git a/src/svg/gradients.cpp b/src/svg/gradients.cpp index 1c07d200e..60c226406 100644 --- a/src/svg/gradients.cpp +++ b/src/svg/gradients.cpp @@ -152,6 +152,7 @@ static ERR xtag_lineargradient(extSVG *Self, const XMLTag &Tag) if (!id.empty()) { SetName(gradient, id.c_str()); add_id(Self, Tag, id); + track_object(Self, gradient); return Self->Scene->addDef(id.c_str(), gradient); } else return ERR::Okay; @@ -222,6 +223,7 @@ static ERR xtag_radialgradient(extSVG *Self, const XMLTag &Tag) if (!id.empty()) { SetName(gradient, id.c_str()); add_id(Self, Tag, id); + track_object(Self, gradient); return Self->Scene->addDef(id.c_str(), gradient); } else return ERR::Okay; @@ -291,6 +293,7 @@ static ERR xtag_diamondgradient(extSVG *Self, const XMLTag &Tag) if (!id.empty()) { SetName(gradient, id.c_str()); add_id(Self, Tag, id); + track_object(Self, gradient); return Self->Scene->addDef(id.c_str(), gradient); } else return ERR::Okay; @@ -358,6 +361,7 @@ static ERR xtag_contourgradient(extSVG *Self, const XMLTag &Tag) if (!id.empty()) { SetName(gradient, id.c_str()); add_id(Self, Tag, id); + track_object(Self, gradient); return Self->Scene->addDef(id.c_str(), gradient); } else return ERR::Okay; @@ -431,6 +435,7 @@ static ERR xtag_conicgradient(extSVG *Self, const XMLTag &Tag) if (!id.empty()) { SetName(gradient, id.c_str()); add_id(Self, Tag, id); + track_object(Self, gradient); return Self->Scene->addDef(id.c_str(), gradient); } else return ERR::Okay; diff --git a/src/svg/parser.cpp b/src/svg/parser.cpp index 64253f1d0..91ad6cba8 100644 --- a/src/svg/parser.cpp +++ b/src/svg/parser.cpp @@ -199,6 +199,7 @@ static void xtag_pathtransition(extSVG *Self, XMLTag &Tag) if (InitObject(trans) IS ERR::Okay) { if (!Self->Cloning) Self->Scene->addDef(id.c_str(), trans); + track_object(Self, trans); return; } } @@ -266,6 +267,7 @@ static void xtag_clippath(extSVG *Self, XMLTag &Tag) process_children(Self, state, Tag, vp); Self->Scene->addDef(id.c_str(), clip); + track_object(Self, clip); } else FreeResource(clip); } @@ -339,6 +341,7 @@ static void xtag_mask(extSVG *Self, XMLTag &Tag) process_children(Self, state, Tag, vp); Self->Scene->addDef(id.c_str(), clip); + track_object(Self, clip); } else FreeResource(clip); } @@ -1466,6 +1469,8 @@ static void xtag_filter(extSVG *Self, svgState &State, XMLTag &Tag) Self->Effects.clear(); if (!Self->Cloning) Self->Scene->addDef(id.c_str(), filter); + + track_object(Self, filter); } else FreeResource(filter); } @@ -1560,6 +1565,7 @@ static void process_pattern(extSVG *Self, XMLTag &Tag) if (!Self->Cloning) { add_id(Self, Tag, id); Self->Scene->addDef(id.c_str(), pattern); + track_object(Self, pattern); } } else { @@ -1812,6 +1818,7 @@ static void def_image(extSVG *Self, XMLTag &Tag) if (!Self->Cloning) { add_id(Self, Tag, id); Self->Scene->addDef(id.c_str(), image); + track_object(Self, image); } } else { @@ -1896,6 +1903,7 @@ static ERR xtag_image(extSVG *Self, svgState &State, XMLTag &Tag, OBJECTPTR Pare SetOwner(pic, image); // It's best if the pic belongs to the image. Self->Scene->addDef(id.c_str(), image); + track_object(Self, image); } else return ERR::CreateObject; } diff --git a/src/svg/svg.cpp b/src/svg/svg.cpp index c53b219c8..c094d7d59 100644 --- a/src/svg/svg.cpp +++ b/src/svg/svg.cpp @@ -94,6 +94,7 @@ class extSVG : public objSVG { std::map Animatrix; // For animated transforms, a vector may have one matrix only. std::vector> Links; std::vector Inherit; + std::vector Resources; // Resources to terminate if ENFORCE_TRACKING was enabled. std::map> StartOnBegin; // When the animation indicated by ULONG begins, it must activate() the referenced anim_base std::map> StartOnEnd; // When the animation indicated by ULONG ends, it must activate() the referenced anim_base TIMER AnimationTimer; @@ -159,6 +160,13 @@ static void xtag_use(extSVG *, svgState &, XMLTag &, OBJECTPTR); static ERR xtag_style(extSVG *, XMLTag &); static void xtag_symbol(extSVG *, XMLTag &); +inline void track_object(extSVG *SVG, OBJECTPTR Object) +{ + if ((SVG->Flags & SVF::ENFORCE_TRACKING) != SVF::NIL) { + SVG->Resources.emplace_back(Object->UID); + } +} + //******************************************************************************************************************** #include "funit.cpp" diff --git a/src/svg/svg.fdl b/src/svg/svg.fdl index 8a12e2a99..e71d1be4f 100644 --- a/src/svg/svg.fdl +++ b/src/svg/svg.fdl @@ -3,7 +3,8 @@ module({ name="SVG", copyright="Paul Manias © 2010-2024", version=1.0, timestamp=20240611 }, function() flags("SVF", { comment="SVG flags." }, "AUTOSCALE: In auto-resize mode, vector dimensions are scaled to the width and height of the vector page. The @VectorScene.PageWidth and @VectorScene.PageHeight must be set for this.", - "ALPHA: Generate an alpha channel in the rendered image.") + "ALPHA: Generate an alpha channel in the rendered image.", + "ENFORCE_TRACKING: Enforce tracking of definition objects when a Target is used.") methods("svg", "Svg", { { id=1, name="Render" }, diff --git a/src/svg/svg_def.c b/src/svg/svg_def.c index b12b1e8d2..39d1a9a04 100644 --- a/src/svg/svg_def.c +++ b/src/svg/svg_def.c @@ -1,2 +1,2 @@ #undef MOD_IDL -#define MOD_IDL "c.SVF:ALPHA=0x2,AUTOSCALE=0x1\n" +#define MOD_IDL "c.SVF:ALPHA=0x2,AUTOSCALE=0x1,ENFORCE_TRACKING=0x4\n"