SDL_ttf: Added support for OT-SVG fonts like Noto Color Emoji

From e8f83719b908b0371e0651fbb3032ceb2f841593 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 27 Jan 2025 21:02:05 -0800
Subject: [PATCH] Added support for OT-SVG fonts like Noto Color Emoji

Fixes https://github.com/libsdl-org/SDL_ttf/issues/321
Fixes https://github.com/libsdl-org/SDL_ttf/issues/363
---
 .gitmodules                             |   6 ++
 CMakeLists.txt                          |  31 +++++++
 README.md                               |  12 +--
 VisualC/SDL_ttf.vcxproj                 |  38 +++++++--
 VisualC/SDL_ttf.vcxproj.filters         |  69 ++++++++++++++++
 Xcode/SDL_ttf.xcodeproj/project.pbxproj | 102 ++++++++++++++++++++++++
 external/plutosvg                       |   1 +
 external/plutovg                        |   1 +
 include/SDL3_ttf/SDL_textengine.h       |  34 +++++---
 include/SDL3_ttf/SDL_ttf.h              |   1 +
 src/SDL_gpu_textengine.c                |  13 ++-
 src/SDL_renderer_textengine.c           |  26 +++++-
 src/SDL_surface_textengine.c            |   4 +-
 src/SDL_ttf.c                           |  24 +++++-
 14 files changed, 333 insertions(+), 29 deletions(-)
 create mode 160000 external/plutosvg
 create mode 160000 external/plutovg

diff --git a/.gitmodules b/.gitmodules
index 49593939..31009f26 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -6,3 +6,9 @@
 	path = external/harfbuzz
 	url = https://github.com/libsdl-org/harfbuzz.git
 	branch = 8.1.1-SDL
+[submodule "external/plutosvg"]
+	path = external/plutosvg
+	url = https://github.com/libsdl-org/plutosvg.git
+[submodule "external/plutovg"]
+	path = external/plutovg
+	url = https://github.com/libsdl-org/plutovg.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c0768b8a..4d8f4e2a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -94,6 +94,9 @@ set(SDLTTF_FREETYPE_VENDORED "${SDLTTF_VENDORED}")
 option(SDLTTF_HARFBUZZ "Use harfbuzz to improve text shaping" ON)
 set(SDLTTF_HARFBUZZ_VENDORED "${SDLTTF_VENDORED}")
 
+option(SDLTTF_PLUTOSVG "Use plutosvg for color emoji support" ON)
+set(SDLTTF_PLUTOSVG_VENDORED "${SDLTTF_VENDORED}")
+
 # Save BUILD_SHARED_LIBS variable
 set(SDLTTF_BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS}")
 
@@ -221,6 +224,34 @@ set(PC_REQUIRES)
 # Build freetype and harfbuzz as a static library
 set(BUILD_SHARED_LIBS OFF)
 
+if(SDLTTF_PLUTOSVG)
+    if(SDLTTF_PLUTOSVG_VENDORED)
+        message(STATUS "${PROJECT_NAME}: Using vendored plutosvg library")
+
+        set(PLUTOSVG_ENABLE_FREETYPE ON CACHE BOOL "plutosvg enable freetype" FORCE)
+        set(PLUTOVG_BUILD_EXAMPLES OFF CACHE BOOL "plutosvg build examples" FORCE)
+        if(NOT EXISTS "${PROJECT_SOURCE_DIR}/external/plutosvg/CMakeLists.txt")
+            message(FATAL_ERROR "No plutosvg sources found. Install a plutosvg development package or run the download script in the external folder.")
+        endif()
+        add_subdirectory(external/plutosvg EXCLUDE_FROM_ALL)
+        if(NOT TARGET plutosvg::plutosvg)
+            add_library(plutosvg::plutosvg ALIAS plutosvg)
+        endif()
+        if(SDLTTF_BUILD_SHARED_LIBS)
+          target_link_libraries(${sdl3_ttf_target_name} PRIVATE plutosvg::plutosvg)
+        else()
+          target_sources(${sdl3_ttf_target_name} PRIVATE $<TARGET_OBJECTS:plutosvg::plutosvg>)
+          target_include_directories(${sdl3_ttf_target_name} PRIVATE $<TARGET_PROPERTY:plutosvg::plutosvg,INTERFACE_INCLUDE_DIRECTORIES>)
+        endif()
+    else()
+        message(STATUS "${PROJECT_NAME}: Using system plutosvg library")
+        find_package(plutosvg REQUIRED)
+        list(APPEND PC_REQUIRES plutosvg)
+        target_link_libraries(${sdl3_ttf_target_name} PRIVATE plutosvg::plutosvg)
+    endif()
+    target_compile_definitions(${sdl3_ttf_target_name} PRIVATE TTF_USE_PLUTOSVG=1)
+endif()
+
 if(SDLTTF_HARFBUZZ)
     if(SDLTTF_HARFBUZZ_VENDORED)
         message(STATUS "${PROJECT_NAME}: Using vendored harfbuzz library")
diff --git a/README.md b/README.md
index bf12a376..3a6a1e9a 100644
--- a/README.md
+++ b/README.md
@@ -10,11 +10,13 @@ Installation instructions and a quick introduction is available in
 [INSTALL.md](INSTALL.md)
 
 This library is distributed under the terms of the zlib license,
-available in [LICENSE.txt](LICENSE.txt). This library uses and
-may include the FreeType library, licensed under the
-[FTL](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/docs/FTL.TXT),
-and may use or include the HarfBuzz library, licensed under the
-[MIT license](https://github.com/harfbuzz/harfbuzz/blob/main/COPYING).
+available in [LICENSE.txt](LICENSE.txt).
+
+This library also uses the following libraries:
+- FreeType, licensed under the [FTL](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/docs/FTL.TXT)
+- HarfBuzz, licensed under the [MIT license](https://github.com/harfbuzz/harfbuzz/blob/main/COPYING)
+- PlutoSVG, licensed under the [MIT license](https://github.com/sammycage/plutosvg/blob/master/LICENSE)
+- PlutoVG, licensed under the [MIT license](https://github.com/sammycage/plutovg/blob/master/LICENSE)
 
 Enjoy!
 
diff --git a/VisualC/SDL_ttf.vcxproj b/VisualC/SDL_ttf.vcxproj
index 0e03093c..a49609bf 100644
--- a/VisualC/SDL_ttf.vcxproj
+++ b/VisualC/SDL_ttf.vcxproj
@@ -88,19 +88,19 @@
     <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <IncludePath>$(ProjectDir)..\include;$(ProjectDir)..\external\freetype\include;$(ProjectDir)..\external\harfbuzz\src;$(ProjectDir)..\..\SDL\include;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)..\include;$(ProjectDir)..\external\freetype\include;$(ProjectDir)..\external\harfbuzz\src;$(ProjectDir)..\external\plutosvg\source;$(ProjectDir)..\external\plutovg\include;$(ProjectDir)..\..\SDL\include;$(IncludePath)</IncludePath>
     <LibraryPath>$(SolutionDir)..\..\SDL\VisualC\$(PlatformName)\$(Configuration);$(LibraryPath)</LibraryPath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <IncludePath>$(ProjectDir)..\include;$(ProjectDir)..\external\freetype\include;$(ProjectDir)..\external\harfbuzz\src;$(ProjectDir)..\..\SDL\include;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)..\include;$(ProjectDir)..\external\freetype\include;$(ProjectDir)..\external\harfbuzz\src;$(ProjectDir)..\external\plutosvg\source;$(ProjectDir)..\external\plutovg\include;$(ProjectDir)..\..\SDL\include;$(IncludePath)</IncludePath>
     <LibraryPath>$(SolutionDir)..\..\SDL\VisualC\$(PlatformName)\$(Configuration);$(LibraryPath)</LibraryPath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <IncludePath>$(ProjectDir)..\include;$(ProjectDir)..\external\freetype\include;$(ProjectDir)..\external\harfbuzz\src;$(ProjectDir)..\..\SDL\include;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)..\include;$(ProjectDir)..\external\freetype\include;$(ProjectDir)..\external\harfbuzz\src;$(ProjectDir)..\external\plutosvg\source;$(ProjectDir)..\external\plutovg\include;$(ProjectDir)..\..\SDL\include;$(IncludePath)</IncludePath>
     <LibraryPath>$(SolutionDir)..\..\SDL\VisualC\$(PlatformName)\$(Configuration);$(LibraryPath)</LibraryPath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <IncludePath>$(ProjectDir)..\include;$(ProjectDir)..\external\freetype\include;$(ProjectDir)..\external\harfbuzz\src;$(ProjectDir)..\..\SDL\include;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)..\include;$(ProjectDir)..\external\freetype\include;$(ProjectDir)..\external\harfbuzz\src;$(ProjectDir)..\external\plutosvg\source;$(ProjectDir)..\external\plutovg\include;$(ProjectDir)..\..\SDL\include;$(IncludePath)</IncludePath>
     <LibraryPath>$(SolutionDir)..\..\SDL\VisualC\$(PlatformName)\$(Configuration);$(LibraryPath)</LibraryPath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -115,7 +115,7 @@
     </Midl>
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>DLL_EXPORT;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;TTF_USE_HARFBUZZ=1;FT_PUBLIC_FUNCTION_ATTRIBUTE=;FT_CONFIG_OPTION_USE_HARFBUZZ;FT2_BUILD_LIBRARY;HAVE_FREETYPE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>DLL_EXPORT;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;TTF_USE_HARFBUZZ=1;FT_PUBLIC_FUNCTION_ATTRIBUTE=;FT_CONFIG_OPTION_USE_HARFBUZZ;FT2_BUILD_LIBRARY;HAVE_FREETYPE;TTF_USE_PLUTOSVG=1;PLUTOSVG_HAS_FREETYPE;PLUTOSVG_BUILD_STATIC;PLUTOVG_BUILD_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>OldStyle</DebugInformationFormat>
@@ -143,7 +143,7 @@
     </Midl>
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>DLL_EXPORT;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;TTF_USE_HARFBUZZ=1;FT_PUBLIC_FUNCTION_ATTRIBUTE=;FT_CONFIG_OPTION_USE_HARFBUZZ;FT2_BUILD_LIBRARY;HAVE_FREETYPE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>DLL_EXPORT;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;TTF_USE_HARFBUZZ=1;FT_PUBLIC_FUNCTION_ATTRIBUTE=;FT_CONFIG_OPTION_USE_HARFBUZZ;FT2_BUILD_LIBRARY;HAVE_FREETYPE;TTF_USE_PLUTOSVG=1;PLUTOSVG_HAS_FREETYPE;PLUTOSVG_BUILD_STATIC;PLUTOVG_BUILD_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>OldStyle</DebugInformationFormat>
@@ -169,7 +169,7 @@
       </HeaderFileName>
     </Midl>
     <ClCompile>
-      <PreprocessorDefinitions>DLL_EXPORT;WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;TTF_USE_HARFBUZZ=1;FT_PUBLIC_FUNCTION_ATTRIBUTE=;FT_CONFIG_OPTION_USE_HARFBUZZ;FT2_BUILD_LIBRARY;HAVE_FREETYPE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>DLL_EXPORT;WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;TTF_USE_HARFBUZZ=1;FT_PUBLIC_FUNCTION_ATTRIBUTE=;FT_CONFIG_OPTION_USE_HARFBUZZ;FT2_BUILD_LIBRARY;HAVE_FREETYPE;TTF_USE_PLUTOSVG=1;PLUTOSVG_HAS_FREETYPE;PLUTOSVG_BUILD_STATIC;PLUTOVG_BUILD_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
       <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -196,7 +196,7 @@
       </HeaderFileName>
     </Midl>
     <ClCompile>
-      <PreprocessorDefinitions>DLL_EXPORT;WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;TTF_USE_HARFBUZZ=1;FT_PUBLIC_FUNCTION_ATTRIBUTE=;FT_CONFIG_OPTION_USE_HARFBUZZ;FT2_BUILD_LIBRARY;HAVE_FREETYPE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>DLL_EXPORT;WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;TTF_USE_HARFBUZZ=1;FT_PUBLIC_FUNCTION_ATTRIBUTE=;FT_CONFIG_OPTION_USE_HARFBUZZ;FT2_BUILD_LIBRARY;HAVE_FREETYPE;TTF_USE_PLUTOSVG=1;PLUTOSVG_HAS_FREETYPE;PLUTOSVG_BUILD_STATIC;PLUTOVG_BUILD_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
     </ClCompile>
@@ -328,6 +328,18 @@
     <ClCompile Include="..\external\harfbuzz\src\hb-uniscribe.cc" />
     <ClCompile Include="..\external\harfbuzz\src\hb-wasm-api.cc" />
     <ClCompile Include="..\external\harfbuzz\src\hb-wasm-shape.cc" />
+    <ClCompile Include="..\external\plutosvg\source\plutosvg.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-blend.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-canvas.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-font.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-ft-math.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-ft-raster.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-ft-stroker.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-matrix.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-paint.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-path.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-rasterize.c" />
+    <ClCompile Include="..\external\plutovg\source\plutovg-surface.c" />
     <ClCompile Include="..\src\SDL_gpu_textengine.c" />
     <ClCompile Include="..\src\SDL_hashtable.c" />
     <ClCompile Include="..\src\SDL_hashtable_ttf.c" />
@@ -339,6 +351,16 @@
     <ResourceCompile Include="..\src\version.rc" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\external\plutosvg\source\plutosvg.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-ft-math.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-ft-raster.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-ft-stroker.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-ft-types.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-private.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-stb-image-write.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-stb-image.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-stb-truetype.h" />
+    <ClInclude Include="..\external\plutovg\source\plutovg-utils.h" />
     <ClInclude Include="..\include\SDL3_ttf\SDL_ttf.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/VisualC/SDL_ttf.vcxproj.filters b/VisualC/SDL_ttf.vcxproj.filters
index db911717..5b843a7e 100644
--- a/VisualC/SDL_ttf.vcxproj.filters
+++ b/VisualC/SDL_ttf.vcxproj.filters
@@ -13,6 +13,9 @@
     <Filter Include="Sources\HarfBuzz">
       <UniqueIdentifier>{1adce3a3-3929-463e-9fc4-76aabd487471}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Sources\PlutoSVG">
+      <UniqueIdentifier>{12b2531a-b0bd-49fb-a66e-8397c3e7dcee}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\src\SDL_hashtable.c">
@@ -381,6 +384,42 @@
     <ClCompile Include="..\src\SDL_gpu_textengine.c">
       <Filter>Sources</Filter>
     </ClCompile>
+    <ClCompile Include="..\external\plutosvg\source\plutosvg.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-blend.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-canvas.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-font.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-ft-math.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-ft-raster.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-ft-stroker.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-matrix.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-paint.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-path.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-rasterize.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
+    <ClCompile Include="..\external\plutovg\source\plutovg-surface.c">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\src\version.rc">
@@ -391,5 +430,35 @@
     <ClInclude Include="..\include\SDL3_ttf\SDL_ttf.h">
       <Filter>Public Headers</Filter>
     </ClInclude>
+    <ClInclude Include="..\external\plutosvg\source\plutosvg.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-ft-math.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-ft-raster.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-ft-stroker.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-ft-types.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-private.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-stb-image.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-stb-image-write.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-stb-truetype.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
+    <ClInclude Include="..\external\plutovg\source\plutovg-utils.h">
+      <Filter>Sources\PlutoSVG</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
diff --git a/Xcode/SDL_ttf.xcodeproj/project.pbxproj b/Xcode/SDL_ttf.xcodeproj/project.pbxproj
index 08be75a7..2703c204 100644
--- a/Xcode/SDL_ttf.xcodeproj/project.pbxproj
+++ b/Xcode/SDL_ttf.xcodeproj/project.pbxproj
@@ -67,6 +67,28 @@
 		F341242E2D42C47A00D6C2B7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = F341242C2D42C47A00D6C2B7 /* README.md */; };
 		F34125C72D491AA800D6C2B7 /* SDL_hashtable_ttf.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125C52D491AA800D6C2B7 /* SDL_hashtable_ttf.h */; };
 		F34125C82D491AA800D6C2B7 /* SDL_hashtable_ttf.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125C62D491AA800D6C2B7 /* SDL_hashtable_ttf.c */; };
+		F34125922D4867F900D6C2B7 /* plutosvg.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125912D4867F900D6C2B7 /* plutosvg.c */; };
+		F34125942D486A1500D6C2B7 /* plutosvg.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125932D486A1500D6C2B7 /* plutosvg.h */; };
+		F34125A92D486A4900D6C2B7 /* plutovg-ft-math.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125992D486A4900D6C2B7 /* plutovg-ft-math.c */; };
+		F34125AA2D486A4900D6C2B7 /* plutovg-ft-raster.c in Sources */ = {isa = PBXBuildFile; fileRef = F341259B2D486A4900D6C2B7 /* plutovg-ft-raster.c */; };
+		F34125AB2D486A4900D6C2B7 /* plutovg-canvas.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125962D486A4900D6C2B7 /* plutovg-canvas.c */; };
+		F34125AC2D486A4900D6C2B7 /* plutovg-font.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125972D486A4900D6C2B7 /* plutovg-font.c */; };
+		F34125AD2D486A4900D6C2B7 /* plutovg-matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = F341259F2D486A4900D6C2B7 /* plutovg-matrix.c */; };
+		F34125AE2D486A4900D6C2B7 /* plutovg-rasterize.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125A32D486A4900D6C2B7 /* plutovg-rasterize.c */; };
+		F34125AF2D486A4900D6C2B7 /* plutovg-blend.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125952D486A4900D6C2B7 /* plutovg-blend.c */; };
+		F34125B02D486A4900D6C2B7 /* plutovg-surface.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125A72D486A4900D6C2B7 /* plutovg-surface.c */; };
+		F34125B12D486A4900D6C2B7 /* plutovg-path.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125A12D486A4900D6C2B7 /* plutovg-path.c */; };
+		F34125B22D486A4900D6C2B7 /* plutovg-paint.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125A02D486A4900D6C2B7 /* plutovg-paint.c */; };
+		F34125B32D486A4900D6C2B7 /* plutovg-ft-stroker.c in Sources */ = {isa = PBXBuildFile; fileRef = F341259D2D486A4900D6C2B7 /* plutovg-ft-stroker.c */; };
+		F34125B42D486A4900D6C2B7 /* plutovg-utils.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125A82D486A4900D6C2B7 /* plutovg-utils.h */; };
+		F34125B52D486A4900D6C2B7 /* plutovg-stb-truetype.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125A62D486A4900D6C2B7 /* plutovg-stb-truetype.h */; };
+		F34125B62D486A4900D6C2B7 /* plutovg-stb-image.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125A42D486A4900D6C2B7 /* plutovg-stb-image.h */; };
+		F34125B72D486A4900D6C2B7 /* plutovg-private.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125A22D486A4900D6C2B7 /* plutovg-private.h */; };
+		F34125B82D486A4900D6C2B7 /* plutovg-ft-raster.h in Headers */ = {isa = PBXBuildFile; fileRef = F341259A2D486A4900D6C2B7 /* plutovg-ft-raster.h */; };
+		F34125B92D486A4900D6C2B7 /* plutovg-ft-types.h in Headers */ = {isa = PBXBuildFile; fileRef = F341259E2D486A4900D6C2B7 /* plutovg-ft-types.h */; };
+		F34125BA2D486A4900D6C2B7 /* plutovg-stb-image-write.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125A52D486A4900D6C2B7 /* plutovg-stb-image-write.h */; };
+		F34125BB2D486A4900D6C2B7 /* plutovg-ft-stroker.h in Headers */ = {isa = PBXBuildFile; fileRef = F341259C2D486A4900D6C2B7 /* plutovg-ft-stroker.h */; };
+		F34125BC2D486A4900D6C2B7 /* plutovg-ft-math.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125982D486A4900D6C2B7 /* plutovg-ft-math.h */; };
 		F34400402D4033CE003F26D7 /* SDL3.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F344003F2D4033CE003F26D7 /* SDL3.framework */; };
 		F344FFBF2D3EB53C003F26D7 /* SDL_gpu_textengine.c in Sources */ = {isa = PBXBuildFile; fileRef = F344FFBE2D3EB53C003F26D7 /* SDL_gpu_textengine.c */; };
 		F3696FE4278F7107003A7F94 /* sdf.c in Sources */ = {isa = PBXBuildFile; fileRef = F3696FE3278F7107003A7F94 /* sdf.c */; };
@@ -195,6 +217,28 @@
 		F341242F2D42C49B00D6C2B7 /* INSTALL.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = INSTALL.md; sourceTree = "<group>"; };
 		F34125C52D491AA800D6C2B7 /* SDL_hashtable_ttf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_hashtable_ttf.h; sourceTree = "<group>"; };
 		F34125C62D491AA800D6C2B7 /* SDL_hashtable_ttf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hashtable_ttf.c; sourceTree = "<group>"; };
+		F34125912D4867F900D6C2B7 /* plutosvg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = plutosvg.c; path = ../external/plutosvg/source/plutosvg.c; sourceTree = "<group>"; };
+		F34125932D486A1500D6C2B7 /* plutosvg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = plutosvg.h; path = ../external/plutosvg/source/plutosvg.h; sourceTree = "<group>"; };
+		F34125952D486A4900D6C2B7 /* plutovg-blend.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-blend.c"; path = "../external/plutovg/source/plutovg-blend.c"; sourceTree = "<group>"; };
+		F34125962D486A4900D6C2B7 /* plutovg-canvas.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-canvas.c"; path = "../external/plutovg/source/plutovg-canvas.c"; sourceTree = "<group>"; };
+		F34125972D486A4900D6C2B7 /* plutovg-font.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-font.c"; path = "../external/plutovg/source/plutovg-font.c"; sourceTree = "<group>"; };
+		F34125982D486A4900D6C2B7 /* plutovg-ft-math.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-ft-math.h"; path = "../external/plutovg/source/plutovg-ft-math.h"; sourceTree = "<group>"; };
+		F34125992D486A4900D6C2B7 /* plutovg-ft-math.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-ft-math.c"; path = "../external/plutovg/source/plutovg-ft-math.c"; sourceTree = "<group>"; };
+		F341259A2D486A4900D6C2B7 /* plutovg-ft-raster.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-ft-raster.h"; path = "../external/plutovg/source/plutovg-ft-raster.h"; sourceTree = "<group>"; };
+		F341259B2D486A4900D6C2B7 /* plutovg-ft-raster.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-ft-raster.c"; path = "../external/plutovg/source/plutovg-ft-raster.c"; sourceTree = "<group>"; };
+		F341259C2D486A4900D6C2B7 /* plutovg-ft-stroker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-ft-stroker.h"; path = "../external/plutovg/source/plutovg-ft-stroker.h"; sourceTree = "<group>"; };
+		F341259D2D486A4900D6C2B7 /* plutovg-ft-stroker.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-ft-stroker.c"; path = "../external/plutovg/source/plutovg-ft-stroker.c"; sourceTree = "<group>"; };
+		F341259E2D486A4900D6C2B7 /* plutovg-ft-types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-ft-types.h"; path = "../external/plutovg/source/plutovg-ft-types.h"; sourceTree = "<group>"; };
+		F341259F2D486A4900D6C2B7 /* plutovg-matrix.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-matrix.c"; path = "../external/plutovg/source/plutovg-matrix.c"; sourceTree = "<group>"; };
+		F34125A02D486A4900D6C2B7 /* plutovg-paint.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-paint.c"; path = "../external/plutovg/source/plutovg-paint.c"; sourceTree = "<group>"; };
+		F34125A12D486A4900D6C2B7 /* plutovg-path.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-path.c"; path = "../external/plutovg/source/plutovg-path.c"; sourceTree = "<group>"; };
+		F34125A22D486A4900D6C2B7 /* plutovg-private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-private.h"; path = "../external/plutovg/source/plutovg-private.h"; sourceTree = "<group>"; };
+		F34125A32D486A4900D6C2B7 /* plutovg-rasterize.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-rasterize.c"; path = "../external/plutovg/source/plutovg-rasterize.c"; sourceTree = "<group>"; };
+		F34125A42D486A4900D6C2B7 /* plutovg-stb-image.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-stb-image.h"; path = "../external/plutovg/source/plutovg-stb-image.h"; sourceTree = "<group>"; };
+		F34125A52D486A4900D6C2B7 /* plutovg-stb-image-write.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-stb-image-write.h"; path = "../external/plutovg/source/plutovg-stb-image-write.h"; sourceTree = "<group>"; };
+		F34125A62D486A4900D6C2B7 /* plutovg-stb-truetype.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-stb-truetype.h"; path = "../external/plutovg/source/plutovg-stb-truetype.h"; sourceTree = "<group>"; };
+		F34125A72D486A4900D6C2B7 /* plutovg-surface.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "plutovg-surface.c"; path = "../external/plutovg/source/plutovg-surface.c"; sourceTree = "<group>"; };
+		F34125A82D486A4900D6C2B7 /* plutovg-utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "plutovg-utils.h"; path = "../external/plutovg/source/plutovg-utils.h"; sourceTree = "<group>"; };
 		F344003F2D4033CE003F26D7 /* SDL3.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SDL3.framework; sourceTree = "<group>"; };
 		F344FFBE2D3EB53C003F26D7 /* SDL_gpu_textengine.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_gpu_textengine.c; sourceTree = "<group>"; };
 		F3696FE3278F7107003A7F94 /* sdf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sdf.c; path = ../external/freetype/src/sdf/sdf.c; sourceTree = "<group>"; };
@@ -334,6 +378,7 @@
 		08FB77ACFE841707C02AAC07 /* Library Source */ = {
 			isa = PBXGroup;
 			children = (
+				F34125902D4867C400D6C2B7 /* PlutoSVG */,
 				F384BB6A261EC02C0028A248 /* FreeType */,
 				F384BD04261EC64F0028A248 /* HarfBuzz */,
 				F344FFBE2D3EB53C003F26D7 /* SDL_gpu_textengine.c */,
@@ -366,6 +411,35 @@
 			path = framework;
 			sourceTree = "<group>";
 		};
+		F34125902D4867C400D6C2B7 /* PlutoSVG */ = {
+			isa = PBXGroup;
+			children = (
+				F34125952D486A4900D6C2B7 /* plutovg-blend.c */,
+				F34125962D486A4900D6C2B7 /* plutovg-canvas.c */,
+				F34125972D486A4900D6C2B7 /* plutovg-font.c */,
+				F34125982D486A4900D6C2B7 /* plutovg-ft-math.h */,
+				F34125992D486A4900D6C2B7 /* plutovg-ft-math.c */,
+				F341259A2D486A4900D6C2B7 /* plutovg-ft-raster.h */,
+				F341259B2D486A4900D6C2B7 /* plutovg-ft-raster.c */,
+				F341259C2D486A4900D6C2B7 /* plutovg-ft-stroker.h */,
+				F341259D2D486A4900D6C2B7 /* plutovg-ft-stroker.c */,
+				F341259E2D486A4900D6C2B7 /* plutovg-ft-types.h */,
+				F341259F2D486A4900D6C2B7 /* plutovg-matrix.c */,
+				F34125A02D486A4900D6C2B7 /* plutovg-paint.c */,
+				F34125A12D486A4900D6C2B7 /* plutovg-path.c */,
+				F34125A22D486A4900D6C2B7 /* plutovg-private.h */,
+				F34125A32D486A4900D6C2B7 /* plutovg-rasterize.c */,
+				F34125A42D486A4900D6C2B7 /* plutovg-stb-image.h */,
+				F34125A52D486A4900D6C2B7 /* plutovg-stb-image-write.h */,
+				F34125A62D486A4900D6C2B7 /* plutovg-stb-truetype.h */,
+				F34125A72D486A4900D6C2B7 /* plutovg-surface.c */,
+				F34125A82D486A4900D6C2B7 /* plutovg-utils.h */,
+				F34125932D486A1500D6C2B7 /* plutosvg.h */,
+				F34125912D4867F900D6C2B7 /* plutosvg.c */,
+			);
+			name = PlutoSVG;
+			sourceTree = "<group>";
+		};
 		F384BB6A261EC02C0028A248 /* FreeType */ = {
 			isa = PBXGroup;
 			children = (
@@ -505,6 +579,16 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				F34125B42D486A4900D6C2B7 /* plutovg-utils.h in Headers */,
+				F34125B52D486A4900D6C2B7 /* plutovg-stb-truetype.h in Headers */,
+				F34125B62D486A4900D6C2B7 /* plutovg-stb-image.h in Headers */,
+				F34125B72D486A4900D6C2B7 /* plutovg-private.h in Headers */,
+				F34125B82D486A4900D6C2B7 /* plutovg-ft-raster.h in Headers */,
+				F34125B92D486A4900D6C2B7 /* plutovg-ft-types.h in Headers */,
+				F34125BA2D486A4900D6C2B7 /* plutovg-stb-image-write.h in Headers */,
+				F34125BB2D486A4900D6C2B7 /* plutovg-ft-stroker.h in Headers */,
+				F34125BC2D486A4900D6C2B7 /* plutovg-ft-math.h in Headers */,
+				F34125942D486A1500D6C2B7 /* plutosvg.h in Headers */,
 				F3F7BDF72CB6FD6700C984AF /* SDL_hashtable.h in Headers */,
 				F34125C72D491AA800D6C2B7 /* SDL_hashtable_ttf.h in Headers */,
 				F3F7BDF82CB6FD6700C984AF /* stb_rect_pack.h in Headers */,
@@ -671,6 +755,17 @@
 				61047EBA2B48AD0F00868128 /* hb-ot-color.cc in Sources */,
 				61047EB42B48AD0F00868128 /* hb-ot-shaper-thai.cc in Sources */,
 				61047EA42B48AD0F00868128 /* hb-ot-shaper-syllabic.cc in Sources */,
+				F34125A92D486A4900D6C2B7 /* plutovg-ft-math.c in Sources */,
+				F34125AA2D486A4900D6C2B7 /* plutovg-ft-raster.c in Sources */,
+				F34125AB2D486A4900D6C2B7 /* plutovg-canvas.c in Sources */,
+				F34125AC2D486A4900D6C2B7 /* plutovg-font.c in Sources */,
+				F34125AD2D486A4900D6C2B7 /* plutovg-matrix.c in Sources */,
+				F34125AE2D486A4900D6C2B7 /* plutovg-rasterize.c in Sources */,
+				F34125AF2D486A4900D6C2B7 /* plutovg-blend.c in Sources */,
+				F34125B02D486A4900D6C2B7 /* plutovg-surface.c in Sources */,
+				F34125B12D486A4900D6C2B7 /* plutovg-path.c in Sources */,
+				F34125B22D486A4900D6C2B7 /* plutovg-paint.c 

(Patch may be truncated, please check the link at the top of this post.)