Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8a11b3c
mbedTLS fix for cURL 8.8.0
Lpsd May 24, 2024
181bf0f
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd May 24, 2024
6728cbe
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd May 25, 2024
0b989ac
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd May 26, 2024
9c19509
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jun 2, 2024
75c36ed
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jun 19, 2024
96dd1ee
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 2, 2024
f9eaf3f
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 8, 2024
54bd11b
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 10, 2024
ddee2d0
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 19, 2024
288b8db
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 21, 2024
b30a4a2
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Oct 22, 2024
27b9eae
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Dec 17, 2024
3731d81
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jan 14, 2025
b50a68c
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jan 22, 2025
58ae23f
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Feb 19, 2025
f3645b8
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Mar 4, 2025
e62d9f4
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Mar 14, 2025
3346e9c
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Mar 16, 2025
95dfc97
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Sep 6, 2025
3307dc6
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Sep 14, 2025
f091a85
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Sep 24, 2025
c66e5de
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Nov 7, 2025
c132ae1
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Nov 9, 2025
5739ef0
Merge branch 'master' of https://github.com/multitheftauto/mtasa-blue
Lpsd Jan 7, 2026
41f7bfa
Update lunasvg vendor to 3.5.0
Lpsd Jan 7, 2026
3a613f2
Update premake5.lua
Lpsd Jan 7, 2026
969dfec
Allow custom resource fonts
Lpsd Jan 7, 2026
892cc22
Merge branch 'master' into lunasvg-3.5.0
Lpsd Jan 7, 2026
7c29995
Revert "Allow custom resource fonts"
Lpsd Jan 8, 2026
fbfd66c
Re-introduce sanity checks
Lpsd Jan 8, 2026
3f16442
Reapply "Allow custom resource fonts"
Lpsd Jan 8, 2026
c37786d
Merge branch 'master' into lunasvg-fonts
Lpsd Jan 8, 2026
0cc6405
Add check for existing font on register
Lpsd Jan 8, 2026
6874010
Avoid memcpy in font registration
Lpsd Jan 8, 2026
9fae239
Use key view in GetRegisteredFonts
Lpsd Jan 8, 2026
4cbba65
Use map.contains in IsFontRegistered
Lpsd Jan 8, 2026
96e8601
Update comments (todo)
Lpsd Jan 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Client/mods/deathmatch/logic/CClientVectorGraphic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ bool CClientVectorGraphic::SetDocument(CXMLNode* node)
m_pXMLDocument = node;
m_pSVGDocument = lunasvg::Document::loadFromData(node->ToString());

// Check if LunaSVG successfully parsed the document
if (!m_pSVGDocument)
return false;

m_pVectorGraphicDisplay->Update();

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ void CClientVectorGraphicDisplay::UpdateTexture()
if (!surface)
return;

// Check for valid SVG dimensions to avoid division by zero
if (svgDocument->width() <= 0 || svgDocument->height() <= 0)
return;

// SVG has a predefined width and height. We need transform it to the requested size
const Matrix transformationMatrix(pVectorGraphicItem->m_uiSizeX / svgDocument->width(), 0, 0, pVectorGraphicItem->m_uiSizeY / svgDocument->height(), 0, 0);

Expand Down
4 changes: 4 additions & 0 deletions Client/mods/deathmatch/logic/CResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define DECLARE_PROFILER_SECTION_CResource
#include "profiler/SharedUtil.Profiler.h"
#include "CServerIdManager.h"
#include "CSVGFontManager.h"

using namespace std;

Expand Down Expand Up @@ -94,6 +95,9 @@ CResource::CResource(unsigned short usNetID, const char* szResourceName, CClient

CResource::~CResource()
{
// Unregister SVG fonts registered by this resource
CSVGFontManager::GetSingleton().UnregisterResourceFonts(this);

// Remove refrences from requested models
m_modelStreamer.ReleaseAll();

Expand Down
139 changes: 139 additions & 0 deletions Client/mods/deathmatch/logic/CSVGFontManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
*
* Multi Theft Auto is available from https://www.multitheftauto.com/
*
*****************************************************************************/

#include "StdInc.h"
#include "CSVGFontManager.h"
#include <lunasvg.h>
#include <ranges>

CSVGFontManager& CSVGFontManager::GetSingleton()
{
static CSVGFontManager instance;
return instance;
}

void CSVGFontManager::FontDataDestroyCallback(void* pData)
{
// We don't need to worry about our own tracking here (already handled), just free the memory
delete[] static_cast<char*>(pData);
}

bool CSVGFontManager::RegisterFont(const SString& strFontFamily, const SString& strFontPath, CResource* pResource)
{
if (strFontFamily.empty() || strFontPath.empty() || !pResource)
return false;

if (IsFontRegistered(strFontFamily))
return false;

SString strAbsPath;
SString strMetaPath;

CResource* pFileResource = pResource;
if (!g_pClientGame->GetResourceManager()->ParseResourcePathInput(strFontPath, pFileResource, &strAbsPath, &strMetaPath))
return false;

if (!FileExists(strAbsPath))
return false;

// Get file size
uint64 fileSize = FileSize(strAbsPath);
if (fileSize == 0 || fileSize > 10 * 1024 * 1024) // max 10MB
return false;

// Allocate memory for font data that will be owned by LunaSVG
size_t dataSize = static_cast<size_t>(fileSize);
char* pFontData = new (std::nothrow) char[dataSize];
if (!pFontData)
return false;

// Read file directly into our allocated buffer
FILE* pFile = File::Fopen(strAbsPath, "rb");
if (!pFile)
{
delete[] pFontData;
return false;
}

size_t bytesRead = fread(pFontData, 1, dataSize, pFile);
fclose(pFile);

if (bytesRead != dataSize)
{
delete[] pFontData;
return false;
}

// Register font with LunaSVG using data API
// LunaSVG takes ownership of the data, we provide a callback to implement destruct behaviour, and notify when we're done
if (!lunasvg_add_font_face_from_data(strFontFamily.c_str(), false, false, pFontData, dataSize, FontDataDestroyCallback, pFontData))
{
// Registration failed, clean up the memory ourselves
delete[] pFontData;
return false;
}

// Store font info for tracking
SFontInfo fontInfo;
fontInfo.strOriginalPath = strFontPath;
fontInfo.strAbsolutePath = strAbsPath;
fontInfo.pOwnerResource = pResource;

m_RegisteredFonts[strFontFamily] = std::move(fontInfo);

return true;
}

bool CSVGFontManager::UnregisterFont(const SString& strFontFamily)
{
auto it = m_RegisteredFonts.find(strFontFamily);
if (it == m_RegisteredFonts.end())
return false;

// TODO: unregister font face with lunasvg here (see https://github.com/sammycage/lunasvg/issues/258)
m_RegisteredFonts.erase(it);
return true;
}

bool CSVGFontManager::IsFontRegistered(const SString& strFontFamily) const
{
return m_RegisteredFonts.contains(strFontFamily);
}

CResource* CSVGFontManager::GetFontOwnerResource(const SString& strFontFamily) const
{
auto it = m_RegisteredFonts.find(strFontFamily);
if (it != m_RegisteredFonts.end())
return it->second.pOwnerResource;
return nullptr;
}

void CSVGFontManager::UnregisterResourceFonts(CResource* pResource)
{
if (!pResource)
return;

// Collect fonts to remove
std::vector<SString> fontsToRemove;
for (const auto& pair : m_RegisteredFonts)
{
if (pair.second.pOwnerResource == pResource)
fontsToRemove.push_back(pair.first);
}

// Remove collected fonts from our tracking
for (const auto& fontFamily : fontsToRemove)
UnregisterFont(fontFamily);
}

std::vector<SString> CSVGFontManager::GetRegisteredFonts() const
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetRegisteredFonts is never called

{
auto keys = std::views::keys(m_RegisteredFonts);
return {keys.begin(), keys.end()};
}
49 changes: 49 additions & 0 deletions Client/mods/deathmatch/logic/CSVGFontManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
*
* Multi Theft Auto is available from https://www.multitheftauto.com/
*
*****************************************************************************/

#pragma once

#include <string>
#include <map>
#include <vector>

class CResource;

class CSVGFontManager
{
public:
struct SFontInfo
{
SString strOriginalPath; // Original resource path for debugging
SString strAbsolutePath; // Absolute path to font file
CResource* pOwnerResource; // Resource that registered this font
};

static CSVGFontManager& GetSingleton();


bool RegisterFont(const SString& strFontFamily, const SString& strFontPath, CResource* pResource);
bool UnregisterFont(const SString& strFontFamily);
bool IsFontRegistered(const SString& strFontFamily) const;
CResource* GetFontOwnerResource(const SString& strFontFamily) const;
void UnregisterResourceFonts(CResource* pResource);
std::vector<SString> GetRegisteredFonts() const;

private:
CSVGFontManager() = default;
~CSVGFontManager() = default;

CSVGFontManager(const CSVGFontManager&) = delete;
CSVGFontManager& operator=(const CSVGFontManager&) = delete;

static void FontDataDestroyCallback(void* pData);

// Fonts we're currently tracking (owned by resources)
std::map<SString, SFontInfo> m_RegisteredFonts;
};
47 changes: 46 additions & 1 deletion Client/mods/deathmatch/logic/luadefs/CLuaVectorGraphicDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "StdInc.h"
#include "lua/CLuaFunctionParser.h"
#include "CLuaVectorGraphicDefs.h"
#include "../CSVGFontManager.h"

void CLuaVectorGraphicDefs::LoadFunctions()
{
Expand All @@ -20,7 +21,8 @@ void CLuaVectorGraphicDefs::LoadFunctions()
{"svgGetSize", ArgumentParser<SVGGetSize>},
{"svgSetSize", ArgumentParser<SVGSetSize>},
{"svgSetUpdateCallback", ArgumentParser<SVGSetUpdateCallback>},

{"svgRegisterFont", ArgumentParser<SVGRegisterFont>},
{"svgUnregisterFont", ArgumentParser<SVGUnregisterFont>},
};

// Add functions
Expand Down Expand Up @@ -271,3 +273,46 @@ std::variant<CLuaFunctionRef, bool> CLuaVectorGraphicDefs::SVGGetUpdateCallback(

return false;
}

bool CLuaVectorGraphicDefs::SVGRegisterFont(lua_State* luaVM, std::string fontFamily, std::string fontPath)
{
if (fontFamily.empty())
throw std::invalid_argument("Font family name cannot be empty");

if (fontPath.empty())
throw std::invalid_argument("Font path cannot be empty");

CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM);
if (!pLuaMain)
return false;

CResource* pResource = pLuaMain->GetResource();
if (!pResource)
return false;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should emit a warning when the font is registered already? I think right now it just returns false.

Bonus points if the warning message includes the name of the resource that registered the font

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented

// Check if the font is already registered
CSVGFontManager& fontManager = CSVGFontManager::GetSingleton();
if (fontManager.IsFontRegistered(fontFamily))
{
CResource* pOwnerResource = fontManager.GetFontOwnerResource(fontFamily);
if (pOwnerResource)
{
m_pScriptDebugging->LogWarning(luaVM, "Font '%s' is already registered by resource '%s'", fontFamily.c_str(), pOwnerResource->GetName());
}
else
{
m_pScriptDebugging->LogWarning(luaVM, "Font '%s' is already registered", fontFamily.c_str());
}
return false;
}

return fontManager.RegisterFont(fontFamily, fontPath, pResource);
}

bool CLuaVectorGraphicDefs::SVGUnregisterFont(std::string fontFamily)
{
if (fontFamily.empty())
throw std::invalid_argument("Font family name cannot be empty");

return CSVGFontManager::GetSingleton().UnregisterFont(fontFamily);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class CLuaVectorGraphicDefs : public CLuaDefs
static CLuaMultiReturn<int, int> SVGGetSize(CClientVectorGraphic* vectorGraphic);
static bool SVGSetSize(CClientVectorGraphic* vectorGraphic, CVector2D size, std::optional<CLuaFunctionRef> luaFunctionRef);

// Font management functions
static bool SVGRegisterFont(lua_State* luaVM, std::string fontFamily, std::string fontPath);
static bool SVGUnregisterFont(std::string fontFamily);

private:
static bool LoadFromData(lua_State* luaVM, CClientVectorGraphic* vectorGraphic, std::string rawData);
static bool LoadFromFile(lua_State* luaVM, CClientVectorGraphic* vectorGraphic, CScriptFile* file, std::string path, CResource* parentResource);
Expand Down
Loading
Loading