From df328996253e17a6e27e57a8237625ade35b24de Mon Sep 17 00:00:00 2001 From: Dutchman101 <12105539+Dutchman101@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:26:53 +0000 Subject: [PATCH 01/16] json-c: Fix crash on Linux64 Missing define led to a server crash that involves json_tokener_parse_ex (called by CLuaArguments::ReadFromJSONString) --- vendor/json-c/config-linux.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vendor/json-c/config-linux.h b/vendor/json-c/config-linux.h index 784b350e9c..0a185d1e98 100644 --- a/vendor/json-c/config-linux.h +++ b/vendor/json-c/config-linux.h @@ -137,6 +137,9 @@ /* Define to 1 if you have the `uselocale' function. */ #define HAVE_USELOCALE +/* Define to 1 if you have the `duplocale' function. */ +#define HAVE_DUPLOCALE + /* Define to 1 if you have the `vasprintf' function. */ #define HAVE_VASPRINTF From 215173eeb1e015c0381ce94f95429c36ab1b4430 Mon Sep 17 00:00:00 2001 From: Marek Kulik Date: Mon, 3 Mar 2025 22:45:12 +0100 Subject: [PATCH 02/16] Update splash window --- Client/core/CCore.cpp | 78 ++- Client/core/CGUI.cpp | 24 +- Client/core/CMainMenu.cpp | 35 +- Client/core/CMainMenu.h | 2 +- Client/game_sa/CGameSA.cpp | 8 - Client/game_sa/CGameSA.h | 2 - Client/loader/Dialogs.cpp | 212 -------- Client/loader/Dialogs.h | 4 +- Client/loader/SplashWindow.cpp | 624 +++++++++++++++++++++++ Client/loader/loader.rc | 1 + Client/loader/resource.h | 1 + Client/loader/resource/color-strip.bmp | Bin 0 -> 11078 bytes Client/loader/resource/splash.bmp | Bin 491078 -> 1500056 bytes Client/multiplayer_sa/CMultiplayerSA.cpp | 4 + Client/sdk/game/CGame.h | 1 - 15 files changed, 669 insertions(+), 327 deletions(-) create mode 100644 Client/loader/SplashWindow.cpp create mode 100644 Client/loader/resource/color-strip.bmp diff --git a/Client/core/CCore.cpp b/Client/core/CCore.cpp index 782d436d6e..972955e43b 100644 --- a/Client/core/CCore.cpp +++ b/Client/core/CCore.cpp @@ -1233,71 +1233,51 @@ void CCore::DoPostFramePulse() m_pGUI->SelectInputHandlers(INPUT_CORE); } - if (m_pGame->GetSystemState() == 5) // GS_INIT_ONCE - { - WatchDogCompletedSection("L2"); // gta_sa.set seems ok - WatchDogCompletedSection("L3"); // No hang on startup - } - // This is the first frame in the menu? if (m_pGame->GetSystemState() == 7) // GS_FRONTEND { - // Wait 250 frames more than the time it took to get status 7 (fade-out time) - static short WaitForMenu = 0; + if (m_bFirstFrame) + { + m_bFirstFrame = false; - // Do crash dump encryption while the credit screen is displayed - if (WaitForMenu == 0) + WatchDogCompletedSection("L2"); // gta_sa.set seems ok + WatchDogCompletedSection("L3"); // No hang on startup HandleCrashDumpEncryption(); - // Cope with early finish - if (m_pGame->HasCreditScreenFadedOut()) - WaitForMenu = 250; + // Disable vsync while it's all dark + m_pGame->DisableVSync(); - if (WaitForMenu >= 250) - { - if (m_bFirstFrame) + // Parse the command line + // Does it begin with mtasa://? + if (m_szCommandLineArgs && strnicmp(m_szCommandLineArgs, "mtasa://", 8) == 0) { - m_bFirstFrame = false; - - // Disable vsync while it's all dark - m_pGame->DisableVSync(); - - // Parse the command line - // Does it begin with mtasa://? - if (m_szCommandLineArgs && strnicmp(m_szCommandLineArgs, "mtasa://", 8) == 0) + SString strArguments = GetConnectCommandFromURI(m_szCommandLineArgs); + // Run the connect command + if (strArguments.length() > 0 && !m_pCommands->Execute(strArguments)) { - SString strArguments = GetConnectCommandFromURI(m_szCommandLineArgs); - // Run the connect command - if (strArguments.length() > 0 && !m_pCommands->Execute(strArguments)) - { - ShowMessageBox(_("Error") + _E("CC41"), _("Error executing URL"), MB_BUTTON_OK | MB_ICON_ERROR); - } + ShowMessageBox(_("Error") + _E("CC41"), _("Error executing URL"), MB_BUTTON_OK | MB_ICON_ERROR); } - else + } + else + { + // We want to load a mod? + const char* szOptionValue; + if (szOptionValue = GetCommandLineOption("l")) { - // We want to load a mod? - const char* szOptionValue; - if (szOptionValue = GetCommandLineOption("l")) - { - // Try to load the mod - if (!m_pModManager->Load(szOptionValue, m_szCommandLineArgs)) - { - SString strTemp(_("Error running mod specified in command line ('%s')"), szOptionValue); - ShowMessageBox(_("Error") + _E("CC42"), strTemp, MB_BUTTON_OK | MB_ICON_ERROR); // Command line Mod load failed - } - } - // We want to connect to a server? - else if (szOptionValue = GetCommandLineOption("c")) + // Try to load the mod + if (!m_pModManager->Load(szOptionValue, m_szCommandLineArgs)) { - CCommandFuncs::Connect(szOptionValue); + SString strTemp(_("Error running mod specified in command line ('%s')"), szOptionValue); + ShowMessageBox(_("Error") + _E("CC42"), strTemp, MB_BUTTON_OK | MB_ICON_ERROR); // Command line Mod load failed } } + // We want to connect to a server? + else if (szOptionValue = GetCommandLineOption("c")) + { + CCommandFuncs::Connect(szOptionValue); + } } } - else - { - WaitForMenu++; - } if (m_bWaitToSetNick && GetLocalGUI()->GetMainMenu()->IsVisible() && !GetLocalGUI()->GetMainMenu()->IsFading()) { diff --git a/Client/core/CGUI.cpp b/Client/core/CGUI.cpp index 6273536347..b46b7ebd87 100644 --- a/Client/core/CGUI.cpp +++ b/Client/core/CGUI.cpp @@ -158,7 +158,8 @@ void CLocalGUI::CreateWindows(bool bGameIsAlreadyLoaded) m_pLabelVersionTag->SetTextColor(255, 255, 255); m_pLabelVersionTag->SetZOrderingEnabled(false); m_pLabelVersionTag->MoveToBack(); - m_pLabelVersionTag->SetVisible(false); + if (MTASA_VERSION_TYPE < VERSION_TYPE_RELEASE) + m_pLabelVersionTag->SetAlwaysOnTop(true); // Create mainmenu m_pMainMenu = new CMainMenu(pGUI); @@ -286,27 +287,6 @@ void CLocalGUI::Draw() // Update mainmenu stuff m_pMainMenu->Update(); - // Make sure our version labels are always visible - static short WaitForMenu = 0; - - // Cope with early finish - if (pGame->HasCreditScreenFadedOut()) - WaitForMenu = 250; - - if (SystemState == 7 || SystemState == 9) - { - if (WaitForMenu < 250) - { - WaitForMenu++; - } - else - { - m_pLabelVersionTag->SetVisible(true); - if (MTASA_VERSION_TYPE < VERSION_TYPE_RELEASE) - m_pLabelVersionTag->SetAlwaysOnTop(true); - } - } - // If we're ingame, make sure the chatbox is drawn bool bChatVisible = (SystemState == 9 /* GS_INGAME */ && m_pMainMenu->GetIsIngame() && m_bChatboxVisible && !CCore::GetSingleton().IsOfflineMod()); if (m_pChat->IsVisible() != bChatVisible) diff --git a/Client/core/CMainMenu.cpp b/Client/core/CMainMenu.cpp index 1ef82a75c6..afc5d6967f 100644 --- a/Client/core/CMainMenu.cpp +++ b/Client/core/CMainMenu.cpp @@ -48,7 +48,6 @@ #define CORE_MTA_FILLER "cgui\\images\\mta_filler.png" #define CORE_MTA_VERSION "cgui\\images\\version.png" -static int WaitForMenu = 0; static const SColor headlineColors[] = {SColorRGBA(233, 234, 106, 255), SColorRGBA(233 / 6 * 4, 234 / 6 * 4, 106 / 6 * 4, 255), SColorRGBA(233 / 7 * 3, 234 / 7 * 3, 106 / 7 * 3, 255)}; @@ -70,11 +69,10 @@ CMainMenu::CMainMenu(CGUI* pManager) // Initialize m_pManager = pManager; - m_bIsVisible = false; + m_bIsVisible = true; m_bIsFullyVisible = false; m_bIsIngame = true; // m_bIsInSubWindow = false; - m_bStarted = false; m_fFader = 0; m_ucFade = FADE_INVISIBLE; m_bCursorAlphaReset = false; @@ -656,37 +654,15 @@ void CMainMenu::Update() // Force the mainmenu on if we're at GTA's mainmenu or not ingame if ((SystemState == 7 || SystemState == 9) && !m_bIsIngame) { - // Cope with early finish - if (pGame->HasCreditScreenFadedOut()) - WaitForMenu = std::max(WaitForMenu, 250); - - // Fade up - if (WaitForMenu >= 250) + if (!m_bStarted) { - m_bIsVisible = true; m_bStarted = true; - } - // Create headlines while the screen is still black - if (WaitForMenu == 250) m_pNewsBrowser->CreateHeadlines(); - - // Start updater after fade up is complete - if (WaitForMenu == 275) GetVersionUpdater()->EnableChecking(true); -#if _WIN32_WINNT <= _WIN32_WINNT_WINXP - if (WaitForMenu == 275) - { - CCore::GetSingletonPtr()->ShowErrorMessageBox("", XP_VISTA_WARNING, "au-revoir-xp-vista"); - } -#endif - - if (WaitForMenu == 299) - { - if (!g_pCore->GetCVars()->GetValue("discord_rpc_share_data_firsttime", false) - && g_pCore->GetCVars()->GetValue("allow_discord_rpc", false) - && !g_pCore->GetCVars()->GetValue("discord_rpc_share_data", false)) + if (!g_pCore->GetCVars()->GetValue("discord_rpc_share_data_firsttime", false) && g_pCore->GetCVars()->GetValue("allow_discord_rpc", false) && + !g_pCore->GetCVars()->GetValue("discord_rpc_share_data", false)) { m_Settings.ShowRichPresenceShareDataQuestionBox(); CVARS_SET("discord_rpc_share_data_firsttime", true); @@ -694,9 +670,6 @@ void CMainMenu::Update() else CVARS_SET("discord_rpc_share_data_firsttime", true); } - - if (WaitForMenu < 300) - WaitForMenu++; } // If we're visible diff --git a/Client/core/CMainMenu.h b/Client/core/CMainMenu.h index 72b549f01e..10dd2e4e60 100644 --- a/Client/core/CMainMenu.h +++ b/Client/core/CMainMenu.h @@ -144,7 +144,7 @@ class CMainMenu int m_menuBY; CGraphics* m_pGraphics; - bool m_bStarted; + bool m_bStarted{false}; CVector2D m_ScreenSize; // Fade variables diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 49992830d9..bbb0b7c00e 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -1041,14 +1041,6 @@ void CGameSA::SetupBrokenModels() FixModelCol(3553, 3554); } -// Well, has it? -bool CGameSA::HasCreditScreenFadedOut() -{ - BYTE ucAlpha = *(BYTE*)0xBAB320; // CLoadingScreen::m_FadeAlpha - bool bCreditScreenFadedOut = (GetSystemState() >= 7) && (ucAlpha < 6); - return bCreditScreenFadedOut; -} - // Ensure replaced/restored textures for models in the GTA map are correct void CGameSA::FlushPendingRestreamIPL() { diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index 5c659d458d..f637f5a4c5 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -280,8 +280,6 @@ class CGameSA : public CGame void SuspendASyncLoading(bool bSuspend, uint uiAutoUnsuspendDelay = 0); bool IsASyncLoadingEnabled(bool bIgnoreSuspend = false); - bool HasCreditScreenFadedOut(); - void SetupSpecialCharacters(); void FixModelCol(uint iFixModel, uint iFromModel); void SetupBrokenModels(); diff --git a/Client/loader/Dialogs.cpp b/Client/loader/Dialogs.cpp index eb450ff55e..041a5c8d5d 100644 --- a/Client/loader/Dialogs.cpp +++ b/Client/loader/Dialogs.cpp @@ -19,8 +19,6 @@ static bool bCancelPressed = false; static bool bOkPressed = false; static bool bOtherPressed = false; static int iOtherCode = 0; -static WNDCLASS splashWindowClass{}; -static HWND splashWindow{}; static HWND hwndProgressDialog = NULL; static unsigned long ulProgressStartTime = 0; static HWND hwndCrashedDialog = NULL; @@ -28,100 +26,6 @@ static HWND hwndGraphicsDllDialog = NULL; static HWND hwndOptimusDialog = NULL; static HWND hwndNoAvDialog = NULL; -/** - * @brief Automatically destroys a window on scope-exit. - */ -struct WindowScope -{ - WindowScope(HWND handle_) noexcept : handle(handle_) {} - - ~WindowScope() noexcept { DestroyWindow(handle); } - - [[nodiscard]] HWND Release() noexcept { return std::exchange(handle, nullptr); } - - HWND handle{}; -}; - -/** - * @brief Provides a compatible memory-only device context for a bitmap handle and - * automatically destroys the device context and bitmap on scope-exit. - */ -struct BitmapScope -{ - BitmapScope(HDC deviceContext_, HBITMAP bitmap_) noexcept : bitmap(bitmap_) - { - if (bitmap != nullptr) - { - if (deviceContext = CreateCompatibleDC(deviceContext_)) - { - previousObject = SelectObject(deviceContext, bitmap_); - } - } - } - - ~BitmapScope() noexcept - { - if (previousObject && previousObject != HGDI_ERROR) - SelectObject(deviceContext, previousObject); - - if (deviceContext) - DeleteDC(deviceContext); - - if (bitmap) - DeleteObject(bitmap); - } - - HDC deviceContext{}; - HGDIOBJ previousObject{}; - HBITMAP bitmap{}; -}; - -/** - * @brief Returns the dots per inch (dpi) value for the specified window. - */ -UINT GetWindowDpi(HWND window) -{ - // Minimum version: Windows 10, version 1607 - using GetDpiForWindow_t = UINT(WINAPI*)(HWND); - - static GetDpiForWindow_t Win32GetDpiForWindow = ([] { - HMODULE user32 = LoadLibrary("user32"); - return user32 ? reinterpret_cast(static_cast(GetProcAddress(user32, "GetDpiForWindow"))) : nullptr; - })(); - - if (Win32GetDpiForWindow) - return Win32GetDpiForWindow(window); - - HDC screenDC = GetDC(NULL); - auto x = static_cast(GetDeviceCaps(screenDC, LOGPIXELSX)); - ReleaseDC(NULL, screenDC); - return x; -} - -/** - * @brief Returns the width and height of the primary monitor. - */ -SIZE GetPrimaryMonitorSize() -{ - POINT zero{}; - HMONITOR primaryMonitor = MonitorFromPoint(zero, MONITOR_DEFAULTTOPRIMARY); - - MONITORINFO monitorInfo{}; - monitorInfo.cbSize = sizeof(monitorInfo); - GetMonitorInfo(primaryMonitor, &monitorInfo); - - const RECT& work = monitorInfo.rcWork; - return {work.right - work.left, work.bottom - work.top}; -} - -/** - * @brief Scales the value from the default screen dpi (96) to the provided dpi. - */ -LONG ScaleToDpi(LONG value, UINT dpi) -{ - return static_cast(ceil(value * static_cast(dpi) / USER_DEFAULT_SCREEN_DPI)); -} - /////////////////////////////////////////////////////////////////////////// // // Dialog strings @@ -277,122 +181,6 @@ int CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return FALSE; } -// -// Show splash dialog -// -void ShowSplash(HINSTANCE hInstance) -{ -#ifndef MTA_DEBUG - if (splashWindowClass.hInstance != hInstance) - { - splashWindowClass.lpfnWndProc = DefWindowProc; - splashWindowClass.hInstance = hInstance; - splashWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW); - splashWindowClass.hIcon = LoadIconA(GetModuleHandle(nullptr), MAKEINTRESOURCE(110)); // IDI_ICON1 from Launcher - splashWindowClass.lpszClassName = TEXT("SplashWindow"); - RegisterClass(&splashWindowClass); - } - - if (splashWindow) - { - ShowWindow(splashWindow, SW_SHOW); - } - else - { - WindowScope window(CreateWindowEx(WS_EX_LAYERED, splashWindowClass.lpszClassName, "Multi Theft Auto Launcher", WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, NULL, - NULL, hInstance, NULL)); - - if (!window.handle) - return; - - UINT dpi = GetWindowDpi(window.handle); - SIZE monitorSize = GetPrimaryMonitorSize(); - - POINT origin{}; - SIZE windowSize{ScaleToDpi(500, dpi), ScaleToDpi(245, dpi)}; - origin.x = (monitorSize.cx - windowSize.cx) / 2; - origin.y = (monitorSize.cy - windowSize.cy) / 2; - - HDC windowHDC = GetWindowDC(window.handle); - { - BitmapScope unscaled(windowHDC, LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1))); - - if (!unscaled.bitmap) - return; - - BitmapScope scaled(windowHDC, CreateCompatibleBitmap(windowHDC, windowSize.cx, windowSize.cy)); - - if (!scaled.bitmap) - return; - - BITMAP bitmap{}; - GetObject(unscaled.bitmap, sizeof(bitmap), &bitmap); - - // Draw the unscaled bitmap to the window-scaled bitmap. - SetStretchBltMode(scaled.deviceContext, HALFTONE); - StretchBlt(scaled.deviceContext, 0, 0, windowSize.cx, windowSize.cy, unscaled.deviceContext, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY); - - // Update the splash window and draw the scaled bitmap. - POINT zero{}; - BLENDFUNCTION blend{AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - UpdateLayeredWindow(window.handle, windowHDC, &origin, &windowSize, scaled.deviceContext, &zero, RGB(0, 0, 0), &blend, 0); - } - ReleaseDC(window.handle, windowHDC); - - splashWindow = window.Release(); - } - - SetForegroundWindow(splashWindow); - SetWindowPos(splashWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - - // Drain messages to allow for repaint in case picture bits were lost during previous operations - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) - { - if (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } -#endif -} - -// -// Hide splash dialog -// -void HideSplash() -{ - if (splashWindow) - { - DestroyWindow(splashWindow); - splashWindow = {}; - } -} - -// -// Hide splash dialog temporarily -// -void SuspendSplash() -{ - if (splashWindow) - { - ShowWindow(splashWindow, SW_HIDE); - } -} - -// -// Show splash dialog if was previously suspended -// -void ResumeSplash() -{ - if (splashWindow) - { - HideSplash(); - ShowSplash(g_hInstance); - } -} - /////////////////////////////////////////////////////////////// // // Progress dialog diff --git a/Client/loader/Dialogs.h b/Client/loader/Dialogs.h index f9fcc0cc56..ac89d1ed80 100644 --- a/Client/loader/Dialogs.h +++ b/Client/loader/Dialogs.h @@ -12,8 +12,10 @@ #include -void ShowSplash(HINSTANCE hInstance); +void ShowSplash(HINSTANCE instance); void HideSplash(); +void SuspendSplash(); +void ResumeSplash(); void ShowProgressDialog(HINSTANCE hInstance, const SString& strTitle, bool bAllowCancel = false); void HideProgressDialog(); diff --git a/Client/loader/SplashWindow.cpp b/Client/loader/SplashWindow.cpp new file mode 100644 index 0000000000..ab5e144dab --- /dev/null +++ b/Client/loader/SplashWindow.cpp @@ -0,0 +1,624 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: Client/loader/SplashWindow.cpp + * PURPOSE: This file implements the functionality to show a splash window + * before the game window appears. The splash window will be + * created and rendered on a separate thread to avoid blocking + the main thread. + * + * Multi Theft Auto is available from https://multitheftauto.com/ + * + *****************************************************************************/ + +#include "resource.h" +#include + +static UINT GetWindowDpi(HWND window); +static SIZE GetPrimaryMonitorSize(); +static LONG ScaleToDpi(LONG value, UINT dpi); + +using hrc = std::chrono::high_resolution_clock; + +/////////////////////////////////////////////////////////////////////////// +// +// Splash window logic. +// +/////////////////////////////////////////////////////////////////////////// + +class Splash final +{ +public: + bool CreateSplashWindow(HINSTANCE instance); + void DestroySplashWindow(); + + bool CreateDeviceResources(); + void ReleaseDeviceResources(); + + bool Update(); + void Paint(HDC windowContext, bool drawBackground) const; + void UpdateLoadingBar(); + void OnDestroy(); + + void Show() const; + void Hide() const; + void BringToFront() const; + +private: + WNDCLASS m_windowClass{}; + HWND m_window{}; + int m_width{}; + int m_height{}; + + // Background bitmap + HBITMAP m_bgBitmap{}; + HDC m_bgContext{}; + + // Loading bar bitmap + hrc::time_point m_barLastUpdate{}; + HBITMAP m_barBitmap{}; + HDC m_barContext{}; + HRGN m_barRegion{}; + int m_barWidth{}; + int m_barHeight{}; + int m_barX{}; + int m_barY{}; +}; + +static Splash g_splash{}; + +/** + * @brief The window procedure for the splash window. + */ +static long CALLBACK HandleSplashWindowMessage(HWND window, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_ERASEBKGND) + return 1; + + if (message == WM_PAINT) + { + PAINTSTRUCT ps{}; + HDC windowContext = BeginPaint(window, &ps); + { + g_splash.Paint(windowContext, ps.rcPaint.top == 0); + } + EndPaint(window, &ps); + return 0; + } + + if (message == WM_DESTROY) + { + g_splash.OnDestroy(); + return 0; + } + + return DefWindowProc(window, message, wParam, lParam); +} + +/** + * @brief Creates the splash window. + * @param instance The instance handle of the loader DLL. + * @return true if the window was created successfully, false otherwise. + */ +bool Splash::CreateSplashWindow(HINSTANCE instance) +{ + if (m_window != nullptr) + return false; + + WNDCLASS windowClass{}; + windowClass.lpfnWndProc = &HandleSplashWindowMessage; + windowClass.style = 0; + windowClass.hInstance = instance; + windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); + windowClass.hIcon = LoadIconA(GetModuleHandle(nullptr), MAKEINTRESOURCE(110)); // IDI_ICON1 from Launcher + windowClass.lpszClassName = TEXT("SplashWindow"); + + if (!RegisterClass(&windowClass)) + { + if (GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + return false; + } + + HWND window = CreateWindow(windowClass.lpszClassName, "Multi Theft Auto Launcher", WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, instance, NULL); + + if (window == nullptr) + { + UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); + return false; + } + + // The source bitmap is 1000x500, but we render it at half size. + SIZE monitorSize = GetPrimaryMonitorSize(); + UINT dpi = GetWindowDpi(window); + m_width = ScaleToDpi(500, dpi); + m_height = ScaleToDpi(250, dpi); + int x = (monitorSize.cx - m_width) / 2; + int y = (monitorSize.cy - m_height) / 2; + MoveWindow(window, x, y, m_width, m_height, TRUE); + ShowWindow(window, SW_SHOW); + + // Calculate the position and size of the loading bar. + m_barLastUpdate = hrc::now(); + m_barX = {}; + m_barY = ScaleToDpi(197, dpi); + m_barWidth = m_width; + m_barHeight = ScaleToDpi(5, dpi) + 1; // We add 1 pixel because scaling can cause the bar to be too small. + + m_windowClass = windowClass; + m_window = window; + return true; +} + +/** + * @brief Destroys the splash window and unregisters its window class. + */ +void Splash::DestroySplashWindow() +{ + ReleaseDeviceResources(); + + if (m_window != nullptr) + { + DestroyWindow(m_window); + m_window = {}; + } + + if (m_windowClass.hInstance != nullptr) + { + UnregisterClass(m_windowClass.lpszClassName, m_windowClass.hInstance); + m_windowClass = {}; + } +} + +/** + * @brief Creates the device context and bitmap with the stretched splash image for rendering. + */ +bool Splash::CreateDeviceResources() +{ + if (!m_window) + return false; + + HBITMAP backgroundResource = LoadBitmap(m_windowClass.hInstance, MAKEINTRESOURCE(IDB_BITMAP1)); + HBITMAP barResource = LoadBitmap(m_windowClass.hInstance, MAKEINTRESOURCE(IDB_BITMAP2)); + + if (backgroundResource == nullptr || barResource == nullptr) + return false; + + HDC windowContext = GetDC(m_window); + + // Background + HDC sourceContext = CreateCompatibleDC(windowContext); + SelectObject(sourceContext, backgroundResource); + { + HBITMAP backgroundBitmap = CreateCompatibleBitmap(windowContext, m_width, m_height); + HDC renderContext = CreateCompatibleDC(windowContext); + SelectObject(renderContext, backgroundBitmap); + + BITMAP source{}; + GetObject(backgroundResource, sizeof(source), &source); + + SetStretchBltMode(renderContext, HALFTONE); + StretchBlt(renderContext, 0, 0, m_width, m_height, sourceContext, 0, 0, source.bmWidth, source.bmHeight, SRCCOPY); + + m_bgBitmap = backgroundBitmap; + m_bgContext = renderContext; + } + + // Loading bar + SelectObject(sourceContext, barResource); + { + HBITMAP barBitmap = CreateCompatibleBitmap(windowContext, m_barWidth, m_barHeight); + HDC renderContext = CreateCompatibleDC(windowContext); + SelectObject(renderContext, barBitmap); + + BITMAP source{}; + GetObject(barResource, sizeof(source), &source); + + SetStretchBltMode(renderContext, HALFTONE); + StretchBlt(renderContext, 0, 0, m_barWidth, m_barHeight, sourceContext, 0, 0, source.bmWidth, source.bmHeight, SRCCOPY); + + m_barBitmap = barBitmap; + m_barContext = renderContext; + m_barRegion = CreateRectRgn(0, m_barY, m_width, m_barY + m_barHeight); + } + + DeleteDC(sourceContext); + DeleteObject(barResource); + DeleteObject(backgroundResource); + + ReleaseDC(m_window, windowContext); + return true; +} + +/** + * @brief Releases the device context and bitmaps used for rendering. + */ +void Splash::ReleaseDeviceResources() +{ + if (m_bgContext) + { + DeleteDC(m_bgContext); + m_bgContext = {}; + } + + if (m_bgBitmap) + { + DeleteObject(m_bgBitmap); + m_bgBitmap = {}; + } + + if (m_barContext) + { + DeleteDC(m_barContext); + m_barContext = {}; + } + + if (m_barBitmap) + { + DeleteObject(m_barBitmap); + m_barBitmap = {}; + } + + if (m_barRegion != nullptr) + { + DeleteObject(m_barRegion); + m_barRegion = {}; + } +} + +/** + * @brief Polls the splash window message queue and updates the loading bar. + */ +bool Splash::Update() +{ + if (!m_window) + return false; + + MSG msg{}; + + while (PeekMessage(&msg, m_window, 0, 0, PM_NOREMOVE)) + { + if (msg.message == WM_QUIT) + return false; + + if (GetMessage(&msg, m_window, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + UpdateLoadingBar(); + return true; +} + +/** + * @brief Called when the splash window is destroyed. + */ +void Splash::OnDestroy() +{ + m_window = {}; +} + +/** + * @brief Renders the splash window. + * @param windowContext The device context of the window. + * @param drawBackground If true, the background must be drawn. + */ +void Splash::Paint(HDC windowContext, bool drawBackground) const +{ + if (drawBackground) + { + SelectClipRgn(windowContext, nullptr); + BitBlt(windowContext, 0, 0, m_width, m_height, m_bgContext, 0, 0, SRCCOPY); + } + + SelectClipRgn(windowContext, m_barRegion); + + if (m_barX > 0) + BitBlt(windowContext, 0, m_barY, m_width, m_height, m_barContext, m_width - m_barX, 0, SRCCOPY); + + BitBlt(windowContext, m_barX, m_barY, m_width, m_height, m_barContext, 0, 0, SRCCOPY); +} + +/** + * @brief Updates the progress of the loading bar and invalidates the loading bar region of the window. + */ +void Splash::UpdateLoadingBar() +{ + constexpr int PIXELS_PER_UPDATE = 3; + constexpr long long UPDATE_RATE_IN_MS = 16; + + const hrc::time_point now = hrc::now(); + const long long elapsed = std::chrono::duration_cast(now - m_barLastUpdate).count(); + + if (elapsed < UPDATE_RATE_IN_MS) + return; + + const long long numUpdates = elapsed / UPDATE_RATE_IN_MS; + m_barLastUpdate += std::chrono::milliseconds(numUpdates * UPDATE_RATE_IN_MS); + + m_barX += PIXELS_PER_UPDATE * numUpdates; + + if (m_barX >= m_width) + m_barX = 0; + + // Only invalidate the loading bar region to avoid flickering. + RECT invalidate{0, m_barY, m_width, m_barY + m_barHeight}; + InvalidateRect(m_window, &invalidate, FALSE); +} + +/** + * @brief Shows the splash window. + */ +void Splash::Show() const +{ + if (m_window) + { + ShowWindow(m_window, SW_SHOW); + } +} + +/** + * @brief Hides the splash window. + */ +void Splash::Hide() const +{ + if (m_window) + { + ShowWindow(m_window, SW_HIDE); + } +} + +/** + * @brief Brings the splash window to the front. + */ +void Splash::BringToFront() const +{ + if (m_window) + { + SetForegroundWindow(m_window); + SetWindowPos(m_window, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// Splash thread logic. +// +/////////////////////////////////////////////////////////////////////////// + +class SplashThread final +{ +public: + void Create(HINSTANCE instance); + void Destroy(); + + bool Exists() const { return m_thread != nullptr; } + bool ShouldExit() const { return m_exitEvent == nullptr || WaitForSingleObject(m_exitEvent, 0) == WAIT_OBJECT_0; } + + void Run(HINSTANCE instance); + void PostRun(); + +private: + HANDLE m_thread{}; + HANDLE m_exitEvent{}; +}; + +static SplashThread g_splashThread{}; + +/** + * @brief The entry point for the splash window thread. + */ +static DWORD WINAPI RunSplashThread(LPVOID instance) +{ + g_splashThread.Run(static_cast(instance)); + g_splashThread.PostRun(); + return 0; +} + +/** + * @brief Creates the splash window thread. + * @param instance The instance handle of the loader DLL. + */ +void SplashThread::Create(HINSTANCE instance) +{ + if (m_thread != nullptr) + return; + + HANDLE exitEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); + + if (exitEvent == nullptr) + return; + + HANDLE thread = CreateThread(nullptr, 0, RunSplashThread, instance, 0, nullptr); + + if (thread == nullptr) + { + CloseHandle(exitEvent); + return; + } + + m_thread = thread; + m_exitEvent = exitEvent; +} + +/** + * @brief Destroys the splash window thread and the splash window, if it still exists. + */ +void SplashThread::Destroy() +{ + if (m_thread) + { + SetEvent(m_exitEvent); + WaitForSingleObject(m_thread, 3000); + CloseHandle(m_thread); + m_thread = {}; + } + + if (m_exitEvent) + { + CloseHandle(m_exitEvent); + m_exitEvent = {}; + } + + g_splash.DestroySplashWindow(); +} + +/** + * @brief The main loop of the splash window thread. + * @param instance The instance handle of the loader DLL. + */ +void SplashThread::Run(HINSTANCE instance) +{ + if (!g_splash.CreateSplashWindow(instance)) + return; + + if (!g_splash.CreateDeviceResources()) + { + g_splash.DestroySplashWindow(); + return; + } + + MSG msg{}; + + while (true) + { + if (g_splashThread.ShouldExit()) + break; + + if (!g_splash.Update()) + break; + + Sleep(10); + } + + g_splash.DestroySplashWindow(); +} + +/** + * @brief Cleans up the splash window thread on thread exit. + */ +void SplashThread::PostRun() +{ + if (m_exitEvent) + { + CloseHandle(m_exitEvent); + m_exitEvent = {}; + } + + if (m_thread) + { + CloseHandle(m_thread); + m_thread = {}; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// Splash interface functions. +// +/////////////////////////////////////////////////////////////////////////// + +#ifdef MTA_DEBUG + +void ShowSplash(HINSTANCE instance) +{ +} + +void HideSplash() +{ +} + +void SuspendSplash() +{ +} + +void ResumeSplash() +{ +} + +#else + +void ShowSplash(HINSTANCE instance) +{ + if (g_splashThread.Exists()) + { + g_splash.BringToFront(); + } + else + { + g_splashThread.Create(instance); + } +} + +void HideSplash() +{ + g_splashThread.Destroy(); + g_splash.DestroySplashWindow(); +} + +void SuspendSplash() +{ + g_splash.Hide(); +} + +void ResumeSplash() +{ + g_splash.Show(); +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// Utility functions. +// +/////////////////////////////////////////////////////////////////////////// + +/** + * @brief Returns the dots per inch (dpi) value for the specified window. + */ +static UINT GetWindowDpi(HWND window) +{ + // Minimum version: Windows 10, version 1607 + using GetDpiForWindow_t = UINT(WINAPI*)(HWND); + + static GetDpiForWindow_t Win32GetDpiForWindow = ([] { + HMODULE user32 = LoadLibrary("user32"); + return user32 ? reinterpret_cast(static_cast(GetProcAddress(user32, "GetDpiForWindow"))) : nullptr; + })(); + + if (Win32GetDpiForWindow) + return Win32GetDpiForWindow(window); + + HDC screenDC = GetDC(NULL); + auto x = static_cast(GetDeviceCaps(screenDC, LOGPIXELSX)); + ReleaseDC(NULL, screenDC); + return x; +} + +/** + * @brief Returns the width and height of the primary monitor. + */ +static SIZE GetPrimaryMonitorSize() +{ + POINT zero{}; + HMONITOR primaryMonitor = MonitorFromPoint(zero, MONITOR_DEFAULTTOPRIMARY); + + MONITORINFO monitorInfo{}; + monitorInfo.cbSize = sizeof(monitorInfo); + GetMonitorInfo(primaryMonitor, &monitorInfo); + + const RECT& work = monitorInfo.rcWork; + return {work.right - work.left, work.bottom - work.top}; +} + +/** + * @brief Scales the value from the default screen dpi (96) to the provided dpi. + */ +static LONG ScaleToDpi(LONG value, UINT dpi) +{ + return static_cast(ceil(value * static_cast(dpi) / USER_DEFAULT_SCREEN_DPI)); +} diff --git a/Client/loader/loader.rc b/Client/loader/loader.rc index 3943163776..7f3d4f1d8a 100644 --- a/Client/loader/loader.rc +++ b/Client/loader/loader.rc @@ -52,6 +52,7 @@ END // IDB_BITMAP1 BITMAP "resource/splash.bmp" +IDB_BITMAP2 BITMAP "resource/color-strip.bmp" #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/Client/loader/resource.h b/Client/loader/resource.h index 7e4c341825..c39b39b698 100644 --- a/Client/loader/resource.h +++ b/Client/loader/resource.h @@ -3,6 +3,7 @@ // Used by loader.rc // #define IDB_BITMAP1 105 +#define IDB_BITMAP2 106 #define IDD_PROGRESS_DIALOG 111 #define IDD_CRASHED_DIALOG 114 #define IDD_D3DDLL_DIALOG 115 diff --git a/Client/loader/resource/color-strip.bmp b/Client/loader/resource/color-strip.bmp new file mode 100644 index 0000000000000000000000000000000000000000..796b7d65d8e047fcaec48c5f7f9b18fa465b33fe GIT binary patch literal 11078 zcmeI2IZFdk6ot<-QDfqg#3gP~!$?$u1|xA77gRz(2og+T3b8Ro+zJtF98yRk)+*L^ z+SvOW6#s=k!!a^;I`3LpoDXK+FmsFH!I^WzJCY^ z`o0e9=H~%DYG0cbOkPofm%*dk@-9>rq z2<7-OZe~pkj>eJ7tRcOb!cOr3*}^HJ+joc+9x-9QVEXD63%745+&{y7ctUb<36V$y zL1PL5V+P}iMD_i6;tp^J{{0RpDK#!B?pi5z^-??yQoKGXjZIRTTcr5K1jGcTw6;lU z?~oGel+x8LrKeX)xKB#|fE3F-rTpQmB9*zK&h^z!oomaTIv0qYI@fn~`nk5P)6ex? zoqjH8-r2Y7x9{S%J)o^`yO27k&Nae1^SORX*VngQNu6uQbmntGN@qT2K6f0;aSo?H zjT7W@yOjBy`P|vx?RH#yW#7)eoqhW+_Re`b=k1QhZkx1VrJvK!>E}P@b>?&CbB&*7 W_@9hpF1HJq&mC?2yFlRMcIgLVPO2dQ literal 0 HcmV?d00001 diff --git a/Client/loader/resource/splash.bmp b/Client/loader/resource/splash.bmp index 3b5b1d7ba19e99f05eacc92a846242c0a586a608..e03bf21d5d402e2a4b380c64edb41b5303cc316e 100644 GIT binary patch literal 1500056 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
j9I#>r+v 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%0AL-Hg`AwhVQTJb0#p=?}f_D7#!T*%W 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

qNyt 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

K0*A1dM$+SK&Hxt)k-fg4ER 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

O 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 literal 491078 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 z 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 z⁣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 dIIn^88aS_k^BOp>f%6(TuYvO#c(0x748EFC, 0x748B08); MemPut(0x748B0E, 5); + // Skip copyright screen + MemSet((void*)0x748C2B, 0x90, 5); // call CLoadingScreen::DoPCTitleFadeIn + MemSet((void*)0x748C9A, 0x90, 5); // call CLoadingScreen::DoPCTitleFadeOut + // Force triggering of the damage event for players on fire MemSet((void*)0x633695, 0x90, 6); MemPut(0x633720, 0); diff --git a/Client/sdk/game/CGame.h b/Client/sdk/game/CGame.h index a87225a024..4ab94f511f 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -248,7 +248,6 @@ class __declspec(novtable) CGame virtual void SuspendASyncLoading(bool bSuspend, uint uiAutoUnsuspendDelay = 0) = 0; virtual bool IsASyncLoadingEnabled(bool bIgnoreSuspend = false) = 0; - virtual bool HasCreditScreenFadedOut() = 0; virtual void FlushPendingRestreamIPL() = 0; virtual void ResetModelLodDistances() = 0; virtual void ResetModelFlags() = 0; From 606adf3951c5448c8fa409f6cb69b0631c22f418 Mon Sep 17 00:00:00 2001 From: Pot Bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 21:50:24 +0000 Subject: [PATCH 03/16] Update client en_US pot [ci skip] --- .../MTA/locale/en_US/client.pot | 150 +++++++++--------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot index 49c71ecd16..1bfe2e58d7 100644 --- a/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot +++ b/Shared/data/MTA San Andreas/MTA/locale/en_US/client.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: MTA San Andreas 1.x\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-27 18:31+0000\n" +"POT-Creation-Date: 2025-03-03 21:50+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -20,7 +20,7 @@ msgstr "" #. Create buttons #. OK button -#: Client/gui/CGUIMessageBox_Impl.cpp:64 Client/loader/Dialogs.cpp:133 +#: Client/gui/CGUIMessageBox_Impl.cpp:64 Client/loader/Dialogs.cpp:37 #: Client/core/CSettings.cpp:127 Client/core/CSettings.cpp:4838 #: Client/core/CVersionUpdater.cpp:1607 Client/core/CVersionUpdater.cpp:1823 #: Client/core/CVersionUpdater.cpp:1916 Client/core/CVersionUpdater.cpp:1938 @@ -31,7 +31,7 @@ msgid "OK" msgstr "" #. Cancel button -#: Client/gui/CGUIMessageBox_Impl.cpp:68 Client/loader/Dialogs.cpp:136 +#: Client/gui/CGUIMessageBox_Impl.cpp:68 Client/loader/Dialogs.cpp:40 #: Client/mods/deathmatch/logic/CLocalServer.cpp:123 #: Client/core/CSettings.cpp:132 Client/core/CSettings.cpp:4837 #: Client/core/CVersionUpdater.cpp:1790 Client/core/CVersionUpdater.cpp:1806 @@ -45,8 +45,8 @@ msgstr "" #. #. #. ///////////////////////////////////////////////////////////////////////// -#: Client/gui/CGUIMessageBox_Impl.cpp:72 Client/loader/Dialogs.cpp:131 -#: Client/core/CMainMenu.cpp:1196 Client/core/CSettings.cpp:1413 +#: Client/gui/CGUIMessageBox_Impl.cpp:72 Client/loader/Dialogs.cpp:35 +#: Client/core/CMainMenu.cpp:1169 Client/core/CSettings.cpp:1413 #: Client/core/CSettings.cpp:1437 Client/core/CSettings.cpp:4542 #: Client/core/CSettings.cpp:4616 Client/core/CSettings.cpp:4646 #: Client/core/CSettings.cpp:4695 Client/core/CVersionUpdater.cpp:1572 @@ -56,7 +56,7 @@ msgstr "" msgid "Yes" msgstr "" -#: Client/loader/Dialogs.cpp:132 Client/core/CMainMenu.cpp:1195 +#: Client/loader/Dialogs.cpp:36 Client/core/CMainMenu.cpp:1168 #: Client/core/CSettings.cpp:1412 Client/core/CSettings.cpp:1436 #: Client/core/CSettings.cpp:4541 Client/core/CSettings.cpp:4615 #: Client/core/CSettings.cpp:4645 Client/core/CSettings.cpp:4694 @@ -67,46 +67,46 @@ msgstr "" msgid "No" msgstr "" -#: Client/loader/Dialogs.cpp:134 +#: Client/loader/Dialogs.cpp:38 msgid "Quit" msgstr "" -#: Client/loader/Dialogs.cpp:135 +#: Client/loader/Dialogs.cpp:39 #: Client/core/ServerBrowser/CServerBrowser.cpp:556 msgid "Help" msgstr "" -#: Client/loader/Dialogs.cpp:151 +#: Client/loader/Dialogs.cpp:55 msgid "MTA: San Andreas has encountered a problem" msgstr "" -#: Client/loader/Dialogs.cpp:152 +#: Client/loader/Dialogs.cpp:56 msgid "Crash information" msgstr "" -#: Client/loader/Dialogs.cpp:153 +#: Client/loader/Dialogs.cpp:57 msgid "" "Tick the check box to send this crash info to MTA devs using the 'internet'" msgstr "" -#: Client/loader/Dialogs.cpp:154 +#: Client/loader/Dialogs.cpp:58 msgid "Doing so will increase the chance of this crash being fixed." msgstr "" -#: Client/loader/Dialogs.cpp:155 +#: Client/loader/Dialogs.cpp:59 msgid "Do you want to restart MTA: San Andreas ?" msgstr "" -#: Client/loader/Dialogs.cpp:162 +#: Client/loader/Dialogs.cpp:66 msgid "MTA: San Andreas - Warning" msgstr "" -#: Client/loader/Dialogs.cpp:163 +#: Client/loader/Dialogs.cpp:67 msgid "" "Your Grand Theft Auto: San Andreas install directory contains these files:" msgstr "" -#: Client/loader/Dialogs.cpp:165 +#: Client/loader/Dialogs.cpp:69 msgid "" "These files are not required and may interfere with the graphical features " "in this version of MTA:SA.\n" @@ -114,79 +114,79 @@ msgid "" "It is recommended that you remove or rename these files." msgstr "" -#: Client/loader/Dialogs.cpp:167 +#: Client/loader/Dialogs.cpp:71 msgid "Keep these files, but also show this warning on next start" msgstr "" -#: Client/loader/Dialogs.cpp:168 +#: Client/loader/Dialogs.cpp:72 msgid "Do not remind me about these files again" msgstr "" -#: Client/loader/Dialogs.cpp:169 +#: Client/loader/Dialogs.cpp:73 msgid "Rename these files from *.dll to *.dll.bak" msgstr "" -#: Client/loader/Dialogs.cpp:170 +#: Client/loader/Dialogs.cpp:74 msgid "Show me these files" msgstr "" -#: Client/loader/Dialogs.cpp:171 +#: Client/loader/Dialogs.cpp:75 msgid "Play MTA:SA" msgstr "" -#: Client/loader/Dialogs.cpp:177 +#: Client/loader/Dialogs.cpp:81 msgid "MTA: San Andreas - Confusing options" msgstr "" -#: Client/loader/Dialogs.cpp:178 +#: Client/loader/Dialogs.cpp:82 msgid "NVidia Optimus detected!" msgstr "" -#: Client/loader/Dialogs.cpp:179 +#: Client/loader/Dialogs.cpp:83 msgid "Try each option and see what works:" msgstr "" -#: Client/loader/Dialogs.cpp:180 +#: Client/loader/Dialogs.cpp:84 msgid "A - Standard NVidia" msgstr "" -#: Client/loader/Dialogs.cpp:181 +#: Client/loader/Dialogs.cpp:85 msgid "B - Alternate NVidia" msgstr "" -#: Client/loader/Dialogs.cpp:182 +#: Client/loader/Dialogs.cpp:86 msgid "C - Standard Intel" msgstr "" -#: Client/loader/Dialogs.cpp:183 +#: Client/loader/Dialogs.cpp:87 msgid "D - Alternate Intel" msgstr "" -#: Client/loader/Dialogs.cpp:184 +#: Client/loader/Dialogs.cpp:88 msgid "If you get desperate, this might help:" msgstr "" -#: Client/loader/Dialogs.cpp:185 +#: Client/loader/Dialogs.cpp:89 msgid "If you have already selected an option that works, this might help:" msgstr "" -#: Client/loader/Dialogs.cpp:186 +#: Client/loader/Dialogs.cpp:90 msgid "Force windowed mode" msgstr "" -#: Client/loader/Dialogs.cpp:187 +#: Client/loader/Dialogs.cpp:91 msgid "Don't show again" msgstr "" -#: Client/loader/Dialogs.cpp:194 Client/game_sa/CSettingsSA.cpp:859 +#: Client/loader/Dialogs.cpp:98 Client/game_sa/CSettingsSA.cpp:859 msgid "MTA: San Andreas" msgstr "" -#: Client/loader/Dialogs.cpp:195 +#: Client/loader/Dialogs.cpp:99 msgid "Warning: Could not detect anti-virus product" msgstr "" -#: Client/loader/Dialogs.cpp:197 +#: Client/loader/Dialogs.cpp:101 msgid "" "MTA could not detect an anti-virus on your PC.\n" "\n" @@ -195,45 +195,45 @@ msgid "" "Press 'Help' for more information." msgstr "" -#: Client/loader/Dialogs.cpp:200 +#: Client/loader/Dialogs.cpp:104 msgid "I have already installed an anti-virus" msgstr "" -#: Client/loader/Dialogs.cpp:202 +#: Client/loader/Dialogs.cpp:106 msgid "" "I will not install an anti-virus.\n" "I want my PC to lag and be part of a botnet." msgstr "" -#: Client/loader/Dialogs.cpp:890 +#: Client/loader/Dialogs.cpp:678 msgid "Searching for Grand Theft Auto San Andreas" msgstr "" -#: Client/loader/Dialogs.cpp:893 +#: Client/loader/Dialogs.cpp:681 msgid "Please start Grand Theft Auto San Andreas" msgstr "" -#: Client/loader/Dialogs.cpp:901 Client/loader/Install.cpp:852 +#: Client/loader/Dialogs.cpp:689 Client/loader/Install.cpp:852 msgid "Installing update..." msgstr "" -#: Client/loader/Dialogs.cpp:909 Client/loader/Install.cpp:934 +#: Client/loader/Dialogs.cpp:697 Client/loader/Install.cpp:934 msgid "Extracting files..." msgstr "" -#: Client/loader/Dialogs.cpp:914 Client/loader/Utils.cpp:1391 +#: Client/loader/Dialogs.cpp:702 Client/loader/Utils.cpp:1391 msgid "Copying files..." msgstr "" -#: Client/loader/Dialogs.cpp:919 Client/loader/Utils.cpp:1451 +#: Client/loader/Dialogs.cpp:707 Client/loader/Utils.cpp:1451 msgid "Copy finished early. Everything OK." msgstr "" -#: Client/loader/Dialogs.cpp:924 Client/loader/Utils.cpp:1457 +#: Client/loader/Dialogs.cpp:712 Client/loader/Utils.cpp:1457 msgid "Finishing..." msgstr "" -#: Client/loader/Dialogs.cpp:928 Client/loader/Utils.cpp:1459 +#: Client/loader/Dialogs.cpp:716 Client/loader/Utils.cpp:1459 msgid "Done!" msgstr "" @@ -391,7 +391,7 @@ msgstr "" #: Client/core/CConnectManager.cpp:413 Client/core/CConnectManager.cpp:423 #: Client/core/CSettings.cpp:2972 Client/core/CSettings.cpp:4219 #: Client/core/CSettings.cpp:4247 Client/core/CSettings.cpp:4817 -#: Client/core/CCore.cpp:1273 Client/core/CCore.cpp:1286 +#: Client/core/CCore.cpp:1258 Client/core/CCore.cpp:1271 #: Client/core/CGUI.cpp:93 Client/core/ServerBrowser/CServerBrowser.cpp:1261 #: Client/core/ServerBrowser/CServerBrowser.cpp:1283 #: Client/core/ServerBrowser/CServerBrowser.cpp:1340 @@ -1243,7 +1243,7 @@ msgid "Choking to death in" msgstr "" #: Client/mods/deathmatch/logic/CClientGame.cpp:540 -#: Client/core/CMainMenu.cpp:304 Client/core/CSettings.cpp:3516 +#: Client/core/CMainMenu.cpp:302 Client/core/CSettings.cpp:3516 #: Client/core/CCore.cpp:672 msgid "Main menu" msgstr "" @@ -1451,27 +1451,27 @@ msgstr "" msgid "Unknown command or cvar: " msgstr "" -#: Client/core/CMainMenu.cpp:333 +#: Client/core/CMainMenu.cpp:331 msgid "" "You are using a feature-branch build! This is a test build only which cannot " "be used to connect to public servers!" msgstr "" -#: Client/core/CMainMenu.cpp:352 +#: Client/core/CMainMenu.cpp:350 msgid "" "MTA will not receive updates on XP/Vista after July 2019.\n" "\n" "Upgrade Windows to play on the latest servers." msgstr "" -#: Client/core/CMainMenu.cpp:1189 +#: Client/core/CMainMenu.cpp:1162 msgid "" "This will disconnect you from the current server.\n" "\n" "Are you sure you want to disconnect?" msgstr "" -#: Client/core/CMainMenu.cpp:1193 +#: Client/core/CMainMenu.cpp:1166 msgid "DISCONNECT WARNING" msgstr "" @@ -2712,102 +2712,102 @@ msgstr "" msgid "%s module is incorrect!" msgstr "" -#: Client/core/CCore.cpp:1273 +#: Client/core/CCore.cpp:1258 msgid "Error executing URL" msgstr "" -#: Client/core/CCore.cpp:1285 +#: Client/core/CCore.cpp:1270 #, c-format msgid "Error running mod specified in command line ('%s')" msgstr "" #. m_pCommands->Add ( "e", CCommandFuncs::Editor ); #. m_pCommands->Add ( "clear", CCommandFuncs::Clear ); -#: Client/core/CCore.cpp:1387 +#: Client/core/CCore.cpp:1367 msgid "this help screen" msgstr "" -#: Client/core/CCore.cpp:1388 Client/core/CCore.cpp:1389 +#: Client/core/CCore.cpp:1368 Client/core/CCore.cpp:1369 msgid "exits the application" msgstr "" -#: Client/core/CCore.cpp:1390 +#: Client/core/CCore.cpp:1370 msgid "shows the version" msgstr "" -#: Client/core/CCore.cpp:1391 +#: Client/core/CCore.cpp:1371 msgid "shows the time" msgstr "" -#: Client/core/CCore.cpp:1392 +#: Client/core/CCore.cpp:1372 msgid "shows the hud" msgstr "" -#: Client/core/CCore.cpp:1393 +#: Client/core/CCore.cpp:1373 msgid "shows all the binds" msgstr "" -#: Client/core/CCore.cpp:1394 +#: Client/core/CCore.cpp:1374 msgid "shows your serial" msgstr "" -#: Client/core/CCore.cpp:1403 +#: Client/core/CCore.cpp:1383 msgid "connects to a server (host port nick pass)" msgstr "" -#: Client/core/CCore.cpp:1404 +#: Client/core/CCore.cpp:1384 msgid "connects to a previous server" msgstr "" -#: Client/core/CCore.cpp:1405 +#: Client/core/CCore.cpp:1385 msgid "binds a key (key control)" msgstr "" -#: Client/core/CCore.cpp:1406 +#: Client/core/CCore.cpp:1386 msgid "unbinds a key (key)" msgstr "" -#: Client/core/CCore.cpp:1407 +#: Client/core/CCore.cpp:1387 msgid "copies the default gta controls" msgstr "" -#: Client/core/CCore.cpp:1408 +#: Client/core/CCore.cpp:1388 msgid "outputs a screenshot" msgstr "" -#: Client/core/CCore.cpp:1409 +#: Client/core/CCore.cpp:1389 msgid "immediately saves the config" msgstr "" -#: Client/core/CCore.cpp:1411 +#: Client/core/CCore.cpp:1391 msgid "clears the debug view" msgstr "" -#: Client/core/CCore.cpp:1412 +#: Client/core/CCore.cpp:1392 msgid "scrolls the chatbox upwards" msgstr "" -#: Client/core/CCore.cpp:1413 +#: Client/core/CCore.cpp:1393 msgid "scrolls the chatbox downwards" msgstr "" -#: Client/core/CCore.cpp:1414 +#: Client/core/CCore.cpp:1394 msgid "scrolls the debug view upwards" msgstr "" -#: Client/core/CCore.cpp:1415 +#: Client/core/CCore.cpp:1395 msgid "scrolls the debug view downwards" msgstr "" -#: Client/core/CCore.cpp:1418 +#: Client/core/CCore.cpp:1398 msgid "shows the memory statistics" msgstr "" -#: Client/core/CCore.cpp:1419 +#: Client/core/CCore.cpp:1399 msgid "shows the frame timing graph" msgstr "" -#: Client/core/CCore.cpp:1423 +#: Client/core/CCore.cpp:1403 msgid "for developers: reload news" msgstr "" From bebeb7d088f060ada1fe35cf50b298238f718c6c Mon Sep 17 00:00:00 2001 From: Marek Kulik Date: Tue, 4 Mar 2025 00:37:27 +0100 Subject: [PATCH 04/16] Adjust contrast in splash image --- Client/loader/resource/splash.bmp | Bin 1500056 -> 1500054 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Client/loader/resource/splash.bmp b/Client/loader/resource/splash.bmp index e03bf21d5d402e2a4b380c64edb41b5303cc316e..2fdfeca36f65317823c008986a919a208de8132d 100644 GIT binary patch delta 72842 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 Pb*i(I{pNbtLqGjLbKDl< delta 91082 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 RO1&xmoMXbRKVod){{h-)A@KkJ From fe84c734e05a2927ee5110fa9d3460381a6a3528 Mon Sep 17 00:00:00 2001 From: Marek Kulik Date: Tue, 4 Mar 2025 17:37:44 +0100 Subject: [PATCH 05/16] Generate native language name list on compile-time --- .gitignore | 1 + Client/core/CLocalization.cpp | 19 ++ Client/core/premake5.lua | 4 + Shared/sdk/SharedUtil.cpp | 1 + Shared/sdk/SharedUtil.hpp | 1 + Shared/sdk/UTF8.h | 243 +-------------- Shared/sdk/UTF8.hpp | 276 ++++++++++++++++++ utils/gen_language_list.exe | Bin 0 -> 591872 bytes .../src/gen_language_list/build-solution.bat | 44 +++ .../src/gen_language_list/create-solution.bat | 3 + .../gen_language_list/gen_language_list.cpp | 134 +++++++++ utils/src/gen_language_list/premake5.lua | 37 +++ vendor/tinygettext/dirent_win32.h | 4 +- vendor/tinygettext/premake5.lua | 3 - vendor/tinygettext/unix_file_system.cpp | 10 +- 15 files changed, 536 insertions(+), 244 deletions(-) create mode 100644 Shared/sdk/UTF8.hpp create mode 100644 utils/gen_language_list.exe create mode 100644 utils/src/gen_language_list/build-solution.bat create mode 100644 utils/src/gen_language_list/create-solution.bat create mode 100644 utils/src/gen_language_list/gen_language_list.cpp create mode 100644 utils/src/gen_language_list/premake5.lua diff --git a/.gitignore b/.gitignore index 074db153b4..a65751ddfb 100644 --- a/.gitignore +++ b/.gitignore @@ -416,3 +416,4 @@ utils/DXFiles/ !*.dll !*.exe utils/vswhere.exe +*.generated.h diff --git a/Client/core/CLocalization.cpp b/Client/core/CLocalization.cpp index 062e7c0f50..6af65cb88a 100644 --- a/Client/core/CLocalization.cpp +++ b/Client/core/CLocalization.cpp @@ -15,6 +15,14 @@ // TRANSLATORS: Replace with your language native name #define NATIVE_LANGUAGE_NAME _td("English") +struct NativeLanguageName +{ + std::string locale; + std::string name; +} g_nativeLanguageNames[] = { + #include "languages.generated.h" +}; + CLocalization::CLocalization(const SString& strLocale, const SString& strLocalePath) { // Set log callbacks so we can record problems @@ -95,12 +103,23 @@ CLanguage* CLocalization::GetLanguage(SString strLocale) SString CLocalization::GetLanguageNativeName(SString strLocale) { strLocale = ValidateLocale(strLocale); + + // Try to find the native language name in our sorted compile-time array first, using binary search. + auto begin = g_nativeLanguageNames; + auto end = g_nativeLanguageNames + _countof(g_nativeLanguageNames); + auto iter = std::lower_bound(begin, end, strLocale, [](const NativeLanguageName& a, const std::string& b) { return a.locale < b; }); + + if (iter != end && iter->locale == strLocale) + return iter->name; + + // If not found, we fall back to the loading the language file and using the name from there. SString strNativeName = GetLanguage(strLocale)->Translate(NATIVE_LANGUAGE_NAME); if (strNativeName == "English" && strLocale != "en_US") { // If native name not available, use English version strNativeName = GetLanguage(strLocale)->GetName(); } + return strNativeName; } diff --git a/Client/core/premake5.lua b/Client/core/premake5.lua index 49755743a2..f5b03bba75 100644 --- a/Client/core/premake5.lua +++ b/Client/core/premake5.lua @@ -55,6 +55,10 @@ project "Client Core" "PNG_SETJMP_NOT_SUPPORTED" } + prebuildcommands { + "%[%{!wks.location}/../utils/gen_language_list.exe] %[%{!wks.location}/../Shared/data/MTA San Andreas/MTA/locale] %[languages.generated.h]" + } + filter "architecture:not x86" flags { "ExcludeFromBuild" } diff --git a/Shared/sdk/SharedUtil.cpp b/Shared/sdk/SharedUtil.cpp index 851dfc9990..46a25926d0 100644 --- a/Shared/sdk/SharedUtil.cpp +++ b/Shared/sdk/SharedUtil.cpp @@ -18,3 +18,4 @@ #include "SharedUtil.SysInfo.hpp" #endif #include "SharedUtil.Memory.hpp" +#include "UTF8.hpp" diff --git a/Shared/sdk/SharedUtil.hpp b/Shared/sdk/SharedUtil.hpp index 8456d6510a..04b8ca9985 100644 --- a/Shared/sdk/SharedUtil.hpp +++ b/Shared/sdk/SharedUtil.hpp @@ -25,3 +25,4 @@ #include "SharedUtil.Logging.hpp" #include "SharedUtil.AsyncTaskScheduler.hpp" #include "SharedUtil.Memory.hpp" +#include "UTF8.hpp" diff --git a/Shared/sdk/UTF8.h b/Shared/sdk/UTF8.h index b230d8b482..8bcd6a6fde 100644 --- a/Shared/sdk/UTF8.h +++ b/Shared/sdk/UTF8.h @@ -23,255 +23,26 @@ */ #pragma once -#include "SharedUtil.IntTypes.h" #include -/* Return code if invalid. (xxx_mbtowc, xxx_wctomb) */ -#define RET_ILSEQ 0 -/* Return code if only a shift sequence of n bytes was read. (xxx_mbtowc) */ -#define RET_TOOFEW(n) (-1-(n)) -/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */ -#define RET_TOOSMALL -1 -/* Replacement character for invalid multibyte sequence or wide character. */ -#define BAD_WCHAR ((wchar_t) 0xfffd) -#define BAD_CHAR '?' +int utf8_mbtowc(wchar_t* pwc, const unsigned char* src, int src_len); -int utf8_mbtowc(wchar_t* pwc, const unsigned char* src, int src_len) -{ - if (!pwc) - return 0; - - unsigned char c = src[0]; - - if (c < 0x80) - { - *pwc = c; - return 1; - } - else if (c < 0xc2) - { - return RET_ILSEQ; - } - else if (c < 0xe0) - { - if (src_len < 2) - return RET_TOOFEW(0); - if (!((src[1] ^ 0x80) < 0x40)) - return RET_ILSEQ; - *pwc = ((wchar_t)(c & 0x1f) << 6) | (wchar_t)(src[1] ^ 0x80); - return 2; - } - else if (c < 0xf0) - { - if (src_len < 3) - return RET_TOOFEW(0); - if (!((src[1] ^ 0x80) < 0x40 && (src[2] ^ 0x80) < 0x40 && (c >= 0xe1 || src[1] >= 0xa0))) - return RET_ILSEQ; - *pwc = ((wchar_t)(c & 0x0f) << 12) | ((wchar_t)(src[1] ^ 0x80) << 6) | (wchar_t)(src[2] ^ 0x80); - return 3; - } - else if (c < 0xf8) - { - if (src_len < 4) - return RET_TOOFEW(0); - if (!((src[1] ^ 0x80) < 0x40 && (src[2] ^ 0x80) < 0x40 && (src[3] ^ 0x80) < 0x40 && (c >= 0xf1 || src[1] >= 0x90))) - return RET_ILSEQ; - *pwc = ((wchar_t)(c & 0x07) << 18) | ((wchar_t)(src[1] ^ 0x80) << 12) | ((wchar_t)(src[2] ^ 0x80) << 6) | (wchar_t)(src[3] ^ 0x80); - return 4; - } - else if (c < 0xfc) - { - if (src_len < 5) - return RET_TOOFEW(0); - if (!((src[1] ^ 0x80) < 0x40 && (src[2] ^ 0x80) < 0x40 && (src[3] ^ 0x80) < 0x40 && (src[4] ^ 0x80) < 0x40 && (c >= 0xf9 || src[1] >= 0x88))) - return RET_ILSEQ; - *pwc = ((wchar_t)(c & 0x03) << 24) | ((wchar_t)(src[1] ^ 0x80) << 18) | ((wchar_t)(src[2] ^ 0x80) << 12) | ((wchar_t)(src[3] ^ 0x80) << 6) | - (wchar_t)(src[4] ^ 0x80); - return 5; - } - else if (c < 0xfe) - { - if (src_len < 6) - return RET_TOOFEW(0); - if (!((src[1] ^ 0x80) < 0x40 && (src[2] ^ 0x80) < 0x40 && (src[3] ^ 0x80) < 0x40 && (src[4] ^ 0x80) < 0x40 && (src[5] ^ 0x80) < 0x40 && - (c >= 0xfd || src[1] >= 0x84))) - return RET_ILSEQ; - *pwc = ((wchar_t)(c & 0x01) << 30) | ((wchar_t)(src[1] ^ 0x80) << 24) | ((wchar_t)(src[2] ^ 0x80) << 18) | ((wchar_t)(src[3] ^ 0x80) << 12) | - ((wchar_t)(src[4] ^ 0x80) << 6) | (wchar_t)(src[5] ^ 0x80); - return 6; - } - else - return RET_ILSEQ; -} - -int utf8_wctomb(unsigned char* dest, wchar_t wc, int dest_size) -{ - if (!dest) - return 0; - - int count; - if (wc < 0x80) - count = 1; - else if (wc < 0x800) - count = 2; - else if (wc < 0x10000) - count = 3; - else if (wc < 0x200000) - count = 4; - else if (wc < 0x4000000) - count = 5; - else if (wc <= 0x7fffffff) - count = 6; - else - return RET_ILSEQ; - if (dest_size < count) - return RET_TOOSMALL; - switch (count) - { /* note: code falls through cases! */ - case 6: - dest[5] = 0x80 | (wc & 0x3f); - wc = wc >> 6; - wc |= 0x4000000; - case 5: - dest[4] = 0x80 | (wc & 0x3f); - wc = wc >> 6; - wc |= 0x200000; - case 4: - dest[3] = 0x80 | (wc & 0x3f); - wc = wc >> 6; - wc |= 0x10000; - case 3: - dest[2] = 0x80 | (wc & 0x3f); - wc = wc >> 6; - wc |= 0x800; - case 2: - dest[1] = 0x80 | (wc & 0x3f); - wc = wc >> 6; - wc |= 0xc0; - case 1: - dest[0] = (unsigned char)wc; - } - return count; -} +int utf8_wctomb(unsigned char* dest, wchar_t wc, int dest_size); ////////////////////////////////////////////////// // // Original - For testing // -std::wstring utf8_mbstowcs_orig(const std::string& str) -{ - std::wstring wstr; - wchar_t wc; - unsigned int sn = 0; - int un = 0; - - const unsigned char* s = (const unsigned char*)str.c_str(); - - while (sn < str.length() && *s != 0 && (un = utf8_mbtowc(&wc, s, str.length() - sn)) > 0) - { - wstr.push_back(wc); - s += un; - sn += un; - } - return wstr; -} - -std::string utf8_wcstombs_orig(const std::wstring& wstr) -{ - std::string str; - char utf8[6]; - int un = 0; +std::wstring utf8_mbstowcs_orig(const std::string& str); - for (unsigned int i = 0; i < wstr.size(); ++i) - { - un = utf8_wctomb((unsigned char*)utf8, wstr[i], 6); - if (un > 0) - str.append(utf8, un); - } - return str; -} +std::string utf8_wcstombs_orig(const std::wstring& wstr); ////////////////////////////////////////////////// // -// Optimized - faster for strings smaller than SMALL_STRING_LIMIT +// Optimized - faster for smaller strings // -#define SMALL_STRING_LIMIT 1000 - -std::wstring utf8_mbstowcs(const std::string& str) -{ - const unsigned char* s = (const unsigned char*)str.c_str(); - const unsigned int length = str.length(); - - if (length < SMALL_STRING_LIMIT) - { - // Faster but limited size - uint cCharacters = length + 1; - uint cBytes = (cCharacters) * sizeof(wchar_t); - - wchar_t* buffer = (wchar_t*)alloca(cBytes); - wchar_t* ptr = buffer; - wchar_t wc; - unsigned int sn = 0; - int un = 0; - - while (sn < length && *s != 0 && (un = utf8_mbtowc(&wc, s, length - sn)) > 0) - { - *ptr++ = wc; - s += un; - sn += un; - } - size_t usedsize = ptr - buffer; - return std::wstring(buffer, usedsize); - } - else - { - // Slower but any size - std::wstring wstr; - wchar_t wc; - unsigned int sn = 0; - int un = 0; - - while (sn < length && *s != 0 && (un = utf8_mbtowc(&wc, s, length - sn)) > 0) - { - wstr.push_back(wc); - s += un; - sn += un; - } - return wstr; - } -} - -// Optimized -std::string utf8_wcstombs(const std::wstring& wstr) -{ - const unsigned int size = wstr.length(); - if (size < SMALL_STRING_LIMIT) - { - // Faster but limited size - uint cBytes = (size + 1) * 6; - char* buffer = (char*)alloca(cBytes); - char* ptr = buffer; - for (unsigned int i = 0; i < size; ++i) - { - ptr += utf8_wctomb((unsigned char*)ptr, wstr[i], 6); - } - size_t usedsize = ptr - buffer; - return std::string(buffer, usedsize); - } - else - { - // Slower but any size - char utf8[6]; - std::string str; +std::wstring utf8_mbstowcs(const std::string& str); - for (unsigned int i = 0; i < size; ++i) - { - int un = utf8_wctomb((unsigned char*)utf8, wstr[i], 6); - if (un > 0) - str.append(utf8, un); - } - return str; - } -} +std::string utf8_wcstombs(const std::wstring& wstr); diff --git a/Shared/sdk/UTF8.hpp b/Shared/sdk/UTF8.hpp new file mode 100644 index 0000000000..50091956bd --- /dev/null +++ b/Shared/sdk/UTF8.hpp @@ -0,0 +1,276 @@ +/* + * Smart Common Input Method + * + * Copyright (c) 2002-2005 James Su + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * $Id: scim_utility.cpp,v 1.48.2.5 2006/11/02 04:11:51 suzhe Exp $ + */ +#pragma once + +#include "UTF8.h" + +/* Return code if invalid. (xxx_mbtowc, xxx_wctomb) */ +#define RET_ILSEQ 0 +/* Return code if only a shift sequence of n bytes was read. (xxx_mbtowc) */ +#define RET_TOOFEW(n) (-1-(n)) +/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */ +#define RET_TOOSMALL -1 +/* Replacement character for invalid multibyte sequence or wide character. */ +#define BAD_WCHAR ((wchar_t) 0xfffd) +#define BAD_CHAR '?' + +int utf8_mbtowc(wchar_t* pwc, const unsigned char* src, int src_len) +{ + if (!pwc) + return 0; + + unsigned char c = src[0]; + + if (c < 0x80) + { + *pwc = c; + return 1; + } + else if (c < 0xc2) + { + return RET_ILSEQ; + } + else if (c < 0xe0) + { + if (src_len < 2) + return RET_TOOFEW(0); + if (!((src[1] ^ 0x80) < 0x40)) + return RET_ILSEQ; + *pwc = ((wchar_t)(c & 0x1f) << 6) | (wchar_t)(src[1] ^ 0x80); + return 2; + } + else if (c < 0xf0) + { + if (src_len < 3) + return RET_TOOFEW(0); + if (!((src[1] ^ 0x80) < 0x40 && (src[2] ^ 0x80) < 0x40 && (c >= 0xe1 || src[1] >= 0xa0))) + return RET_ILSEQ; + *pwc = ((wchar_t)(c & 0x0f) << 12) | ((wchar_t)(src[1] ^ 0x80) << 6) | (wchar_t)(src[2] ^ 0x80); + return 3; + } + else if (c < 0xf8) + { + if (src_len < 4) + return RET_TOOFEW(0); + if (!((src[1] ^ 0x80) < 0x40 && (src[2] ^ 0x80) < 0x40 && (src[3] ^ 0x80) < 0x40 && (c >= 0xf1 || src[1] >= 0x90))) + return RET_ILSEQ; + *pwc = ((wchar_t)(c & 0x07) << 18) | ((wchar_t)(src[1] ^ 0x80) << 12) | ((wchar_t)(src[2] ^ 0x80) << 6) | (wchar_t)(src[3] ^ 0x80); + return 4; + } + else if (c < 0xfc) + { + if (src_len < 5) + return RET_TOOFEW(0); + if (!((src[1] ^ 0x80) < 0x40 && (src[2] ^ 0x80) < 0x40 && (src[3] ^ 0x80) < 0x40 && (src[4] ^ 0x80) < 0x40 && (c >= 0xf9 || src[1] >= 0x88))) + return RET_ILSEQ; + *pwc = ((wchar_t)(c & 0x03) << 24) | ((wchar_t)(src[1] ^ 0x80) << 18) | ((wchar_t)(src[2] ^ 0x80) << 12) | ((wchar_t)(src[3] ^ 0x80) << 6) | + (wchar_t)(src[4] ^ 0x80); + return 5; + } + else if (c < 0xfe) + { + if (src_len < 6) + return RET_TOOFEW(0); + if (!((src[1] ^ 0x80) < 0x40 && (src[2] ^ 0x80) < 0x40 && (src[3] ^ 0x80) < 0x40 && (src[4] ^ 0x80) < 0x40 && (src[5] ^ 0x80) < 0x40 && + (c >= 0xfd || src[1] >= 0x84))) + return RET_ILSEQ; + *pwc = ((wchar_t)(c & 0x01) << 30) | ((wchar_t)(src[1] ^ 0x80) << 24) | ((wchar_t)(src[2] ^ 0x80) << 18) | ((wchar_t)(src[3] ^ 0x80) << 12) | + ((wchar_t)(src[4] ^ 0x80) << 6) | (wchar_t)(src[5] ^ 0x80); + return 6; + } + else + return RET_ILSEQ; +} + +int utf8_wctomb(unsigned char* dest, wchar_t wc, int dest_size) +{ + if (!dest) + return 0; + + int count; + if (wc < 0x80) + count = 1; + else if (wc < 0x800) + count = 2; + else if (wc < 0x10000) + count = 3; + else if (wc < 0x200000) + count = 4; + else if (wc < 0x4000000) + count = 5; + else if (wc <= 0x7fffffff) + count = 6; + else + return RET_ILSEQ; + if (dest_size < count) + return RET_TOOSMALL; + switch (count) + { /* note: code falls through cases! */ + case 6: + dest[5] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0x4000000; + case 5: + dest[4] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0x200000; + case 4: + dest[3] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0x10000; + case 3: + dest[2] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0x800; + case 2: + dest[1] = 0x80 | (wc & 0x3f); + wc = wc >> 6; + wc |= 0xc0; + case 1: + dest[0] = (unsigned char)wc; + } + return count; +} + +////////////////////////////////////////////////// +// +// Original - For testing +// + +std::wstring utf8_mbstowcs_orig(const std::string& str) +{ + std::wstring wstr; + wchar_t wc; + unsigned int sn = 0; + int un = 0; + + const unsigned char* s = (const unsigned char*)str.c_str(); + + while (sn < str.length() && *s != 0 && (un = utf8_mbtowc(&wc, s, str.length() - sn)) > 0) + { + wstr.push_back(wc); + s += un; + sn += un; + } + return wstr; +} + +std::string utf8_wcstombs_orig(const std::wstring& wstr) +{ + std::string str; + char utf8[6]; + int un = 0; + + for (unsigned int i = 0; i < wstr.size(); ++i) + { + un = utf8_wctomb((unsigned char*)utf8, wstr[i], 6); + if (un > 0) + str.append(utf8, un); + } + return str; +} + +////////////////////////////////////////////////// +// +// Optimized - faster for strings smaller than SMALL_STRING_LIMIT +// +#define SMALL_STRING_LIMIT 1000 + +std::wstring utf8_mbstowcs(const std::string& str) +{ + const unsigned char* s = (const unsigned char*)str.c_str(); + const unsigned int length = str.length(); + + if (length < SMALL_STRING_LIMIT) + { + // Faster but limited size + unsigned int cCharacters = length + 1; + unsigned int cBytes = (cCharacters) * sizeof(wchar_t); + + wchar_t* buffer = (wchar_t*)alloca(cBytes); + wchar_t* ptr = buffer; + wchar_t wc; + unsigned int sn = 0; + int un = 0; + + while (sn < length && *s != 0 && (un = utf8_mbtowc(&wc, s, length - sn)) > 0) + { + *ptr++ = wc; + s += un; + sn += un; + } + size_t usedsize = ptr - buffer; + return std::wstring(buffer, usedsize); + } + else + { + // Slower but any size + std::wstring wstr; + wchar_t wc; + unsigned int sn = 0; + int un = 0; + + while (sn < length && *s != 0 && (un = utf8_mbtowc(&wc, s, length - sn)) > 0) + { + wstr.push_back(wc); + s += un; + sn += un; + } + return wstr; + } +} + +// Optimized +std::string utf8_wcstombs(const std::wstring& wstr) +{ + const unsigned int size = wstr.length(); + + if (size < SMALL_STRING_LIMIT) + { + // Faster but limited size + unsigned int cBytes = (size + 1) * 6; + char* buffer = (char*)alloca(cBytes); + char* ptr = buffer; + for (unsigned int i = 0; i < size; ++i) + { + ptr += utf8_wctomb((unsigned char*)ptr, wstr[i], 6); + } + size_t usedsize = ptr - buffer; + return std::string(buffer, usedsize); + } + else + { + // Slower but any size + char utf8[6]; + std::string str; + + for (unsigned int i = 0; i < size; ++i) + { + int un = utf8_wctomb((unsigned char*)utf8, wstr[i], 6); + if (un > 0) + str.append(utf8, un); + } + return str; + } +} diff --git a/utils/gen_language_list.exe b/utils/gen_language_list.exe new file mode 100644 index 0000000000000000000000000000000000000000..998247835ee11fa90335fd188107538c65c23dc1 GIT binary patch literal 591872 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 z�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 hq!j~UDW0K&^> %VSWHERE% +pause +exit /b 1 + +:FindVisualStudio +for /f "usebackq tokens=*" %%i in (`call "%VSWHERE%" -latest -requires Microsoft.Component.MSBuild -find "**\VsDevCmd.bat"`) do ( + set VSDEVCMD=%%i +) + +if defined VSDEVCMD goto :SetupEnv +echo Visual Studio not found +echo Make sure you've installed the 'Desktop development with C++' workload +pause +exit /b 1 + +:SetupEnv +echo Found Visual Studio environment setup batch file: +echo ^>^> %VSDEVCMD% +call "%VSDEVCMD%" -arch=arm64 -host_arch=amd64 >NUL + +where MSBuild.exe >NUL 2>&1 +if %ERRORLEVEL% == 0 goto :Build +echo MSBuild not found +echo Make sure you've installed the 'Desktop development with C++' workload +pause +exit /b 1 + +:Build +call create-solution.bat < NUL + +MSBuild.exe build\utility.sln ^ + -target:gen_language_list ^ + -property:Configuration=Release ^ + -property:Platform=x64 ^ + -maxCpuCount + +copy build\bin\Release\gen_language_list.exe ..\..\ >NUL + +if %0 == "%~0" pause diff --git a/utils/src/gen_language_list/create-solution.bat b/utils/src/gen_language_list/create-solution.bat new file mode 100644 index 0000000000..7d3243124e --- /dev/null +++ b/utils/src/gen_language_list/create-solution.bat @@ -0,0 +1,3 @@ +@echo off +..\..\premake5.exe vs2022 +if %0 == "%~0" pause diff --git a/utils/src/gen_language_list/gen_language_list.cpp b/utils/src/gen_language_list/gen_language_list.cpp new file mode 100644 index 0000000000..057e89f560 --- /dev/null +++ b/utils/src/gen_language_list/gen_language_list.cpp @@ -0,0 +1,134 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: utils/src/gen_language_list/gen_language_list.cpp + * PURPOSE: Tool to generate an include file with the list of all available + * languages in the locale directory. The Client Core project is + * going to use that include file to lookup the native name of a + * language without loading the translation files first. This + * safes a nice amount of time on startup. + * + * Multi Theft Auto is available from https://multitheftauto.com/ + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) + #include +#endif + +#define MTA_LOCALE_TEXTDOMAIN "client" + +using namespace tinygettext; + +namespace fs = std::filesystem; + +struct NativeLanguageName +{ + std::string locale; + std::string inNative; + std::string inEnglish; +}; + +auto quoted(const std::string& input) -> std::string +{ + std::string result = input; + std::string::size_type pos = 0; + while ((pos = result.find('\"', pos)) != std::string::npos) + { + result.replace(pos, 1, "\\\""); + pos += 2; + } + result = '"' + result + '"'; + return result; +} + +auto bytes(const std::string& input) -> std::string +{ + std::stringstream ss; + for (const unsigned char c : input) + { + ss << std::format("\\x{:02X}", c); + } + return ss.str(); +} + +int main(int argc, char* argv[]) +{ +#if defined(_WIN32) + SetConsoleOutputCP(CP_UTF8); +#endif + + if (argc != 3) + { + std::cerr << "Usage: gen_language_list " << std::endl; + return 1; + } + + const fs::path localeDirPath = argv[1]; + const fs::path outputFilePath = argv[2]; + + if (!fs::exists(localeDirPath) || !fs::is_directory(localeDirPath)) + { + std::cerr << "Error: " << localeDirPath << " is not a valid directory." << std::endl; + return 1; + } + + std::ofstream outputFile(outputFilePath); + + if (!outputFile.is_open()) + { + std::cerr << "Error: Failed to open " << outputFilePath << " for writing." << std::endl; + return 1; + } + + Log::set_log_info_callback(nullptr); + Log::set_log_warning_callback(nullptr); + Log::set_log_error_callback(nullptr); + + DictionaryManager dictManager; + { + std::u8string raw = localeDirPath.u8string(); + dictManager.add_directory(std::string{raw.begin(), raw.end()}); + } + + std::vector nativeLanguageNames; + + for (const auto& lang : dictManager.get_languages(MTA_LOCALE_TEXTDOMAIN)) + { + Dictionary dict = dictManager.get_dictionary(lang, MTA_LOCALE_TEXTDOMAIN); + std::string name = dict.translate("English"); + + if (name == "English" && lang.get_language() != "en") + { + name = lang.get_name(); + } + +#if defined(MTA_DEBUG) + std::cout << lang.str() << " => " << name << std::endl; +#endif + + nativeLanguageNames.push_back({lang.str(), name, lang.get_name()}); + } + + // Sort our list by locale for faster binary search later. + std::sort(nativeLanguageNames.begin(), nativeLanguageNames.end(), + [](const NativeLanguageName& a, const NativeLanguageName& b) { return a.locale < b.locale; }); + + for (const NativeLanguageName& lang : nativeLanguageNames) + { + outputFile << "{ " << quoted(lang.locale) << ", " << quoted(bytes(lang.inNative)) << " }, // " << lang.inEnglish << std::endl; + } + + return 0; +} diff --git a/utils/src/gen_language_list/premake5.lua b/utils/src/gen_language_list/premake5.lua new file mode 100644 index 0000000000..6a189e06e5 --- /dev/null +++ b/utils/src/gen_language_list/premake5.lua @@ -0,0 +1,37 @@ +workspace "utility" + configurations { "Debug", "Release" } + architecture "x86_64" + preferredtoolarchitecture "x86_64" + staticruntime "on" + cppdialect "C++20" + characterset "Unicode" + flags "MultiProcessorCompile" + warnings "Off" + location "build" + targetdir "build/bin/%{cfg.buildcfg}" + objdir "build/obj" + + filter "configurations:Debug" + defines { "MTA_DEBUG" } + symbols "On" + + filter "configurations:Release" + optimize "On" + + filter "system:windows" + defines { "WIN32", "_WIN32", "_WIN32_WINNT=0x601", "TGT_STANDALONE" } + buildoptions { "/Zc:__cplusplus" } + + include "../../../vendor/tinygettext" + +project "gen_language_list" + kind "ConsoleApp" + language "C++" + warnings "Extra" + + files { + "gen_language_list.cpp", + } + + links { "tinygettext" } + includedirs { "../../../vendor/tinygettext" } diff --git a/vendor/tinygettext/dirent_win32.h b/vendor/tinygettext/dirent_win32.h index 98467af457..e81a853f0c 100644 --- a/vendor/tinygettext/dirent_win32.h +++ b/vendor/tinygettext/dirent_win32.h @@ -779,7 +779,7 @@ dirent_mbstowcs_s( #if defined(_MSC_VER) && _MSC_VER >= 1400 - wcscpy_s(wcstr, sizeInWords, *FromUTF8(mbstr)); + wcscpy_s(wcstr, sizeInWords, utf8_mbstowcs(mbstr).c_str()); error = 0; #else @@ -829,7 +829,7 @@ dirent_wcstombs_s( #if defined(_MSC_VER) && _MSC_VER >= 1400 - strcpy_s(mbstr, sizeInBytes, *ToUTF8(wcstr)); + strcpy_s(mbstr, sizeInBytes, utf8_wcstombs(wcstr).c_str()); error = 0; #else diff --git a/vendor/tinygettext/premake5.lua b/vendor/tinygettext/premake5.lua index c840efdc50..852bab66ee 100644 --- a/vendor/tinygettext/premake5.lua +++ b/vendor/tinygettext/premake5.lua @@ -20,8 +20,5 @@ project "tinygettext" "*.cpp" } - filter "architecture:not x86" - flags { "ExcludeFromBuild" } - filter "system:windows" disablewarnings { "4800", "4309", "4503", "4099", "4503" } diff --git a/vendor/tinygettext/unix_file_system.cpp b/vendor/tinygettext/unix_file_system.cpp index 6116f72a6f..f98d6696a9 100644 --- a/vendor/tinygettext/unix_file_system.cpp +++ b/vendor/tinygettext/unix_file_system.cpp @@ -19,9 +19,13 @@ #include #include -#include "SharedUtil.h" #ifdef WIN32 + #include + #include #include + #ifdef TGT_STANDALONE + #include + #endif #else #include #endif @@ -75,7 +79,7 @@ std::unique_ptr UnixFileSystem::open_file(const std::string& filename) { #ifdef WIN32 - return std::unique_ptr(new std::ifstream(FromUTF8(filename.c_str()))); + return std::unique_ptr(new std::ifstream(utf8_mbstowcs(filename.c_str()))); #else return std::unique_ptr(new std::ifstream(filename.c_str())); #endif @@ -85,7 +89,7 @@ bool UnixFileSystem::file_exists(const std::string& filename) { #ifdef WIN32 - std::ifstream file( FromUTF8(filename.c_str()).c_str () ); + std::ifstream file( utf8_mbstowcs(filename.c_str()).c_str () ); #else std::ifstream file(filename.c_str()); #endif From 708f50a52dbcb5084b6c94bbdc6a0c1d4d0e8e54 Mon Sep 17 00:00:00 2001 From: Marek Kulik Date: Tue, 4 Mar 2025 18:52:03 +0100 Subject: [PATCH 06/16] Bump build [ci skip] From e7c59fb34fdba0b917ddee6d0c61ab959a1d673a Mon Sep 17 00:00:00 2001 From: lopsi <40902730+Lpsd@users.noreply.github.com> Date: Thu, 6 Mar 2025 00:53:58 +0100 Subject: [PATCH 07/16] Update from lunasvg 2.3.8 to 3.2.0 (#4067) --- .../logic/CClientVectorGraphicDisplay.cpp | 4 +- Client/mods/deathmatch/premake5.lua | 2 +- vendor/lunasvg/3rdparty/plutovg/LICENSE | 21 + .../lunasvg/3rdparty/plutovg/plutovg-blend.c | 1065 ++- .../lunasvg/3rdparty/plutovg/plutovg-canvas.c | 714 ++ .../lunasvg/3rdparty/plutovg/plutovg-dash.c | 114 - .../lunasvg/3rdparty/plutovg/plutovg-font.c | 414 + .../3rdparty/plutovg/plutovg-ft-math.c | 34 +- .../3rdparty/plutovg/plutovg-ft-math.h | 2 +- .../3rdparty/plutovg/plutovg-ft-raster.c | 76 +- .../3rdparty/plutovg/plutovg-ft-raster.h | 2 +- .../3rdparty/plutovg/plutovg-ft-stroker.c | 84 +- .../3rdparty/plutovg/plutovg-ft-stroker.h | 2 +- .../3rdparty/plutovg/plutovg-ft-types.h | 2 +- .../3rdparty/plutovg/plutovg-geometry.c | 581 -- .../lunasvg/3rdparty/plutovg/plutovg-matrix.c | 231 + .../lunasvg/3rdparty/plutovg/plutovg-paint.c | 578 +- .../lunasvg/3rdparty/plutovg/plutovg-path.c | 924 ++ .../3rdparty/plutovg/plutovg-private.h | 214 +- .../3rdparty/plutovg/plutovg-rasterize.c | 377 + vendor/lunasvg/3rdparty/plutovg/plutovg-rle.c | 424 - .../plutovg/plutovg-stb-image-write.h | 1724 ++++ .../3rdparty/plutovg/plutovg-stb-image.h | 7988 +++++++++++++++++ .../3rdparty/plutovg/plutovg-stb-truetype.h | 5077 +++++++++++ .../3rdparty/plutovg/plutovg-surface.c | 300 + .../lunasvg/3rdparty/plutovg/plutovg-utils.h | 211 + vendor/lunasvg/3rdparty/plutovg/plutovg.c | 495 - vendor/lunasvg/3rdparty/plutovg/plutovg.h | 2479 ++++- vendor/lunasvg/LICENSE | 2 +- vendor/lunasvg/README.md | 193 +- vendor/lunasvg/include/lunasvg.h | 755 +- vendor/lunasvg/premake5.lua | 9 +- vendor/lunasvg/source/canvas.cpp | 261 - vendor/lunasvg/source/canvas.h | 73 - vendor/lunasvg/source/clippathelement.cpp | 37 - vendor/lunasvg/source/clippathelement.h | 22 - vendor/lunasvg/source/defselement.cpp | 15 - vendor/lunasvg/source/defselement.h | 17 - vendor/lunasvg/source/element.cpp | 158 - vendor/lunasvg/source/element.h | 196 - vendor/lunasvg/source/gelement.cpp | 30 - vendor/lunasvg/source/gelement.h | 18 - vendor/lunasvg/source/geometryelement.cpp | 335 - vendor/lunasvg/source/geometryelement.h | 113 - vendor/lunasvg/source/graphics.cpp | 740 ++ vendor/lunasvg/source/graphics.h | 558 ++ vendor/lunasvg/source/graphicselement.cpp | 17 - vendor/lunasvg/source/graphicselement.h | 18 - vendor/lunasvg/source/layoutcontext.cpp | 745 -- vendor/lunasvg/source/layoutcontext.h | 372 - vendor/lunasvg/source/lunasvg.cpp | 519 +- vendor/lunasvg/source/markerelement.cpp | 98 - vendor/lunasvg/source/markerelement.h | 30 - vendor/lunasvg/source/maskelement.cpp | 77 - vendor/lunasvg/source/maskelement.h | 27 - vendor/lunasvg/source/paintelement.cpp | 428 - vendor/lunasvg/source/paintelement.h | 335 - vendor/lunasvg/source/parser.cpp | 1974 ---- vendor/lunasvg/source/parser.h | 202 - vendor/lunasvg/source/parserutils.h | 257 - vendor/lunasvg/source/property.cpp | 694 -- vendor/lunasvg/source/property.h | 349 - vendor/lunasvg/source/stopelement.cpp | 29 - vendor/lunasvg/source/stopelement.h | 20 - vendor/lunasvg/source/styledelement.cpp | 177 - vendor/lunasvg/source/styledelement.h | 52 - vendor/lunasvg/source/styleelement.cpp | 15 - vendor/lunasvg/source/styleelement.h | 17 - vendor/lunasvg/source/svgelement.cpp | 1200 ++- vendor/lunasvg/source/svgelement.h | 496 +- vendor/lunasvg/source/svggeometryelement.cpp | 324 + vendor/lunasvg/source/svggeometryelement.h | 139 + vendor/lunasvg/source/svglayoutstate.cpp | 529 ++ vendor/lunasvg/source/svglayoutstate.h | 117 + vendor/lunasvg/source/svgpaintelement.cpp | 359 + vendor/lunasvg/source/svgpaintelement.h | 288 + vendor/lunasvg/source/svgparser.cpp | 942 ++ vendor/lunasvg/source/svgparserutils.h | 210 + vendor/lunasvg/source/svgproperty.cpp | 687 ++ vendor/lunasvg/source/svgproperty.h | 534 ++ vendor/lunasvg/source/svgrenderstate.cpp | 61 + vendor/lunasvg/source/svgrenderstate.h | 69 + vendor/lunasvg/source/svgtextelement.cpp | 455 + vendor/lunasvg/source/svgtextelement.h | 138 + vendor/lunasvg/source/symbolelement.cpp | 52 - vendor/lunasvg/source/symbolelement.h | 24 - vendor/lunasvg/source/useelement.cpp | 96 - vendor/lunasvg/source/useelement.h | 25 - 88 files changed, 30390 insertions(+), 10478 deletions(-) create mode 100644 vendor/lunasvg/3rdparty/plutovg/LICENSE create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-canvas.c delete mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-dash.c create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-font.c delete mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-geometry.c create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-matrix.c create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-path.c create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-rasterize.c delete mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-rle.c create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-stb-image-write.h create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-stb-image.h create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-stb-truetype.h create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-surface.c create mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg-utils.h delete mode 100644 vendor/lunasvg/3rdparty/plutovg/plutovg.c delete mode 100644 vendor/lunasvg/source/canvas.cpp delete mode 100644 vendor/lunasvg/source/canvas.h delete mode 100644 vendor/lunasvg/source/clippathelement.cpp delete mode 100644 vendor/lunasvg/source/clippathelement.h delete mode 100644 vendor/lunasvg/source/defselement.cpp delete mode 100644 vendor/lunasvg/source/defselement.h delete mode 100644 vendor/lunasvg/source/element.cpp delete mode 100644 vendor/lunasvg/source/element.h delete mode 100644 vendor/lunasvg/source/gelement.cpp delete mode 100644 vendor/lunasvg/source/gelement.h delete mode 100644 vendor/lunasvg/source/geometryelement.cpp delete mode 100644 vendor/lunasvg/source/geometryelement.h create mode 100644 vendor/lunasvg/source/graphics.cpp create mode 100644 vendor/lunasvg/source/graphics.h delete mode 100644 vendor/lunasvg/source/graphicselement.cpp delete mode 100644 vendor/lunasvg/source/graphicselement.h delete mode 100644 vendor/lunasvg/source/layoutcontext.cpp delete mode 100644 vendor/lunasvg/source/layoutcontext.h delete mode 100644 vendor/lunasvg/source/markerelement.cpp delete mode 100644 vendor/lunasvg/source/markerelement.h delete mode 100644 vendor/lunasvg/source/maskelement.cpp delete mode 100644 vendor/lunasvg/source/maskelement.h delete mode 100644 vendor/lunasvg/source/paintelement.cpp delete mode 100644 vendor/lunasvg/source/paintelement.h delete mode 100644 vendor/lunasvg/source/parser.cpp delete mode 100644 vendor/lunasvg/source/parser.h delete mode 100644 vendor/lunasvg/source/parserutils.h delete mode 100644 vendor/lunasvg/source/property.cpp delete mode 100644 vendor/lunasvg/source/property.h delete mode 100644 vendor/lunasvg/source/stopelement.cpp delete mode 100644 vendor/lunasvg/source/stopelement.h delete mode 100644 vendor/lunasvg/source/styledelement.cpp delete mode 100644 vendor/lunasvg/source/styledelement.h delete mode 100644 vendor/lunasvg/source/styleelement.cpp delete mode 100644 vendor/lunasvg/source/styleelement.h create mode 100644 vendor/lunasvg/source/svggeometryelement.cpp create mode 100644 vendor/lunasvg/source/svggeometryelement.h create mode 100644 vendor/lunasvg/source/svglayoutstate.cpp create mode 100644 vendor/lunasvg/source/svglayoutstate.h create mode 100644 vendor/lunasvg/source/svgpaintelement.cpp create mode 100644 vendor/lunasvg/source/svgpaintelement.h create mode 100644 vendor/lunasvg/source/svgparser.cpp create mode 100644 vendor/lunasvg/source/svgparserutils.h create mode 100644 vendor/lunasvg/source/svgproperty.cpp create mode 100644 vendor/lunasvg/source/svgproperty.h create mode 100644 vendor/lunasvg/source/svgrenderstate.cpp create mode 100644 vendor/lunasvg/source/svgrenderstate.h create mode 100644 vendor/lunasvg/source/svgtextelement.cpp create mode 100644 vendor/lunasvg/source/svgtextelement.h delete mode 100644 vendor/lunasvg/source/symbolelement.cpp delete mode 100644 vendor/lunasvg/source/symbolelement.h delete mode 100644 vendor/lunasvg/source/useelement.cpp delete mode 100644 vendor/lunasvg/source/useelement.h diff --git a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp index 9e174d1878..ce91d2882d 100644 --- a/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp +++ b/Client/mods/deathmatch/logic/CClientVectorGraphicDisplay.cpp @@ -100,9 +100,9 @@ void CClientVectorGraphicDisplay::UpdateTexture() if (SUCCEEDED(surface->LockRect(&LockedRect, nullptr, D3DLOCK_DISCARD))) { auto surfaceData = static_cast(LockedRect.pBits); - auto stride = static_cast(LockedRect.Pitch); + auto stride = static_cast(LockedRect.Pitch); - Bitmap bitmap{surfaceData, pVectorGraphicItem->m_uiSizeX, pVectorGraphicItem->m_uiSizeY, stride}; + Bitmap bitmap{surfaceData, (int32_t)pVectorGraphicItem->m_uiSizeX, (int32_t)pVectorGraphicItem->m_uiSizeY, stride}; bitmap.clear(0); svgDocument->render(bitmap, transformationMatrix); UnpremultiplyBitmap(bitmap); diff --git a/Client/mods/deathmatch/premake5.lua b/Client/mods/deathmatch/premake5.lua index c8fdfd2ed8..07013f8d8d 100644 --- a/Client/mods/deathmatch/premake5.lua +++ b/Client/mods/deathmatch/premake5.lua @@ -7,7 +7,7 @@ project "Client Deathmatch" pchheader "StdInc.h" pchsource "StdInc.cpp" - defines { "LUA_USE_APICHECK", "SDK_WITH_BCRYPT" } + defines { "LUNASVG_BUILD", "LUA_USE_APICHECK", "SDK_WITH_BCRYPT" } links { "Lua_Client", "pcre", "json-c", "ws2_32", "portaudio", "zlib", "cryptopp", "libspeex", "blowfish_bcrypt", "lunasvg", "../../../vendor/bass/lib/bass", diff --git a/vendor/lunasvg/3rdparty/plutovg/LICENSE b/vendor/lunasvg/3rdparty/plutovg/LICENSE new file mode 100644 index 0000000000..62a964e73f --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2025 Samuel Ugochukwu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-blend.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-blend.c index 64cb79da26..e36b79dae7 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-blend.c +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-blend.c @@ -1,24 +1,24 @@ #include "plutovg-private.h" +#include "plutovg-utils.h" +#include #include -#include -#include #define COLOR_TABLE_SIZE 1024 typedef struct { - plutovg_spread_method_t spread; plutovg_matrix_t matrix; + plutovg_spread_method_t spread; uint32_t colortable[COLOR_TABLE_SIZE]; union { struct { - double x1, y1; - double x2, y2; + float x1, y1; + float x2, y2; } linear; struct { - double cx, cy, cr; - double fx, fy, fr; + float cx, cy, cr; + float fx, fy, fr; } radial; - }; + } values; } gradient_data_t; typedef struct { @@ -31,56 +31,31 @@ typedef struct { } texture_data_t; typedef struct { - double dx; - double dy; - double l; - double off; + float dx; + float dy; + float l; + float off; } linear_gradient_values_t; typedef struct { - double dx; - double dy; - double dr; - double sqrfr; - double a; - double inv2a; - int extended; + float dx; + float dy; + float dr; + float sqrfr; + float a; + bool extended; } radial_gradient_values_t; -static inline uint32_t premultiply_color(const plutovg_color_t* color, double opacity) +static inline uint32_t premultiply_color_with_opacity(const plutovg_color_t* color, float opacity) { - uint32_t alpha = (uint8_t)(color->a * opacity * 255); - uint32_t pr = (uint8_t)(color->r * alpha); - uint32_t pg = (uint8_t)(color->g * alpha); - uint32_t pb = (uint8_t)(color->b * alpha); - + uint32_t alpha = lroundf(color->a * opacity * 255); + uint32_t pr = lroundf(color->r * alpha); + uint32_t pg = lroundf(color->g * alpha); + uint32_t pb = lroundf(color->b * alpha); return (alpha << 24) | (pr << 16) | (pg << 8) | (pb); } -static inline uint32_t combine_opacity(const plutovg_color_t* color, double opacity) -{ - uint32_t a = (uint8_t)(color->a * opacity * 255); - uint32_t r = (uint8_t)(color->r * 255); - uint32_t g = (uint8_t)(color->g * 255); - uint32_t b = (uint8_t)(color->b * 255); - - return (a << 24) | (r << 16) | (g << 8) | (b); -} - -static inline uint32_t premultiply_pixel(uint32_t color) -{ - uint32_t a = plutovg_alpha(color); - uint32_t r = plutovg_red(color); - uint32_t g = plutovg_green(color); - uint32_t b = plutovg_blue(color); - - uint32_t pr = (r * a) / 255; - uint32_t pg = (g * a) / 255; - uint32_t pb = (b * a) / 255; - return (a << 24) | (pr << 16) | (pg << 8) | (pb); -} - -static inline uint32_t interpolate_pixel(uint32_t x, uint32_t a, uint32_t y, uint32_t b) +static inline uint32_t INTERPOLATE_PIXEL(uint32_t x, uint32_t a, uint32_t y, uint32_t b) { uint32_t t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; @@ -104,32 +79,90 @@ static inline uint32_t BYTE_MUL(uint32_t x, uint32_t a) return x; } -static inline void memfill32(uint32_t* dest, uint32_t value, int length) +#ifdef __SSE2__ + +#include + +void plutovg_memfill32(unsigned int* dest, int length, unsigned int value) { - for(int i = 0;i < length;i++) - dest[i] = value; + __m128i vector_data = _mm_set_epi32(value, value, value, value); + while(length && ((uintptr_t)dest & 0xf)) { + *dest++ = value; + length--; + } + + while(length >= 32) { + _mm_store_si128((__m128i*)(dest), vector_data); + _mm_store_si128((__m128i*)(dest + 4), vector_data); + _mm_store_si128((__m128i*)(dest + 8), vector_data); + _mm_store_si128((__m128i*)(dest + 12), vector_data); + _mm_store_si128((__m128i*)(dest + 16), vector_data); + _mm_store_si128((__m128i*)(dest + 20), vector_data); + _mm_store_si128((__m128i*)(dest + 24), vector_data); + _mm_store_si128((__m128i*)(dest + 28), vector_data); + + dest += 32; + length -= 32; + } + + if(length >= 16) { + _mm_store_si128((__m128i*)(dest), vector_data); + _mm_store_si128((__m128i*)(dest + 4), vector_data); + _mm_store_si128((__m128i*)(dest + 8), vector_data); + _mm_store_si128((__m128i*)(dest + 12), vector_data); + + dest += 16; + length -= 16; + } + + if(length >= 8) { + _mm_store_si128((__m128i*)(dest), vector_data); + _mm_store_si128((__m128i*)(dest + 4), vector_data); + + dest += 8; + length -= 8; + } + + if(length >= 4) { + _mm_store_si128((__m128i*)(dest), vector_data); + + dest += 4; + length -= 4; + } + + while(length) { + *dest++ = value; + length--; + } } +#else + +void plutovg_memfill32(unsigned int* dest, int length, unsigned int value) +{ + while(length--) { + *dest++ = value; + } +} + +#endif // __SSE2__ + static inline int gradient_clamp(const gradient_data_t* gradient, int ipos) { - if(gradient->spread == plutovg_spread_method_repeat) - { + if(gradient->spread == PLUTOVG_SPREAD_METHOD_REPEAT) { ipos = ipos % COLOR_TABLE_SIZE; ipos = ipos < 0 ? COLOR_TABLE_SIZE + ipos : ipos; - } - else if(gradient->spread == plutovg_spread_method_reflect) - { + } else if(gradient->spread == PLUTOVG_SPREAD_METHOD_REFLECT) { const int limit = COLOR_TABLE_SIZE * 2; ipos = ipos % limit; ipos = ipos < 0 ? limit + ipos : ipos; ipos = ipos >= COLOR_TABLE_SIZE ? limit - 1 - ipos : ipos; - } - else - { - if(ipos < 0) + } else { + if(ipos < 0) { ipos = 0; - else if(ipos >= COLOR_TABLE_SIZE) + } else if(ipos >= COLOR_TABLE_SIZE) { ipos = COLOR_TABLE_SIZE - 1; + } } return ipos; @@ -143,53 +176,42 @@ static inline uint32_t gradient_pixel_fixed(const gradient_data_t* gradient, int return gradient->colortable[gradient_clamp(gradient, ipos)]; } -static inline uint32_t gradient_pixel(const gradient_data_t* gradient, double pos) +static inline uint32_t gradient_pixel(const gradient_data_t* gradient, float pos) { - int ipos = (int)(pos * (COLOR_TABLE_SIZE - 1) + 0.5); + int ipos = (int)(pos * (COLOR_TABLE_SIZE - 1) + 0.5f); return gradient->colortable[gradient_clamp(gradient, ipos)]; } static void fetch_linear_gradient(uint32_t* buffer, const linear_gradient_values_t* v, const gradient_data_t* gradient, int y, int x, int length) { - double t, inc; - double rx = 0, ry = 0; + float t, inc; + float rx = 0, ry = 0; - if(v->l == 0.0) - { + if(v->l == 0.f) { t = inc = 0; - } - else - { - rx = gradient->matrix.m01 * (y + 0.5) + gradient->matrix.m00 * (x + 0.5) + gradient->matrix.m02; - ry = gradient->matrix.m11 * (y + 0.5) + gradient->matrix.m10 * (x + 0.5) + gradient->matrix.m12; + } else { + rx = gradient->matrix.c * (y + 0.5f) + gradient->matrix.a * (x + 0.5f) + gradient->matrix.e; + ry = gradient->matrix.d * (y + 0.5f) + gradient->matrix.b * (x + 0.5f) + gradient->matrix.f; t = v->dx * rx + v->dy * ry + v->off; - inc = v->dx * gradient->matrix.m00 + v->dy * gradient->matrix.m10; + inc = v->dx * gradient->matrix.a + v->dy * gradient->matrix.b; t *= (COLOR_TABLE_SIZE - 1); inc *= (COLOR_TABLE_SIZE - 1); } const uint32_t* end = buffer + length; - if(inc > -1e-5 && inc < 1e-5) - { - memfill32(buffer, gradient_pixel_fixed(gradient, (int)(t * FIXPT_SIZE)), length); - } - else - { - if(t + inc * length < (double)(INT_MAX >> (FIXPT_BITS + 1)) && t + inc * length > (double)(INT_MIN >> (FIXPT_BITS + 1))) - { + if(inc > -1e-5f && inc < 1e-5f) { + plutovg_memfill32(buffer, length, gradient_pixel_fixed(gradient, (int)(t * FIXPT_SIZE))); + } else { + if(t + inc * length < (float)(INT_MAX >> (FIXPT_BITS + 1)) && t + inc * length > (float)(INT_MIN >> (FIXPT_BITS + 1))) { int t_fixed = (int)(t * FIXPT_SIZE); int inc_fixed = (int)(inc * FIXPT_SIZE); - while(buffer < end) - { + while(buffer < end) { *buffer = gradient_pixel_fixed(gradient, t_fixed); t_fixed += inc_fixed; ++buffer; } - } - else - { - while(buffer < end) - { + } else { + while(buffer < end) { *buffer = gradient_pixel(gradient, t / COLOR_TABLE_SIZE); t += inc; ++buffer; @@ -200,56 +222,52 @@ static void fetch_linear_gradient(uint32_t* buffer, const linear_gradient_values static void fetch_radial_gradient(uint32_t* buffer, const radial_gradient_values_t* v, const gradient_data_t* gradient, int y, int x, int length) { - if(v->a == 0.0) - { - memfill32(buffer, 0, length); + if(v->a == 0.f) { + plutovg_memfill32(buffer, length, 0); return; } - double rx = gradient->matrix.m01 * (y + 0.5) + gradient->matrix.m02 + gradient->matrix.m00 * (x + 0.5); - double ry = gradient->matrix.m11 * (y + 0.5) + gradient->matrix.m12 + gradient->matrix.m10 * (x + 0.5); + float rx = gradient->matrix.c * (y + 0.5f) + gradient->matrix.e + gradient->matrix.a * (x + 0.5f); + float ry = gradient->matrix.d * (y + 0.5f) + gradient->matrix.f + gradient->matrix.b * (x + 0.5f); - rx -= gradient->radial.fx; - ry -= gradient->radial.fy; + rx -= gradient->values.radial.fx; + ry -= gradient->values.radial.fy; - double inv_a = 1 / (2 * v->a); - double delta_rx = gradient->matrix.m00; - double delta_ry = gradient->matrix.m10; + float inv_a = 1.f / (2.f * v->a); + float delta_rx = gradient->matrix.a; + float delta_ry = gradient->matrix.b; - double b = 2 * (v->dr * gradient->radial.fr + rx * v->dx + ry * v->dy); - double delta_b = 2 * (delta_rx * v->dx + delta_ry * v->dy); - double b_delta_b = 2 * b * delta_b; - double delta_b_delta_b = 2 * delta_b * delta_b; + float b = 2 * (v->dr * gradient->values.radial.fr + rx * v->dx + ry * v->dy); + float delta_b = 2 * (delta_rx * v->dx + delta_ry * v->dy); + float b_delta_b = 2 * b * delta_b; + float delta_b_delta_b = 2 * delta_b * delta_b; - double bb = b * b; - double delta_bb = delta_b * delta_b; + float bb = b * b; + float delta_bb = delta_b * delta_b; b *= inv_a; delta_b *= inv_a; - double rxrxryry = rx * rx + ry * ry; - double delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; - double rx_plus_ry = 2 * (rx * delta_rx + ry * delta_ry); - double delta_rx_plus_ry = 2 * delta_rxrxryry; + float rxrxryry = rx * rx + ry * ry; + float delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; + float rx_plus_ry = 2 * (rx * delta_rx + ry * delta_ry); + float delta_rx_plus_ry = 2 * delta_rxrxryry; inv_a *= inv_a; - double det = (bb - 4 * v->a * (v->sqrfr - rxrxryry)) * inv_a; - double delta_det = (b_delta_b + delta_bb + 4 * v->a * (rx_plus_ry + delta_rxrxryry)) * inv_a; - double delta_delta_det = (delta_b_delta_b + 4 * v->a * delta_rx_plus_ry) * inv_a; + float det = (bb - 4 * v->a * (v->sqrfr - rxrxryry)) * inv_a; + float delta_det = (b_delta_b + delta_bb + 4 * v->a * (rx_plus_ry + delta_rxrxryry)) * inv_a; + float delta_delta_det = (delta_b_delta_b + 4 * v->a * delta_rx_plus_ry) * inv_a; const uint32_t* end = buffer + length; - if(v->extended) - { - while(buffer < end) - { + if(v->extended) { + while(buffer < end) { uint32_t result = 0; - det = fabs(det) < DBL_EPSILON ? 0.0 : det; - if(det >= 0) - { - double w = sqrt(det) - b; - if(gradient->radial.fr + v->dr * w >= 0) + if(det >= 0) { + float w = sqrtf(det) - b; + if(gradient->values.radial.fr + v->dr * w >= 0) { result = gradient_pixel(gradient, w); + } } *buffer = result; @@ -258,16 +276,9 @@ static void fetch_radial_gradient(uint32_t* buffer, const radial_gradient_values b += delta_b; ++buffer; } - } - else - { - while(buffer < end) - { - det = fabs(det) < DBL_EPSILON ? 0.0 : det; - uint32_t result = 0; - if (det >= 0) - result = gradient_pixel(gradient, sqrt(det) - b); - *buffer++ = result; + } else { + while(buffer < end) { + *buffer++ = gradient_pixel(gradient, sqrtf(det) - b); det += delta_det; delta_det += delta_delta_det; b += delta_b; @@ -275,149 +286,361 @@ static void fetch_radial_gradient(uint32_t* buffer, const radial_gradient_values } } -static void composition_solid_source(uint32_t* dest, int length, uint32_t color, uint32_t alpha) +static void composition_solid_clear(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) { - if(alpha == 255) - { - memfill32(dest, color, length); + if(const_alpha == 255) { + plutovg_memfill32(dest, length, 0); + } else { + uint32_t ialpha = 255 - const_alpha; + for(int i = 0; i < length; i++) { + dest[i] = BYTE_MUL(dest[i], ialpha); + } } - else - { - uint32_t ialpha = 255 - alpha; - color = BYTE_MUL(color, alpha); - for(int i = 0;i < length;i++) +} + +static void composition_solid_source(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) +{ + if(const_alpha == 255) { + plutovg_memfill32(dest, length, color); + } else { + uint32_t ialpha = 255 - const_alpha; + color = BYTE_MUL(color, const_alpha); + for(int i = 0; i < length; i++) { dest[i] = color + BYTE_MUL(dest[i], ialpha); + } } } +static void composition_solid_destination(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) +{ +} + static void composition_solid_source_over(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) { - if(const_alpha != 255) color = BYTE_MUL(color, const_alpha); + if(const_alpha != 255) + color = BYTE_MUL(color, const_alpha); uint32_t ialpha = 255 - plutovg_alpha(color); - for(int i = 0;i < length;i++) + for(int i = 0; i < length; i++) { dest[i] = color + BYTE_MUL(dest[i], ialpha); + } +} + +static void composition_solid_destination_over(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) +{ + if(const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + dest[i] = d + BYTE_MUL(color, plutovg_alpha(~d)); + } +} + +static void composition_solid_source_in(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) +{ + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + dest[i] = BYTE_MUL(color, plutovg_alpha(dest[i])); + } + } else { + color = BYTE_MUL(color, const_alpha); + uint32_t cia = 255 - const_alpha; + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(color, plutovg_alpha(d), d, cia); + } + } } static void composition_solid_destination_in(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) { uint32_t a = plutovg_alpha(color); - if(const_alpha != 255) a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - for(int i = 0;i < length;i++) + if(const_alpha != 255) + a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; + for(int i = 0; i < length; i++) { dest[i] = BYTE_MUL(dest[i], a); + } +} + +static void composition_solid_source_out(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) +{ + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + dest[i] = BYTE_MUL(color, plutovg_alpha(~dest[i])); + } + } else { + color = BYTE_MUL(color, const_alpha); + uint32_t cia = 255 - const_alpha; + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(color, plutovg_alpha(~d), d, cia); + } + } } static void composition_solid_destination_out(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) { uint32_t a = plutovg_alpha(~color); - if(const_alpha != 255) a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - for(int i = 0; i < length;i++) + if(const_alpha != 255) + a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; + for(int i = 0; i < length; i++) { dest[i] = BYTE_MUL(dest[i], a); + } } -static void composition_source(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +static void composition_solid_source_atop(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) +{ + if(const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + uint32_t sia = plutovg_alpha(~color); + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(color, plutovg_alpha(d), d, sia); + } +} + +static void composition_solid_destination_atop(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) +{ + uint32_t a = plutovg_alpha(color); + if(const_alpha != 255) { + color = BYTE_MUL(color, const_alpha); + a = plutovg_alpha(color) + 255 - const_alpha; + } + + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(d, a, color, plutovg_alpha(~d)); + } +} + +static void composition_solid_xor(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha) +{ + if(const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + uint32_t sia = plutovg_alpha(~color); + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(color, plutovg_alpha(~d), d, sia); + } +} + +typedef void(*composition_solid_function_t)(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha); + +static const composition_solid_function_t composition_solid_table[] = { + composition_solid_clear, + composition_solid_source, + composition_solid_destination, + composition_solid_source_over, + composition_solid_destination_over, + composition_solid_source_in, + composition_solid_destination_in, + composition_solid_source_out, + composition_solid_destination_out, + composition_solid_source_atop, + composition_solid_destination_atop, + composition_solid_xor +}; + +static void composition_clear(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) { - if(const_alpha == 255) - { - memcpy(dest, src, (size_t)(length) * sizeof(uint32_t)); + if(const_alpha == 255) { + plutovg_memfill32(dest, length, 0); + } else { + uint32_t ialpha = 255 - const_alpha; + for(int i = 0; i < length; i++) { + dest[i] = BYTE_MUL(dest[i], ialpha); + } } - else - { +} + +static void composition_source(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +{ + if(const_alpha == 255) { + memcpy(dest, src, length * sizeof(uint32_t)); + } else { uint32_t ialpha = 255 - const_alpha; - for(int i = 0;i < length;i++) - dest[i] = interpolate_pixel(src[i], const_alpha, dest[i], ialpha); + for(int i = 0; i < length; i++) { + dest[i] = INTERPOLATE_PIXEL(src[i], const_alpha, dest[i], ialpha); + } } } +static void composition_destination(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +{ +} + static void composition_source_over(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) { - uint32_t s, sia; - if(const_alpha == 255) - { - for(int i = 0;i < length;i++) - { - s = src[i]; - if(s >= 0xff000000) + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + uint32_t s = src[i]; + if(s >= 0xff000000) { dest[i] = s; - else if(s != 0) - { - sia = plutovg_alpha(~s); - dest[i] = s + BYTE_MUL(dest[i], sia); + } else if (s != 0) { + dest[i] = s + BYTE_MUL(dest[i], plutovg_alpha(~s)); } } + } else { + for(int i = 0; i < length; i++) { + uint32_t s = BYTE_MUL(src[i], const_alpha); + dest[i] = s + BYTE_MUL(dest[i], plutovg_alpha(~s)); + } } - else - { - for(int i = 0;i < length;i++) - { - s = BYTE_MUL(src[i], const_alpha); - sia = plutovg_alpha(~s); - dest[i] = s + BYTE_MUL(dest[i], sia); +} + +static void composition_destination_over(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +{ + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + dest[i] = d + BYTE_MUL(src[i], plutovg_alpha(~d)); + } + } else { + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + uint32_t s = BYTE_MUL(src[i], const_alpha); + dest[i] = d + BYTE_MUL(s, plutovg_alpha(~d)); + } + } +} + +static void composition_source_in(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +{ + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + dest[i] = BYTE_MUL(src[i], plutovg_alpha(dest[i])); + } + } else { + uint32_t cia = 255 - const_alpha; + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + uint32_t s = BYTE_MUL(src[i], const_alpha); + dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(d), d, cia); } } } static void composition_destination_in(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) { - if(const_alpha == 255) - { - for(int i = 0; i < length;i++) + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { dest[i] = BYTE_MUL(dest[i], plutovg_alpha(src[i])); - } - else - { + } + } else { uint32_t cia = 255 - const_alpha; - uint32_t a; - for(int i = 0;i < length;i++) - { - a = BYTE_MUL(plutovg_alpha(src[i]), const_alpha) + cia; + for(int i = 0; i < length; i++) { + uint32_t a = BYTE_MUL(plutovg_alpha(src[i]), const_alpha) + cia; dest[i] = BYTE_MUL(dest[i], a); } } } +static void composition_source_out(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +{ + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + dest[i] = BYTE_MUL(src[i], plutovg_alpha(~dest[i])); + } + } else { + uint32_t cia = 255 - const_alpha; + for(int i = 0; i < length; i++) { + uint32_t s = BYTE_MUL(src[i], const_alpha); + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(~d), d, cia); + } + } +} + static void composition_destination_out(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) { - if(const_alpha == 255) - { - for(int i = 0;i < length;i++) + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { dest[i] = BYTE_MUL(dest[i], plutovg_alpha(~src[i])); - } - else - { + } + } else { uint32_t cia = 255 - const_alpha; - uint32_t sia; - for(int i = 0;i < length;i++) - { - sia = BYTE_MUL(plutovg_alpha(~src[i]), const_alpha) + cia; + for(int i = 0; i < length; i++) { + uint32_t sia = BYTE_MUL(plutovg_alpha(~src[i]), const_alpha) + cia; dest[i] = BYTE_MUL(dest[i], sia); } } } -typedef void(*composition_solid_function_t)(uint32_t* dest, int length, uint32_t color, uint32_t const_alpha); -typedef void(*composition_function_t)(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha); +static void composition_source_atop(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +{ + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + uint32_t s = src[i]; + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(d), d, plutovg_alpha(~s)); + } + } else { + for(int i = 0; i < length; i++) { + uint32_t s = BYTE_MUL(src[i], const_alpha); + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(d), d, plutovg_alpha(~s)); + } + } +} -static const composition_solid_function_t composition_solid_map[] = { - composition_solid_source, - composition_solid_source_over, - composition_solid_destination_in, - composition_solid_destination_out -}; +static void composition_destination_atop(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +{ + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + uint32_t s = src[i]; + uint32_t d = dest[i]; + dest[i] = INTERPOLATE_PIXEL(d, plutovg_alpha(s), s, plutovg_alpha(~d)); + } + } else { + uint32_t cia = 255 - const_alpha; + for(int i = 0; i < length; i++) { + uint32_t s = BYTE_MUL(src[i], const_alpha); + uint32_t d = dest[i]; + uint32_t a = plutovg_alpha(s) + cia; + dest[i] = INTERPOLATE_PIXEL(d, a, s, plutovg_alpha(~d)); + } + } +} + +static void composition_xor(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha) +{ + if(const_alpha == 255) { + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + uint32_t s = src[i]; + dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(~d), d, plutovg_alpha(~s)); + } + } else { + for(int i = 0; i < length; i++) { + uint32_t d = dest[i]; + uint32_t s = BYTE_MUL(src[i], const_alpha); + dest[i] = INTERPOLATE_PIXEL(s, plutovg_alpha(~d), d, plutovg_alpha(~s)); + } + } +} -static const composition_function_t composition_map[] = { +typedef void(*composition_function_t)(uint32_t* dest, int length, const uint32_t* src, uint32_t const_alpha); + +static const composition_function_t composition_table[] = { + composition_clear, composition_source, + composition_destination, composition_source_over, + composition_destination_over, + composition_source_in, composition_destination_in, - composition_destination_out + composition_source_out, + composition_destination_out, + composition_source_atop, + composition_destination_atop, + composition_xor }; -static void blend_solid(plutovg_surface_t* surface, plutovg_operator_t op, const plutovg_rle_t* rle, uint32_t solid) +static void blend_solid(plutovg_surface_t* surface, plutovg_operator_t op, uint32_t solid, const plutovg_span_buffer_t* span_buffer) { - composition_solid_function_t func = composition_solid_map[op]; - int count = rle->spans.size; - const plutovg_span_t* spans = rle->spans.data; - while(count--) - { + composition_solid_function_t func = composition_solid_table[op]; + int count = span_buffer->spans.size; + const plutovg_span_t* spans = span_buffer->spans.data; + while(count--) { uint32_t* target = (uint32_t*)(surface->data + spans->y * surface->stride) + spans->x; func(target, spans->len, solid, spans->coverage); ++spans; @@ -425,31 +648,28 @@ static void blend_solid(plutovg_surface_t* surface, plutovg_operator_t op, const } #define BUFFER_SIZE 1024 -static void blend_linear_gradient(plutovg_surface_t* surface, plutovg_operator_t op, const plutovg_rle_t* rle, const gradient_data_t* gradient) +static void blend_linear_gradient(plutovg_surface_t* surface, plutovg_operator_t op, const gradient_data_t* gradient, const plutovg_span_buffer_t* span_buffer) { - composition_function_t func = composition_map[op]; + composition_function_t func = composition_table[op]; unsigned int buffer[BUFFER_SIZE]; linear_gradient_values_t v; - v.dx = gradient->linear.x2 - gradient->linear.x1; - v.dy = gradient->linear.y2 - gradient->linear.y1; + v.dx = gradient->values.linear.x2 - gradient->values.linear.x1; + v.dy = gradient->values.linear.y2 - gradient->values.linear.y1; v.l = v.dx * v.dx + v.dy * v.dy; - v.off = 0.0; - if(v.l != 0.0) - { + v.off = 0.f; + if(v.l != 0.f) { v.dx /= v.l; v.dy /= v.l; - v.off = -v.dx * gradient->linear.x1 - v.dy * gradient->linear.y1; + v.off = -v.dx * gradient->values.linear.x1 - v.dy * gradient->values.linear.y1; } - int count = rle->spans.size; - const plutovg_span_t* spans = rle->spans.data; - while(count--) - { + int count = span_buffer->spans.size; + const plutovg_span_t* spans = span_buffer->spans.data; + while(count--) { int length = spans->len; int x = spans->x; - while(length) - { + while(length) { int l = plutovg_min(length, BUFFER_SIZE); fetch_linear_gradient(buffer, &v, gradient, spans->y, x, l); uint32_t* target = (uint32_t*)(surface->data + spans->y * surface->stride) + x; @@ -462,28 +682,25 @@ static void blend_linear_gradient(plutovg_surface_t* surface, plutovg_operator_t } } -static void blend_radial_gradient(plutovg_surface_t* surface, plutovg_operator_t op, const plutovg_rle_t* rle, const gradient_data_t* gradient) +static void blend_radial_gradient(plutovg_surface_t* surface, plutovg_operator_t op, const gradient_data_t* gradient, const plutovg_span_buffer_t* span_buffer) { - composition_function_t func = composition_map[op]; + composition_function_t func = composition_table[op]; unsigned int buffer[BUFFER_SIZE]; radial_gradient_values_t v; - v.dx = gradient->radial.cx - gradient->radial.fx; - v.dy = gradient->radial.cy - gradient->radial.fy; - v.dr = gradient->radial.cr - gradient->radial.fr; - v.sqrfr = gradient->radial.fr * gradient->radial.fr; + v.dx = gradient->values.radial.cx - gradient->values.radial.fx; + v.dy = gradient->values.radial.cy - gradient->values.radial.fy; + v.dr = gradient->values.radial.cr - gradient->values.radial.fr; + v.sqrfr = gradient->values.radial.fr * gradient->values.radial.fr; v.a = v.dr * v.dr - v.dx * v.dx - v.dy * v.dy; - v.inv2a = 1.0 / (2.0 * v.a); - v.extended = gradient->radial.fr != 0.0 || v.a <= 0.0; + v.extended = gradient->values.radial.fr != 0.f || v.a <= 0.f; - int count = rle->spans.size; - const plutovg_span_t* spans = rle->spans.data; - while(count--) - { + int count = span_buffer->spans.size; + const plutovg_span_t* spans = span_buffer->spans.data; + while(count--) { int length = spans->len; int x = spans->x; - while(length) - { + while(length) { int l = plutovg_min(length, BUFFER_SIZE); fetch_radial_gradient(buffer, &v, gradient, spans->y, x, l); uint32_t* target = (uint32_t*)(surface->data + spans->y * surface->stride) + x; @@ -496,42 +713,81 @@ static void blend_radial_gradient(plutovg_surface_t* surface, plutovg_operator_t } } +static void blend_untransformed_argb(plutovg_surface_t* surface, plutovg_operator_t op, const texture_data_t* texture, const plutovg_span_buffer_t* span_buffer) +{ + composition_function_t func = composition_table[op]; + + const int image_width = texture->width; + const int image_height = texture->height; + + int xoff = (int)(texture->matrix.e); + int yoff = (int)(texture->matrix.f); + + int count = span_buffer->spans.size; + const plutovg_span_t* spans = span_buffer->spans.data; + while(count--) { + int x = spans->x; + int length = spans->len; + int sx = xoff + x; + int sy = yoff + spans->y; + if(sy >= 0 && sy < image_height && sx < image_width) { + if(sx < 0) { + x -= sx; + length += sx; + sx = 0; + } + + if(sx + length > image_width) + length = image_width - sx; + if(length > 0) { + const int coverage = (spans->coverage * texture->const_alpha) >> 8; + const uint32_t* src = (const uint32_t*)(texture->data + sy * texture->stride) + sx; + uint32_t* dest = (uint32_t*)(surface->data + spans->y * surface->stride) + x; + func(dest, length, src, coverage); + } + } + + ++spans; + } +} + #define FIXED_SCALE (1 << 16) -static void blend_transformed_argb(plutovg_surface_t* surface, plutovg_operator_t op, const plutovg_rle_t* rle, const texture_data_t* texture) +static void blend_transformed_argb(plutovg_surface_t* surface, plutovg_operator_t op, const texture_data_t* texture, const plutovg_span_buffer_t* span_buffer) { - composition_function_t func = composition_map[op]; + composition_function_t func = composition_table[op]; uint32_t buffer[BUFFER_SIZE]; int image_width = texture->width; int image_height = texture->height; - int fdx = (int)(texture->matrix.m00 * FIXED_SCALE); - int fdy = (int)(texture->matrix.m10 * FIXED_SCALE); + int fdx = (int)(texture->matrix.a * FIXED_SCALE); + int fdy = (int)(texture->matrix.b * FIXED_SCALE); - int count = rle->spans.size; - const plutovg_span_t* spans = rle->spans.data; - while(count--) - { + int count = span_buffer->spans.size; + const plutovg_span_t* spans = span_buffer->spans.data; + while(count--) { uint32_t* target = (uint32_t*)(surface->data + spans->y * surface->stride) + spans->x; - const double cx = spans->x + 0.5; - const double cy = spans->y + 0.5; + const float cx = spans->x + 0.5f; + const float cy = spans->y + 0.5f; - int x = (int)((texture->matrix.m01 * cy + texture->matrix.m00 * cx + texture->matrix.m02) * FIXED_SCALE); - int y = (int)((texture->matrix.m11 * cy + texture->matrix.m10 * cx + texture->matrix.m12) * FIXED_SCALE); + int x = (int)((texture->matrix.c * cy + texture->matrix.a * cx + texture->matrix.e) * FIXED_SCALE); + int y = (int)((texture->matrix.d * cy + texture->matrix.b * cx + texture->matrix.f) * FIXED_SCALE); int length = spans->len; const int coverage = (spans->coverage * texture->const_alpha) >> 8; - while(length) - { + while(length) { int l = plutovg_min(length, BUFFER_SIZE); const uint32_t* end = buffer + l; uint32_t* b = buffer; - while(b < end) - { - int px = plutovg_clamp(x >> 16, 0, image_width - 1); - int py = plutovg_clamp(y >> 16, 0, image_height - 1); - *b = ((const uint32_t*)(texture->data + py * texture->stride))[px]; + while(b < end) { + int px = x >> 16; + int py = y >> 16; + if((px < 0) || (px >= image_width) || (py < 0) || (py >= image_height)) { + *b = 0x00000000; + } else { + *b = ((const uint32_t*)(texture->data + py * texture->stride))[px]; + } x += fdx; y += fdy; @@ -547,77 +803,37 @@ static void blend_transformed_argb(plutovg_surface_t* surface, plutovg_operator_ } } -static void blend_untransformed_argb(plutovg_surface_t* surface, plutovg_operator_t op, const plutovg_rle_t* rle, const texture_data_t* texture) -{ - composition_function_t func = composition_map[op]; - - const int image_width = texture->width; - const int image_height = texture->height; - - int xoff = (int)(texture->matrix.m02); - int yoff = (int)(texture->matrix.m12); - - int count = rle->spans.size; - const plutovg_span_t* spans = rle->spans.data; - while(count--) - { - int x = spans->x; - int length = spans->len; - int sx = xoff + x; - int sy = yoff + spans->y; - if(sy >= 0 && sy < image_height && sx < image_width) - { - if(sx < 0) - { - x -= sx; - length += sx; - sx = 0; - } - if(sx + length > image_width) length = image_width - sx; - if(length > 0) - { - const int coverage = (spans->coverage * texture->const_alpha) >> 8; - const uint32_t* src = (const uint32_t*)(texture->data + sy * texture->stride) + sx; - uint32_t* dest = (uint32_t*)(surface->data + spans->y * surface->stride) + x; - func(dest, length, src, coverage); - } - } - - ++spans; - } -} - -static void blend_untransformed_tiled_argb(plutovg_surface_t* surface, plutovg_operator_t op, const plutovg_rle_t* rle, const texture_data_t* texture) +static void blend_untransformed_tiled_argb(plutovg_surface_t* surface, plutovg_operator_t op, const texture_data_t* texture, const plutovg_span_buffer_t* span_buffer) { - composition_function_t func = composition_map[op]; + composition_function_t func = composition_table[op]; int image_width = texture->width; int image_height = texture->height; - int xoff = (int)(texture->matrix.m02) % image_width; - int yoff = (int)(texture->matrix.m12) % image_height; + int xoff = (int)(texture->matrix.e) % image_width; + int yoff = (int)(texture->matrix.f) % image_height; if(xoff < 0) xoff += image_width; - if(yoff < 0) + if(yoff < 0) { yoff += image_height; + } - int count = rle->spans.size; - const plutovg_span_t* spans = rle->spans.data; - while(count--) - { + int count = span_buffer->spans.size; + const plutovg_span_t* spans = span_buffer->spans.data; + while(count--) { int x = spans->x; int length = spans->len; int sx = (xoff + spans->x) % image_width; int sy = (spans->y + yoff) % image_height; if(sx < 0) sx += image_width; - if(sy < 0) + if(sy < 0) { sy += image_height; + } const int coverage = (spans->coverage * texture->const_alpha) >> 8; - while(length) - { + while(length) { int l = plutovg_min(image_width - sx, length); if(BUFFER_SIZE < l) l = BUFFER_SIZE; @@ -625,67 +841,62 @@ static void blend_untransformed_tiled_argb(plutovg_surface_t* surface, plutovg_o uint32_t* dest = (uint32_t*)(surface->data + spans->y * surface->stride) + x; func(dest, l, src, coverage); x += l; + sx += l; length -= l; - sx = 0; + if(sx >= image_width) { + sx = 0; + } } ++spans; } } -static void blend_transformed_tiled_argb(plutovg_surface_t* surface, plutovg_operator_t op, const plutovg_rle_t* rle, const texture_data_t* texture) +static void blend_transformed_tiled_argb(plutovg_surface_t* surface, plutovg_operator_t op, const texture_data_t* texture, const plutovg_span_buffer_t* span_buffer) { - composition_function_t func = composition_map[op]; + composition_function_t func = composition_table[op]; uint32_t buffer[BUFFER_SIZE]; int image_width = texture->width; int image_height = texture->height; const int scanline_offset = texture->stride / 4; - int fdx = (int)(texture->matrix.m00 * FIXED_SCALE); - int fdy = (int)(texture->matrix.m10 * FIXED_SCALE); + int fdx = (int)(texture->matrix.a * FIXED_SCALE); + int fdy = (int)(texture->matrix.b * FIXED_SCALE); - int count = rle->spans.size; - const plutovg_span_t* spans = rle->spans.data; - while(count--) - { + int count = span_buffer->spans.size; + const plutovg_span_t* spans = span_buffer->spans.data; + while(count--) { uint32_t* target = (uint32_t*)(surface->data + spans->y * surface->stride) + spans->x; const uint32_t* image_bits = (const uint32_t*)texture->data; - const double cx = spans->x + 0.5; - const double cy = spans->y + 0.5; + const float cx = spans->x + 0.5f; + const float cy = spans->y + 0.5f; - int x = (int)((texture->matrix.m01 * cy + texture->matrix.m00 * cx + texture->matrix.m02) * FIXED_SCALE); - int y = (int)((texture->matrix.m11 * cy + texture->matrix.m10 * cx + texture->matrix.m12) * FIXED_SCALE); + int x = (int)((texture->matrix.c * cy + texture->matrix.a * cx + texture->matrix.e) * FIXED_SCALE); + int y = (int)((texture->matrix.d * cy + texture->matrix.b * cx + texture->matrix.f) * FIXED_SCALE); const int coverage = (spans->coverage * texture->const_alpha) >> 8; int length = spans->len; - while(length) - { + while(length) { int l = plutovg_min(length, BUFFER_SIZE); const uint32_t* end = buffer + l; uint32_t* b = buffer; - int px16 = x % (image_width << 16); - int py16 = y % (image_height << 16); - int px_delta = fdx % (image_width << 16); - int py_delta = fdy % (image_height << 16); - while(b < end) - { - if(px16 < 0) px16 += image_width << 16; - if(py16 < 0) py16 += image_height << 16; - int px = px16 >> 16; - int py = py16 >> 16; + while(b < end) { + int px = x >> 16; + int py = y >> 16; + px %= image_width; + py %= image_height; + if(px < 0) px += image_width; + if(py < 0) py += image_height; int y_offset = py * scanline_offset; + assert(px >= 0 && px < image_width); + assert(py >= 0 && py < image_height); + *b = image_bits[y_offset + px]; x += fdx; y += fdy; - px16 += px_delta; - if(px16 >= image_width << 16) - px16 -= image_width << 16; - py16 += py_delta; - if(py16 >= image_height << 16) - py16 -= image_height << 16; ++b; } @@ -698,68 +909,63 @@ static void blend_transformed_tiled_argb(plutovg_surface_t* surface, plutovg_ope } } -void plutovg_blend(plutovg_t* pluto, const plutovg_rle_t* rle) -{ - plutovg_paint_t* source = &pluto->state->paint; - if(source->type == plutovg_paint_type_color) - plutovg_blend_color(pluto, rle, &source->color); - else if(source->type == plutovg_paint_type_gradient) - plutovg_blend_gradient(pluto, rle, &source->gradient); - else - plutovg_blend_texture(pluto, rle, &source->texture); -} - -void plutovg_blend_color(plutovg_t* pluto, const plutovg_rle_t* rle, const plutovg_color_t* color) +static void plutovg_blend_color(plutovg_canvas_t* canvas, const plutovg_color_t* color, const plutovg_span_buffer_t* span_buffer) { - plutovg_state_t* state = pluto->state; - uint32_t solid = premultiply_color(color, state->opacity); - + plutovg_state_t* state = canvas->state; + uint32_t solid = premultiply_color_with_opacity(color, state->opacity); uint32_t alpha = plutovg_alpha(solid); - if(alpha == 255 && state->op == plutovg_operator_src_over) - blend_solid(pluto->surface, plutovg_operator_src, rle, solid); - else - blend_solid(pluto->surface, state->op, rle, solid); + + if(alpha == 255 && state->op == PLUTOVG_OPERATOR_SRC_OVER) { + blend_solid(canvas->surface, PLUTOVG_OPERATOR_SRC, solid, span_buffer); + } else { + blend_solid(canvas->surface, state->op, solid, span_buffer); + } } -void plutovg_blend_gradient(plutovg_t* pluto, const plutovg_rle_t* rle, const plutovg_gradient_t* gradient) +static void plutovg_blend_gradient(plutovg_canvas_t* canvas, const plutovg_gradient_paint_t* gradient, const plutovg_span_buffer_t* span_buffer) { - plutovg_state_t* state = pluto->state; + if(gradient->nstops == 0) + return; + plutovg_state_t* state = canvas->state; gradient_data_t data; - int i, pos = 0, nstop = gradient->stops.size; + data.spread = gradient->spread; + data.matrix = gradient->matrix; + plutovg_matrix_multiply(&data.matrix, &data.matrix, &state->matrix); + if(!plutovg_matrix_invert(&data.matrix, &data.matrix)) + return; + int i, pos = 0, nstops = gradient->nstops; const plutovg_gradient_stop_t *curr, *next, *start, *last; uint32_t curr_color, next_color, last_color; uint32_t dist, idist; - double delta, t, incr, fpos; - double opacity = state->opacity * gradient->opacity; + float delta, t, incr, fpos; + float opacity = state->opacity; - start = gradient->stops.data; + start = gradient->stops; curr = start; - curr_color = combine_opacity(&curr->color, opacity); + curr_color = premultiply_color_with_opacity(&curr->color, opacity); - data.colortable[pos] = premultiply_pixel(curr_color); - ++pos; - incr = 1.0 / COLOR_TABLE_SIZE; - fpos = 1.5 * incr; + data.colortable[pos++] = curr_color; + incr = 1.0f / COLOR_TABLE_SIZE; + fpos = 1.5f * incr; - while(fpos <= curr->offset) - { + while(fpos <= curr->offset) { data.colortable[pos] = data.colortable[pos - 1]; ++pos; fpos += incr; } - for(i = 0;i < nstop - 1;i++) - { + for(i = 0; i < nstops - 1; i++) { curr = (start + i); next = (start + i + 1); - delta = 1.0 / (next->offset - curr->offset); - next_color = combine_opacity(&next->color, opacity); - while(fpos < next->offset && pos < COLOR_TABLE_SIZE) - { + if(curr->offset == next->offset) + continue; + delta = 1.f / (next->offset - curr->offset); + next_color = premultiply_color_with_opacity(&next->color, opacity); + while(fpos < next->offset && pos < COLOR_TABLE_SIZE) { t = (fpos - curr->offset) * delta; dist = (uint32_t)(255 * t); idist = 255 - dist; - data.colortable[pos] = premultiply_pixel(interpolate_pixel(curr_color, idist, next_color, dist)); + data.colortable[pos] = INTERPOLATE_PIXEL(curr_color, idist, next_color, dist); ++pos; fpos += incr; } @@ -767,64 +973,79 @@ void plutovg_blend_gradient(plutovg_t* pluto, const plutovg_rle_t* rle, const pl curr_color = next_color; } - last = start + nstop - 1; - last_color = premultiply_color(&last->color, opacity); - for(;pos < COLOR_TABLE_SIZE;++pos) + last = start + nstops - 1; + last_color = premultiply_color_with_opacity(&last->color, opacity); + for(; pos < COLOR_TABLE_SIZE; ++pos) { data.colortable[pos] = last_color; - - data.spread = gradient->spread; - data.matrix = gradient->matrix; - plutovg_matrix_multiply(&data.matrix, &data.matrix, &state->matrix); - plutovg_matrix_invert(&data.matrix); - - if(gradient->type==plutovg_gradient_type_linear) - { - data.linear.x1 = gradient->values[0]; - data.linear.y1 = gradient->values[1]; - data.linear.x2 = gradient->values[2]; - data.linear.y2 = gradient->values[3]; - blend_linear_gradient(pluto->surface, state->op, rle, &data); } - else - { - data.radial.cx = gradient->values[0]; - data.radial.cy = gradient->values[1]; - data.radial.cr = gradient->values[2]; - data.radial.fx = gradient->values[3]; - data.radial.fy = gradient->values[4]; - data.radial.fr = gradient->values[5]; - blend_radial_gradient(pluto->surface, state->op, rle, &data); + + if(gradient->type == PLUTOVG_GRADIENT_TYPE_LINEAR) { + data.values.linear.x1 = gradient->values[0]; + data.values.linear.y1 = gradient->values[1]; + data.values.linear.x2 = gradient->values[2]; + data.values.linear.y2 = gradient->values[3]; + blend_linear_gradient(canvas->surface, state->op, &data, span_buffer); + } else { + data.values.radial.cx = gradient->values[0]; + data.values.radial.cy = gradient->values[1]; + data.values.radial.cr = gradient->values[2]; + data.values.radial.fx = gradient->values[3]; + data.values.radial.fy = gradient->values[4]; + data.values.radial.fr = gradient->values[5]; + blend_radial_gradient(canvas->surface, state->op, &data, span_buffer); } } -void plutovg_blend_texture(plutovg_t* pluto, const plutovg_rle_t* rle, const plutovg_texture_t* texture) +static void plutovg_blend_texture(plutovg_canvas_t* canvas, const plutovg_texture_paint_t* texture, const plutovg_span_buffer_t* span_buffer) { - plutovg_state_t* state = pluto->state; + if(texture->surface == NULL) + return; + plutovg_state_t* state = canvas->state; texture_data_t data; + data.matrix = texture->matrix; data.data = texture->surface->data; data.width = texture->surface->width; data.height = texture->surface->height; data.stride = texture->surface->stride; - data.const_alpha = (int)(state->opacity * texture->opacity * 256.0); + data.const_alpha = lroundf(state->opacity * texture->opacity * 256); - data.matrix = texture->matrix; plutovg_matrix_multiply(&data.matrix, &data.matrix, &state->matrix); - plutovg_matrix_invert(&data.matrix); - + if(!plutovg_matrix_invert(&data.matrix, &data.matrix)) + return; const plutovg_matrix_t* matrix = &data.matrix; - int translating = (matrix->m00==1.0 && matrix->m10==0.0 && matrix->m01==0.0 && matrix->m11==1.0); - if(translating) - { - if(texture->type==plutovg_texture_type_plain) - blend_untransformed_argb(pluto->surface, state->op, rle, &data); - else - blend_untransformed_tiled_argb(pluto->surface, state->op, rle, &data); - } - else - { - if(texture->type==plutovg_texture_type_plain) - blend_transformed_argb(pluto->surface, state->op, rle, &data); - else - blend_transformed_tiled_argb(pluto->surface, state->op, rle, &data); + if(matrix->a == 1 && matrix->b == 0 && matrix->c == 0 && matrix->d == 1) { + if(texture->type == PLUTOVG_TEXTURE_TYPE_PLAIN) { + blend_untransformed_argb(canvas->surface, state->op, &data, span_buffer); + } else { + blend_untransformed_tiled_argb(canvas->surface, state->op, &data, span_buffer); + } + } else { + if(texture->type == PLUTOVG_TEXTURE_TYPE_PLAIN) { + blend_transformed_argb(canvas->surface, state->op, &data, span_buffer); + } else { + blend_transformed_tiled_argb(canvas->surface, state->op, &data, span_buffer); + } + } +} + +void plutovg_blend(plutovg_canvas_t* canvas, const plutovg_span_buffer_t* span_buffer) +{ + if(span_buffer->spans.size == 0) + return; + if(canvas->state->paint == NULL) { + plutovg_blend_color(canvas, &canvas->state->color, span_buffer); + return; + } + + plutovg_paint_t* paint = canvas->state->paint; + if(paint->type == PLUTOVG_PAINT_TYPE_COLOR) { + plutovg_solid_paint_t* solid = (plutovg_solid_paint_t*)(paint); + plutovg_blend_color(canvas, &solid->color, span_buffer); + } else if(paint->type == PLUTOVG_PAINT_TYPE_GRADIENT) { + plutovg_gradient_paint_t* gradient = (plutovg_gradient_paint_t*)(paint); + plutovg_blend_gradient(canvas, gradient, span_buffer); + } else { + plutovg_texture_paint_t* texture = (plutovg_texture_paint_t*)(paint); + plutovg_blend_texture(canvas, texture, span_buffer); } } diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-canvas.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-canvas.c new file mode 100644 index 0000000000..187b2ef81e --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-canvas.c @@ -0,0 +1,714 @@ +#include "plutovg-private.h" +#include "plutovg-utils.h" + +int plutovg_version(void) +{ + return PLUTOVG_VERSION; +} + +const char* plutovg_version_string(void) +{ + return PLUTOVG_VERSION_STRING; +} + +#define PLUTOVG_DEFAULT_STROKE_STYLE ((plutovg_stroke_style_t){1.f, PLUTOVG_LINE_CAP_BUTT, PLUTOVG_LINE_JOIN_MITER, 10.f}) + +static plutovg_state_t* plutovg_state_create(void) +{ + plutovg_state_t* state = malloc(sizeof(plutovg_state_t)); + state->paint = NULL; + state->font_face = NULL; + state->color = PLUTOVG_BLACK_COLOR; + state->matrix = PLUTOVG_IDENTITY_MATRIX; + state->stroke.style = PLUTOVG_DEFAULT_STROKE_STYLE; + state->stroke.dash.offset = 0.f; + plutovg_array_init(state->stroke.dash.array); + plutovg_span_buffer_init(&state->clip_spans); + state->winding = PLUTOVG_FILL_RULE_NON_ZERO; + state->op = PLUTOVG_OPERATOR_SRC_OVER; + state->font_size = 12.f; + state->opacity = 1.f; + state->clipping = false; + state->next = NULL; + return state; +} + +static void plutovg_state_reset(plutovg_state_t* state) +{ + plutovg_paint_destroy(state->paint); + plutovg_font_face_destroy(state->font_face); + state->paint = NULL; + state->font_face = NULL; + state->color = PLUTOVG_BLACK_COLOR; + state->matrix = PLUTOVG_IDENTITY_MATRIX; + state->stroke.style = PLUTOVG_DEFAULT_STROKE_STYLE; + state->stroke.dash.offset = 0.f; + plutovg_array_clear(state->stroke.dash.array); + plutovg_span_buffer_reset(&state->clip_spans); + state->winding = PLUTOVG_FILL_RULE_NON_ZERO; + state->op = PLUTOVG_OPERATOR_SRC_OVER; + state->font_size = 12.f; + state->opacity = 1.f; + state->clipping = false; +} + +static void plutovg_state_copy(plutovg_state_t* state, const plutovg_state_t* source) +{ + state->paint = plutovg_paint_reference(source->paint); + state->font_face = plutovg_font_face_reference(source->font_face); + state->color = source->color; + state->matrix = source->matrix; + state->stroke.style = source->stroke.style; + state->stroke.dash.offset = source->stroke.dash.offset; + plutovg_array_clear(state->stroke.dash.array); + plutovg_array_append(state->stroke.dash.array, source->stroke.dash.array); + plutovg_span_buffer_copy(&state->clip_spans, &source->clip_spans); + state->winding = source->winding; + state->op = source->op; + state->font_size = source->font_size; + state->opacity = source->opacity; + state->clipping = source->clipping; +} + +static void plutovg_state_destroy(plutovg_state_t* state) +{ + plutovg_paint_destroy(state->paint); + plutovg_font_face_destroy(state->font_face); + plutovg_array_destroy(state->stroke.dash.array); + plutovg_span_buffer_destroy(&state->clip_spans); + free(state); +} + +plutovg_canvas_t* plutovg_canvas_create(plutovg_surface_t* surface) +{ + plutovg_canvas_t* canvas = malloc(sizeof(plutovg_canvas_t)); + canvas->ref_count = 1; + canvas->surface = plutovg_surface_reference(surface); + canvas->path = plutovg_path_create(); + canvas->state = plutovg_state_create(); + canvas->freed_state = NULL; + canvas->clip_rect = PLUTOVG_MAKE_RECT(0, 0, surface->width, surface->height); + plutovg_span_buffer_init(&canvas->clip_spans); + plutovg_span_buffer_init(&canvas->fill_spans); + return canvas; +} + +plutovg_canvas_t* plutovg_canvas_reference(plutovg_canvas_t* canvas) +{ + if(canvas == NULL) + return NULL; + ++canvas->ref_count; + return canvas; +} + +void plutovg_canvas_destroy(plutovg_canvas_t* canvas) +{ + if(canvas == NULL) + return; + if(--canvas->ref_count == 0) { + while(canvas->state) { + plutovg_state_t* state = canvas->state; + canvas->state = state->next; + plutovg_state_destroy(state); + } + + while(canvas->freed_state) { + plutovg_state_t* state = canvas->freed_state; + canvas->freed_state = state->next; + plutovg_state_destroy(state); + } + + plutovg_span_buffer_destroy(&canvas->fill_spans); + plutovg_span_buffer_destroy(&canvas->clip_spans); + plutovg_surface_destroy(canvas->surface); + plutovg_path_destroy(canvas->path); + free(canvas); + } +} + +int plutovg_canvas_get_reference_count(const plutovg_canvas_t* canvas) +{ + if(canvas == NULL) + return 0; + return canvas->ref_count; +} + +plutovg_surface_t* plutovg_canvas_get_surface(const plutovg_canvas_t* canvas) +{ + return canvas->surface; +} + +void plutovg_canvas_save(plutovg_canvas_t* canvas) +{ + plutovg_state_t* new_state = canvas->freed_state; + if(new_state == NULL) + new_state = plutovg_state_create(); + else + canvas->freed_state = new_state->next; + plutovg_state_copy(new_state, canvas->state); + new_state->next = canvas->state; + canvas->state = new_state; +} + +void plutovg_canvas_restore(plutovg_canvas_t* canvas) +{ + if(canvas->state->next == NULL) + return; + plutovg_state_t* old_state = canvas->state; + canvas->state = old_state->next; + plutovg_state_reset(old_state); + old_state->next = canvas->freed_state; + canvas->freed_state = old_state; +} + +void plutovg_canvas_set_rgb(plutovg_canvas_t* canvas, float r, float g, float b) +{ + plutovg_canvas_set_rgba(canvas, r, g, b, 1.f); +} + +void plutovg_canvas_set_rgba(plutovg_canvas_t* canvas, float r, float g, float b, float a) +{ + plutovg_color_init_rgba(&canvas->state->color, r, g, b, a); + plutovg_canvas_set_paint(canvas, NULL); +} + +void plutovg_canvas_set_color(plutovg_canvas_t* canvas, const plutovg_color_t* color) +{ + plutovg_canvas_set_rgba(canvas, color->r, color->g, color->b, color->a); +} + +void plutovg_canvas_set_linear_gradient(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix) +{ + plutovg_paint_t* paint = plutovg_paint_create_linear_gradient(x1, y1, x2, y2, spread, stops, nstops, matrix); + plutovg_canvas_set_paint(canvas, paint); + plutovg_paint_destroy(paint); +} + +void plutovg_canvas_set_radial_gradient(plutovg_canvas_t* canvas, float cx, float cy, float cr, float fx, float fy, float fr, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix) +{ + plutovg_paint_t* paint = plutovg_paint_create_radial_gradient(cx, cy, cr, fx, fy, fr, spread, stops, nstops, matrix); + plutovg_canvas_set_paint(canvas, paint); + plutovg_paint_destroy(paint); +} + +void plutovg_canvas_set_texture(plutovg_canvas_t* canvas, plutovg_surface_t* surface, plutovg_texture_type_t type, float opacity, const plutovg_matrix_t* matrix) +{ + plutovg_paint_t* paint = plutovg_paint_create_texture(surface, type, opacity, matrix); + plutovg_canvas_set_paint(canvas, paint); + plutovg_paint_destroy(paint); +} + +void plutovg_canvas_set_paint(plutovg_canvas_t* canvas, plutovg_paint_t* paint) +{ + paint = plutovg_paint_reference(paint); + plutovg_paint_destroy(canvas->state->paint); + canvas->state->paint = paint; +} + +plutovg_paint_t* plutovg_canvas_get_paint(const plutovg_canvas_t* canvas, plutovg_color_t* color) +{ + if(color) + *color = canvas->state->color; + return canvas->state->paint; +} + +void plutovg_canvas_set_font(plutovg_canvas_t* canvas, plutovg_font_face_t* face, float size) +{ + plutovg_canvas_set_font_face(canvas, face); + plutovg_canvas_set_font_size(canvas, size); +} + +void plutovg_canvas_set_font_face(plutovg_canvas_t* canvas, plutovg_font_face_t* face) +{ + face = plutovg_font_face_reference(face); + plutovg_font_face_destroy(canvas->state->font_face); + canvas->state->font_face = face; +} + +plutovg_font_face_t* plutovg_canvas_get_font_face(const plutovg_canvas_t* canvas) +{ + return canvas->state->font_face; +} + +void plutovg_canvas_set_font_size(plutovg_canvas_t* canvas, float size) +{ + canvas->state->font_size = size; +} + +float plutovg_canvas_get_font_size(const plutovg_canvas_t* canvas) +{ + return canvas->state->font_size; +} + +void plutovg_canvas_set_fill_rule(plutovg_canvas_t* canvas, plutovg_fill_rule_t winding) +{ + canvas->state->winding = winding; +} + +plutovg_fill_rule_t plutovg_canvas_get_fill_rule(const plutovg_canvas_t* canvas) +{ + return canvas->state->winding; +} + +void plutovg_canvas_set_operator(plutovg_canvas_t* canvas, plutovg_operator_t op) +{ + canvas->state->op = op; +} + +plutovg_operator_t plutovg_canvas_get_operator(const plutovg_canvas_t* canvas) +{ + return canvas->state->op; +} + +void plutovg_canvas_set_opacity(plutovg_canvas_t* canvas, float opacity) +{ + canvas->state->opacity = plutovg_clamp(opacity, 0.f, 1.f); +} + +float plutovg_canvas_get_opacity(const plutovg_canvas_t* canvas) +{ + return canvas->state->opacity; +} + +void plutovg_canvas_set_line_width(plutovg_canvas_t* canvas, float line_width) +{ + canvas->state->stroke.style.width = line_width; +} + +float plutovg_canvas_get_line_width(const plutovg_canvas_t* canvas) +{ + return canvas->state->stroke.style.width; +} + +void plutovg_canvas_set_line_cap(plutovg_canvas_t* canvas, plutovg_line_cap_t line_cap) +{ + canvas->state->stroke.style.cap = line_cap; +} + +plutovg_line_cap_t plutovg_canvas_get_line_cap(const plutovg_canvas_t* canvas) +{ + return canvas->state->stroke.style.cap; +} + +void plutovg_canvas_set_line_join(plutovg_canvas_t* canvas, plutovg_line_join_t line_join) +{ + canvas->state->stroke.style.join = line_join; +} + +plutovg_line_join_t plutovg_canvas_get_line_join(const plutovg_canvas_t* canvas) +{ + return canvas->state->stroke.style.join; +} + +void plutovg_canvas_set_miter_limit(plutovg_canvas_t* canvas, float miter_limit) +{ + canvas->state->stroke.style.miter_limit = miter_limit; +} + +float plutovg_canvas_get_miter_limit(const plutovg_canvas_t* canvas) +{ + return canvas->state->stroke.style.miter_limit; +} + +void plutovg_canvas_set_dash(plutovg_canvas_t* canvas, float offset, const float* dashes, int ndashes) +{ + plutovg_canvas_set_dash_offset(canvas, offset); + plutovg_canvas_set_dash_array(canvas, dashes, ndashes); +} + +void plutovg_canvas_set_dash_offset(plutovg_canvas_t* canvas, float offset) +{ + canvas->state->stroke.dash.offset = offset; +} + +float plutovg_canvas_get_dash_offset(const plutovg_canvas_t* canvas) +{ + return canvas->state->stroke.dash.offset; +} + +void plutovg_canvas_set_dash_array(plutovg_canvas_t* canvas, const float* dashes, int ndashes) +{ + plutovg_array_clear(canvas->state->stroke.dash.array); + plutovg_array_append_data(canvas->state->stroke.dash.array, dashes, ndashes); +} + +int plutovg_canvas_get_dash_array(const plutovg_canvas_t* canvas, const float** dashes) +{ + if(dashes) + *dashes = canvas->state->stroke.dash.array.data; + return canvas->state->stroke.dash.array.size; +} + +void plutovg_canvas_translate(plutovg_canvas_t* canvas, float tx, float ty) +{ + plutovg_matrix_translate(&canvas->state->matrix, tx, ty); +} + +void plutovg_canvas_scale(plutovg_canvas_t* canvas, float sx, float sy) +{ + plutovg_matrix_scale(&canvas->state->matrix, sx, sy); +} + +void plutovg_canvas_shear(plutovg_canvas_t* canvas, float shx, float shy) +{ + plutovg_matrix_shear(&canvas->state->matrix, shx, shy); +} + +void plutovg_canvas_rotate(plutovg_canvas_t* canvas, float angle) +{ + plutovg_matrix_rotate(&canvas->state->matrix, angle); +} + +void plutovg_canvas_transform(plutovg_canvas_t* canvas, const plutovg_matrix_t* matrix) +{ + plutovg_matrix_multiply(&canvas->state->matrix, matrix, &canvas->state->matrix); +} + +void plutovg_canvas_reset_matrix(plutovg_canvas_t* canvas) +{ + plutovg_matrix_init_identity(&canvas->state->matrix); +} + +void plutovg_canvas_set_matrix(plutovg_canvas_t* canvas, const plutovg_matrix_t* matrix) +{ + canvas->state->matrix = matrix ? *matrix : PLUTOVG_IDENTITY_MATRIX; +} + +void plutovg_canvas_get_matrix(const plutovg_canvas_t* canvas, plutovg_matrix_t* matrix) +{ + *matrix = canvas->state->matrix; +} + +void plutovg_canvas_map(const plutovg_canvas_t* canvas, float x, float y, float* xx, float* yy) +{ + plutovg_matrix_map(&canvas->state->matrix, x, y, xx, yy); +} + +void plutovg_canvas_map_point(const plutovg_canvas_t* canvas, const plutovg_point_t* src, plutovg_point_t* dst) +{ + plutovg_matrix_map_point(&canvas->state->matrix, src, dst); +} + +void plutovg_canvas_map_rect(const plutovg_canvas_t* canvas, const plutovg_rect_t* src, plutovg_rect_t* dst) +{ + plutovg_matrix_map_rect(&canvas->state->matrix, src, dst); +} + +void plutovg_canvas_move_to(plutovg_canvas_t* canvas, float x, float y) +{ + plutovg_path_move_to(canvas->path, x, y); +} + +void plutovg_canvas_line_to(plutovg_canvas_t* canvas, float x, float y) +{ + plutovg_path_line_to(canvas->path, x, y); +} + +void plutovg_canvas_quad_to(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2) +{ + plutovg_path_quad_to(canvas->path, x1, y1, x2, y2); +} + +void plutovg_canvas_cubic_to(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2, float x3, float y3) +{ + plutovg_path_cubic_to(canvas->path, x1, y1, x2, y2, x3, y3); +} + +void plutovg_canvas_arc_to(plutovg_canvas_t* canvas, float rx, float ry, float angle, bool large_arc_flag, bool sweep_flag, float x, float y) +{ + plutovg_path_arc_to(canvas->path, rx, ry, angle, large_arc_flag, sweep_flag, x, y); +} + +void plutovg_canvas_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h) +{ + plutovg_path_add_rect(canvas->path, x, y, w, h); +} + +void plutovg_canvas_round_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h, float rx, float ry) +{ + plutovg_path_add_round_rect(canvas->path, x, y, w, h, rx, ry); +} + +void plutovg_canvas_ellipse(plutovg_canvas_t* canvas, float cx, float cy, float rx, float ry) +{ + plutovg_path_add_ellipse(canvas->path, cx, cy, rx, ry); +} + +void plutovg_canvas_circle(plutovg_canvas_t* canvas, float cx, float cy, float r) +{ + plutovg_path_add_circle(canvas->path, cx, cy, r); +} + +void plutovg_canvas_arc(plutovg_canvas_t* canvas, float cx, float cy, float r, float a0, float a1, bool ccw) +{ + plutovg_path_add_arc(canvas->path, cx, cy, r, a0, a1, ccw); +} + +void plutovg_canvas_add_path(plutovg_canvas_t* canvas, const plutovg_path_t* path) +{ + plutovg_path_add_path(canvas->path, path, NULL); +} + +void plutovg_canvas_new_path(plutovg_canvas_t* canvas) +{ + plutovg_path_reset(canvas->path); +} + +void plutovg_canvas_close_path(plutovg_canvas_t* canvas) +{ + plutovg_path_close(canvas->path); +} + +void plutovg_canvas_get_current_point(const plutovg_canvas_t* canvas, float* x, float* y) +{ + plutovg_path_get_current_point(canvas->path, x, y); +} + +plutovg_path_t* plutovg_canvas_get_path(const plutovg_canvas_t* canvas) +{ + return canvas->path; +} + +void plutovg_canvas_fill_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents) +{ + plutovg_path_extents(canvas->path, extents, true); + plutovg_canvas_map_rect(canvas, extents, extents); +} + +void plutovg_canvas_stroke_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents) +{ + plutovg_stroke_data_t* stroke = &canvas->state->stroke; + float cap_limit = stroke->style.width / 2.f; + if(stroke->style.cap == PLUTOVG_LINE_CAP_SQUARE) + cap_limit *= PLUTOVG_SQRT2; + float join_limit = stroke->style.width / 2.f; + if(stroke->style.join == PLUTOVG_LINE_JOIN_MITER) { + join_limit *= stroke->style.miter_limit; + } + + float delta = plutovg_max(cap_limit, join_limit); + plutovg_path_extents(canvas->path, extents, true); + extents->x -= delta; + extents->y -= delta; + extents->w += delta * 2.f; + extents->h += delta * 2.f; + plutovg_canvas_map_rect(canvas, extents, extents); +} + +void plutovg_canvas_clip_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents) +{ + if(canvas->state->clipping) { + plutovg_span_buffer_extents(&canvas->state->clip_spans, extents); + } else { + extents->x = canvas->clip_rect.x; + extents->y = canvas->clip_rect.y; + extents->w = canvas->clip_rect.w; + extents->h = canvas->clip_rect.h; + } +} + +void plutovg_canvas_fill(plutovg_canvas_t* canvas) +{ + plutovg_canvas_fill_preserve(canvas); + plutovg_canvas_new_path(canvas); +} + +void plutovg_canvas_stroke(plutovg_canvas_t* canvas) +{ + plutovg_canvas_stroke_preserve(canvas); + plutovg_canvas_new_path(canvas); +} + +void plutovg_canvas_clip(plutovg_canvas_t* canvas) +{ + plutovg_canvas_clip_preserve(canvas); + plutovg_canvas_new_path(canvas); +} + +void plutovg_canvas_paint(plutovg_canvas_t* canvas) +{ + if(canvas->state->clipping) { + plutovg_blend(canvas, &canvas->state->clip_spans); + } else { + plutovg_span_buffer_init_rect(&canvas->clip_spans, 0, 0, canvas->surface->width, canvas->surface->height); + plutovg_blend(canvas, &canvas->clip_spans); + } +} + +void plutovg_canvas_fill_preserve(plutovg_canvas_t* canvas) +{ + plutovg_rasterize(&canvas->fill_spans, canvas->path, &canvas->state->matrix, &canvas->clip_rect, NULL, canvas->state->winding); + if(canvas->state->clipping) { + plutovg_span_buffer_intersect(&canvas->clip_spans, &canvas->fill_spans, &canvas->state->clip_spans); + plutovg_blend(canvas, &canvas->clip_spans); + } else { + plutovg_blend(canvas, &canvas->fill_spans); + } +} + +void plutovg_canvas_stroke_preserve(plutovg_canvas_t* canvas) +{ + plutovg_rasterize(&canvas->fill_spans, canvas->path, &canvas->state->matrix, &canvas->clip_rect, &canvas->state->stroke, PLUTOVG_FILL_RULE_NON_ZERO); + if(canvas->state->clipping) { + plutovg_span_buffer_intersect(&canvas->clip_spans, &canvas->fill_spans, &canvas->state->clip_spans); + plutovg_blend(canvas, &canvas->clip_spans); + } else { + plutovg_blend(canvas, &canvas->fill_spans); + } +} + +void plutovg_canvas_clip_preserve(plutovg_canvas_t* canvas) +{ + if(canvas->state->clipping) { + plutovg_rasterize(&canvas->fill_spans, canvas->path, &canvas->state->matrix, &canvas->clip_rect, NULL, canvas->state->winding); + plutovg_span_buffer_intersect(&canvas->clip_spans, &canvas->fill_spans, &canvas->state->clip_spans); + plutovg_span_buffer_copy(&canvas->state->clip_spans, &canvas->clip_spans); + } else { + plutovg_rasterize(&canvas->state->clip_spans, canvas->path, &canvas->state->matrix, &canvas->clip_rect, NULL, canvas->state->winding); + canvas->state->clipping = true; + } +} + +void plutovg_canvas_fill_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h) +{ + plutovg_canvas_new_path(canvas); + plutovg_canvas_rect(canvas, x, y, w, h); + plutovg_canvas_fill(canvas); +} + +void plutovg_canvas_fill_path(plutovg_canvas_t* canvas, const plutovg_path_t* path) +{ + plutovg_canvas_new_path(canvas); + plutovg_canvas_add_path(canvas, path); + plutovg_canvas_fill(canvas); +} + +void plutovg_canvas_stroke_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h) +{ + plutovg_canvas_new_path(canvas); + plutovg_canvas_rect(canvas, x, y, w, h); + plutovg_canvas_stroke(canvas); +} + +void plutovg_canvas_stroke_path(plutovg_canvas_t* canvas, const plutovg_path_t* path) +{ + plutovg_canvas_new_path(canvas); + plutovg_canvas_add_path(canvas, path); + plutovg_canvas_stroke(canvas); +} + +void plutovg_canvas_clip_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h) +{ + plutovg_canvas_new_path(canvas); + plutovg_canvas_rect(canvas, x, y, w, h); + plutovg_canvas_clip(canvas); +} + +void plutovg_canvas_clip_path(plutovg_canvas_t* canvas, const plutovg_path_t* path) +{ + plutovg_canvas_new_path(canvas); + plutovg_canvas_add_path(canvas, path); + plutovg_canvas_clip(canvas); +} + +float plutovg_canvas_add_glyph(plutovg_canvas_t* canvas, plutovg_codepoint_t codepoint, float x, float y) +{ + plutovg_state_t* state = canvas->state; + if(state->font_face && state->font_size > 0.f) + return plutovg_font_face_get_glyph_path(state->font_face, state->font_size, x, y, codepoint, canvas->path); + return 0.f; +} + +float plutovg_canvas_add_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y) +{ + plutovg_state_t* state = canvas->state; + if(state->font_face == NULL || state->font_size <= 0.f) + return 0.f; + plutovg_text_iterator_t it; + plutovg_text_iterator_init(&it, text, length, encoding); + float advance_width = 0.f; + while(plutovg_text_iterator_has_next(&it)) { + plutovg_codepoint_t codepoint = plutovg_text_iterator_next(&it); + advance_width += plutovg_font_face_get_glyph_path(state->font_face, state->font_size, x + advance_width, y, codepoint, canvas->path); + } + + return advance_width; +} + +float plutovg_canvas_fill_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y) +{ + plutovg_canvas_new_path(canvas); + float advance_width = plutovg_canvas_add_text(canvas, text, length, encoding, x, y); + plutovg_canvas_fill(canvas); + return advance_width; +} + +float plutovg_canvas_stroke_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y) +{ + plutovg_canvas_new_path(canvas); + float advance_width = plutovg_canvas_add_text(canvas, text, length, encoding, x, y); + plutovg_canvas_stroke(canvas); + return advance_width; +} + +float plutovg_canvas_clip_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y) +{ + plutovg_canvas_new_path(canvas); + float advance_width = plutovg_canvas_add_text(canvas, text, length, encoding, x, y); + plutovg_canvas_clip(canvas); + return advance_width; +} + +void plutovg_canvas_font_metrics(const plutovg_canvas_t* canvas, float* ascent, float* descent, float* line_gap, plutovg_rect_t* extents) +{ + plutovg_state_t* state = canvas->state; + if(state->font_face && state->font_size > 0.f) { + plutovg_font_face_get_metrics(state->font_face, state->font_size, ascent, descent, line_gap, extents); + return; + } + + if(ascent) *ascent = 0.f; + if(descent) *descent = 0.f; + if(line_gap) *line_gap = 0.f; + if(extents) { + extents->x = 0.f; + extents->y = 0.f; + extents->w = 0.f; + extents->h = 0.f; + } +} + +void plutovg_canvas_glyph_metrics(plutovg_canvas_t* canvas, plutovg_codepoint_t codepoint, float* advance_width, float* left_side_bearing, plutovg_rect_t* extents) +{ + plutovg_state_t* state = canvas->state; + if(state->font_face && state->font_size > 0.f) { + plutovg_font_face_get_glyph_metrics(state->font_face, state->font_size, codepoint, advance_width, left_side_bearing, extents); + return; + } + + if(advance_width) *advance_width = 0.f; + if(left_side_bearing) *left_side_bearing = 0.f; + if(extents) { + extents->x = 0.f; + extents->y = 0.f; + extents->w = 0.f; + extents->h = 0.f; + } +} + +float plutovg_canvas_text_extents(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, plutovg_rect_t* extents) +{ + plutovg_state_t* state = canvas->state; + if(state->font_face && state->font_size > 0.f) { + return plutovg_font_face_text_extents(state->font_face, state->font_size, text, length, encoding, extents); + } + + if(extents) { + extents->x = 0.f; + extents->y = 0.f; + extents->w = 0.f; + extents->h = 0.f; + } + + return 0.f; +} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-dash.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-dash.c deleted file mode 100644 index 40a8027027..0000000000 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-dash.c +++ /dev/null @@ -1,114 +0,0 @@ -#include "plutovg-private.h" - -#include - -plutovg_dash_t* plutovg_dash_create(double offset, const double* data, int size) -{ - if(data==NULL || size==0) - return NULL; - - plutovg_dash_t* dash = malloc(sizeof(plutovg_dash_t)); - dash->offset = offset; - dash->data = malloc((size_t)size * sizeof(double)); - dash->size = size; - memcpy(dash->data, data, (size_t)size * sizeof(double)); - return dash; -} - -plutovg_dash_t* plutovg_dash_clone(const plutovg_dash_t* dash) -{ - if(dash==NULL) - return NULL; - - return plutovg_dash_create(dash->offset, dash->data, dash->size); -} - -void plutovg_dash_destroy(plutovg_dash_t* dash) -{ - if(dash==NULL) - return; - - free(dash->data); - free(dash); -} - -plutovg_path_t* plutovg_dash_path(const plutovg_dash_t* dash, const plutovg_path_t* path) -{ - if(dash->data==NULL || dash->size==0) - return plutovg_path_clone(path); - - int toggle = 1; - int offset = 0; - double phase = dash->offset; - while(phase >= dash->data[offset]) - { - toggle = !toggle; - phase -= dash->data[offset]; - offset += 1; - if(offset == dash->size) offset = 0; - } - - plutovg_path_t* flat = plutovg_path_clone_flat(path); - plutovg_path_t* result = plutovg_path_create(); - plutovg_array_ensure(result->elements, flat->elements.size); - plutovg_array_ensure(result->points, flat->points.size); - - plutovg_path_element_t* elements = flat->elements.data; - plutovg_path_element_t* end = elements + flat->elements.size; - plutovg_point_t* points = flat->points.data; - while(elements < end) - { - int itoggle = toggle; - int ioffset = offset; - double iphase = phase; - - double x0 = points->x; - double y0 = points->y; - - if(itoggle) - plutovg_path_move_to(result, x0, y0); - - ++elements; - ++points; - - while(elements < end && *elements==plutovg_path_element_line_to) - { - double dx = points->x - x0; - double dy = points->y - y0; - double dist0 = sqrt(dx*dx + dy*dy); - double dist1 = 0; - - while(dist0 - dist1 > dash->data[ioffset] - iphase) - { - dist1 += dash->data[ioffset] - iphase; - double a = dist1 / dist0; - double x = x0 + a * dx; - double y = y0 + a * dy; - - if(itoggle) - plutovg_path_line_to(result, x, y); - else - plutovg_path_move_to(result, x, y); - - itoggle = !itoggle; - iphase = 0; - ioffset += 1; - if(ioffset == dash->size) ioffset = 0; - } - - iphase += dist0 - dist1; - - x0 = points->x; - y0 = points->y; - - if(itoggle) - plutovg_path_line_to(result, x0, y0); - - ++elements; - ++points; - } - } - - plutovg_path_destroy(flat); - return result; -} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-font.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-font.c new file mode 100644 index 0000000000..2e67033cb4 --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-font.c @@ -0,0 +1,414 @@ +#include "plutovg.h" +#include "plutovg-utils.h" + +#include +#include + +#define STBTT_STATIC +#define STB_TRUETYPE_IMPLEMENTATION +#include "plutovg-stb-truetype.h" + +static int plutovg_text_iterator_length(const void* data, int length, plutovg_text_encoding_t encoding) +{ + if(length != -1) + return length; + length = 0; + switch(encoding) { + case PLUTOVG_TEXT_ENCODING_UTF8: + case PLUTOVG_TEXT_ENCODING_LATIN1: { + const uint8_t* text = data; + while(*text++) + length++; + break; + } case PLUTOVG_TEXT_ENCODING_UTF16: { + const uint16_t* text = data; + while(*text++) + length++; + break; + } case PLUTOVG_TEXT_ENCODING_UTF32: { + const uint32_t* text = data; + while(*text++) + length++; + break; + } default: + assert(false); + } + + return length; +} + +void plutovg_text_iterator_init(plutovg_text_iterator_t* it, const void* text, int length, plutovg_text_encoding_t encoding) +{ + it->text = text; + it->length = plutovg_text_iterator_length(text, length, encoding); + it->encoding = encoding; + it->index = 0; +} + +bool plutovg_text_iterator_has_next(const plutovg_text_iterator_t* it) +{ + return it->index < it->length; +} + +plutovg_codepoint_t plutovg_text_iterator_next(plutovg_text_iterator_t* it) +{ + plutovg_codepoint_t codepoint = 0; + switch(it->encoding) { + case PLUTOVG_TEXT_ENCODING_UTF8: { + static const uint8_t trailing[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 + }; + + static const uint32_t offsets[6] = { + 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080 + }; + + const uint8_t* text = it->text; + int trailing_bytes = trailing[text[it->index]]; + if(it->index + trailing_bytes >= it->length) + trailing_bytes = 0; + switch(trailing_bytes) { + case 5: codepoint += text[it->index++]; codepoint <<= 6; + case 4: codepoint += text[it->index++]; codepoint <<= 6; + case 3: codepoint += text[it->index++]; codepoint <<= 6; + case 2: codepoint += text[it->index++]; codepoint <<= 6; + case 1: codepoint += text[it->index++]; codepoint <<= 6; + case 0: codepoint += text[it->index++]; + } + + codepoint -= offsets[trailing_bytes]; + break; + } case PLUTOVG_TEXT_ENCODING_UTF16: { + const uint16_t* text = it->text; + codepoint = text[it->index++]; + if(((codepoint) & 0xfffffc00) == 0xd800) { + if(it->index < it->length && (((codepoint) & 0xfffffc00) == 0xdc00)) { + uint16_t trail = text[it->index++]; + codepoint = (codepoint << 10) + trail - ((0xD800u << 10) - 0x10000u + 0xDC00u); + } + } + + break; + } case PLUTOVG_TEXT_ENCODING_UTF32: { + const uint32_t* text = it->text; + codepoint = text[it->index++]; + break; + } case PLUTOVG_TEXT_ENCODING_LATIN1: { + const uint8_t* text = it->text; + codepoint = text[it->index++]; + break; + } default: + assert(false); + } + + return codepoint; +} + +typedef struct { + stbtt_vertex* vertices; + int nvertices; + int index; + int advance_width; + int left_side_bearing; + int x1; + int y1; + int x2; + int y2; +} glyph_t; + +#define GLYPH_CACHE_SIZE 256 +struct plutovg_font_face { + int ref_count; + int ascent; + int descent; + int line_gap; + int x1; + int y1; + int x2; + int y2; + stbtt_fontinfo info; + glyph_t** glyphs[GLYPH_CACHE_SIZE]; + plutovg_destroy_func_t destroy_func; + void* closure; +}; + +plutovg_font_face_t* plutovg_font_face_load_from_file(const char* filename, int ttcindex) +{ + FILE* fp = fopen(filename, "rb"); + if(fp == NULL) { + return NULL; + } + + fseek(fp, 0, SEEK_END); + long length = ftell(fp); + if(length == -1L) { + fclose(fp); + return NULL; + } + + void* data = malloc(length); + if(data == NULL) { + fclose(fp); + return NULL; + } + + fseek(fp, 0, SEEK_SET); + size_t nread = fread(data, 1, length, fp); + fclose(fp); + + if(nread != length) { + free(data); + return NULL; + } + + return plutovg_font_face_load_from_data(data, length, ttcindex, free, data); +} + +plutovg_font_face_t* plutovg_font_face_load_from_data(const void* data, unsigned int length, int ttcindex, plutovg_destroy_func_t destroy_func, void* closure) +{ + stbtt_fontinfo info; + int offset = stbtt_GetFontOffsetForIndex(data, ttcindex); + if(offset == -1 || !stbtt_InitFont(&info, data, offset)) { + if(destroy_func) + destroy_func(closure); + return NULL; + } + + plutovg_font_face_t* face = malloc(sizeof(plutovg_font_face_t)); + face->ref_count = 1; + face->info = info; + stbtt_GetFontVMetrics(&face->info, &face->ascent, &face->descent, &face->line_gap); + stbtt_GetFontBoundingBox(&face->info, &face->x1, &face->y1, &face->x2, &face->y2); + memset(face->glyphs, 0, sizeof(face->glyphs)); + face->destroy_func = destroy_func; + face->closure = closure; + return face; +} + +plutovg_font_face_t* plutovg_font_face_reference(plutovg_font_face_t* face) +{ + if(face == NULL) + return NULL; + ++face->ref_count; + return face; +} + +void plutovg_font_face_destroy(plutovg_font_face_t* face) +{ + if(face == NULL) + return; + if(--face->ref_count == 0) { + for(int i = 0; i < GLYPH_CACHE_SIZE; i++) { + if(face->glyphs[i] == NULL) + continue; + for(int j = 0; j < GLYPH_CACHE_SIZE; j++) { + glyph_t* glyph = face->glyphs[i][j]; + if(glyph == NULL) + continue; + stbtt_FreeShape(&face->info, glyph->vertices); + free(glyph); + } + + free(face->glyphs[i]); + } + + if(face->destroy_func) + face->destroy_func(face->closure); + free(face); + } +} + +int plutovg_font_face_get_reference_count(const plutovg_font_face_t* face) +{ + if(face) + return face->ref_count; + return 0; +} + +static float plutovg_font_face_get_scale(const plutovg_font_face_t* face, float size) +{ + return stbtt_ScaleForMappingEmToPixels(&face->info, size); +} + +void plutovg_font_face_get_metrics(const plutovg_font_face_t* face, float size, float* ascent, float* descent, float* line_gap, plutovg_rect_t* extents) +{ + float scale = plutovg_font_face_get_scale(face, size); + if(ascent) *ascent = face->ascent * scale; + if(descent) *descent = face->descent * scale; + if(line_gap) *line_gap = face->line_gap * scale; + if(extents) { + extents->x = face->x1 * scale; + extents->y = face->y2 * -scale; + extents->w = (face->x2 - face->x1) * scale; + extents->h = (face->y1 - face->y2) * -scale; + } +} + +static glyph_t* plutovg_font_face_get_glyph(plutovg_font_face_t* face, plutovg_codepoint_t codepoint) +{ + unsigned int msb = (codepoint >> 8) & 0xFF; + if(face->glyphs[msb] == NULL) { + face->glyphs[msb] = calloc(GLYPH_CACHE_SIZE, sizeof(glyph_t*)); + } + + unsigned int lsb = codepoint & 0xFF; + if(face->glyphs[msb][lsb] == NULL) { + glyph_t* glyph = malloc(sizeof(glyph_t)); + glyph->index = stbtt_FindGlyphIndex(&face->info, codepoint); + glyph->nvertices = stbtt_GetGlyphShape(&face->info, glyph->index, &glyph->vertices); + stbtt_GetGlyphHMetrics(&face->info, glyph->index, &glyph->advance_width, &glyph->left_side_bearing); + if(!stbtt_GetGlyphBox(&face->info, glyph->index, &glyph->x1, &glyph->y1, &glyph->x2, &glyph->y2)) + glyph->x1 = glyph->y1 = glyph->x2 = glyph->y2 = 0; + face->glyphs[msb][lsb] = glyph; + } + + return face->glyphs[msb][lsb]; +} + +void plutovg_font_face_get_glyph_metrics(plutovg_font_face_t* face, float size, plutovg_codepoint_t codepoint, float* advance_width, float* left_side_bearing, plutovg_rect_t* extents) +{ + float scale = plutovg_font_face_get_scale(face, size); + glyph_t* glyph = plutovg_font_face_get_glyph(face, codepoint); + if(advance_width) *advance_width = glyph->advance_width * scale; + if(left_side_bearing) *left_side_bearing = glyph->left_side_bearing * scale; + if(extents) { + extents->x = glyph->x1 * scale; + extents->y = glyph->y2 * -scale; + extents->w = (glyph->x2 - glyph->x1) * scale; + extents->h = (glyph->y1 - glyph->y2) * -scale; + } +} + +static void glyph_traverse_func(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints) +{ + plutovg_path_t* path = (plutovg_path_t*)(closure); + switch(command) { + case PLUTOVG_PATH_COMMAND_MOVE_TO: + plutovg_path_move_to(path, points[0].x, points[0].y); + break; + case PLUTOVG_PATH_COMMAND_LINE_TO: + plutovg_path_line_to(path, points[0].x, points[0].y); + break; + case PLUTOVG_PATH_COMMAND_CUBIC_TO: + plutovg_path_cubic_to(path, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); + break; + case PLUTOVG_PATH_COMMAND_CLOSE: + assert(false); + } +} + +float plutovg_font_face_get_glyph_path(plutovg_font_face_t* face, float size, float x, float y, plutovg_codepoint_t codepoint, plutovg_path_t* path) +{ + return plutovg_font_face_traverse_glyph_path(face, size, x, y, codepoint, glyph_traverse_func, path); +} + +float plutovg_font_face_traverse_glyph_path(plutovg_font_face_t* face, float size, float x, float y, plutovg_codepoint_t codepoint, plutovg_path_traverse_func_t traverse_func, void* closure) +{ + float scale = plutovg_font_face_get_scale(face, size); + plutovg_matrix_t matrix; + plutovg_matrix_init_translate(&matrix, x, y); + plutovg_matrix_scale(&matrix, scale, -scale); + + plutovg_point_t points[3]; + plutovg_point_t current_point = {0, 0}; + glyph_t* glyph = plutovg_font_face_get_glyph(face, codepoint); + for(int i = 0; i < glyph->nvertices; i++) { + switch(glyph->vertices[i].type) { + case STBTT_vmove: + points[0].x = glyph->vertices[i].x; + points[0].y = glyph->vertices[i].y; + current_point = points[0]; + plutovg_matrix_map_points(&matrix, points, points, 1); + traverse_func(closure, PLUTOVG_PATH_COMMAND_MOVE_TO, points, 1); + break; + case STBTT_vline: + points[0].x = glyph->vertices[i].x; + points[0].y = glyph->vertices[i].y; + current_point = points[0]; + plutovg_matrix_map_points(&matrix, points, points, 1); + traverse_func(closure, PLUTOVG_PATH_COMMAND_LINE_TO, points, 1); + break; + case STBTT_vcurve: + points[0].x = 2.f / 3.f * glyph->vertices[i].cx + 1.f / 3.f * current_point.x; + points[0].y = 2.f / 3.f * glyph->vertices[i].cy + 1.f / 3.f * current_point.y; + points[1].x = 2.f / 3.f * glyph->vertices[i].cx + 1.f / 3.f * glyph->vertices[i].x; + points[1].y = 2.f / 3.f * glyph->vertices[i].cy + 1.f / 3.f * glyph->vertices[i].y; + points[2].x = glyph->vertices[i].x; + points[2].y = glyph->vertices[i].y; + current_point = points[2]; + plutovg_matrix_map_points(&matrix, points, points, 3); + traverse_func(closure, PLUTOVG_PATH_COMMAND_CUBIC_TO, points, 3); + break; + case STBTT_vcubic: + points[0].x = glyph->vertices[i].cx; + points[0].y = glyph->vertices[i].cy; + points[1].x = glyph->vertices[i].cx1; + points[1].y = glyph->vertices[i].cy1; + points[2].x = glyph->vertices[i].x; + points[2].y = glyph->vertices[i].y; + current_point = points[2]; + plutovg_matrix_map_points(&matrix, points, points, 3); + traverse_func(closure, PLUTOVG_PATH_COMMAND_CUBIC_TO, points, 3); + break; + default: + assert(false); + } + } + + return glyph->advance_width * scale; +} + +float plutovg_font_face_text_extents(plutovg_font_face_t* face, float size, const void* text, int length, plutovg_text_encoding_t encoding, plutovg_rect_t* extents) +{ + plutovg_text_iterator_t it; + plutovg_text_iterator_init(&it, text, length, encoding); + plutovg_rect_t* text_extents = NULL; + float total_advance_width = 0.f; + while(plutovg_text_iterator_has_next(&it)) { + plutovg_codepoint_t codepoint = plutovg_text_iterator_next(&it); + + float advance_width; + if(extents == NULL) { + plutovg_font_face_get_glyph_metrics(face, size, codepoint, &advance_width, NULL, NULL); + total_advance_width += advance_width; + continue; + } + + plutovg_rect_t glyph_extents; + plutovg_font_face_get_glyph_metrics(face, size, codepoint, &advance_width, NULL, &glyph_extents); + + glyph_extents.x += total_advance_width; + total_advance_width += advance_width; + if(text_extents == NULL) { + text_extents = extents; + *text_extents = glyph_extents; + continue; + } + + float x1 = plutovg_min(text_extents->x, glyph_extents.x); + float y1 = plutovg_min(text_extents->y, glyph_extents.y); + float x2 = plutovg_max(text_extents->x + text_extents->w, glyph_extents.x + glyph_extents.w); + float y2 = plutovg_max(text_extents->y + text_extents->h, glyph_extents.y + glyph_extents.h); + + text_extents->x = x1; + text_extents->y = y1; + text_extents->w = x2 - x1; + text_extents->h = y2 - y1; + } + + if(extents && !text_extents) { + extents->x = 0; + extents->y = 0; + extents->w = 0; + extents->h = 0; + } + + return total_advance_width; +} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-math.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-math.c index 417242b239..5d6089075f 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-math.c +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-math.c @@ -9,7 +9,7 @@ /* */ /* This file is part of the FreeType project, and may only be used, */ /* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* license, FTL.TXT. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ @@ -19,29 +19,27 @@ #if defined(_MSC_VER) #include -static unsigned int __inline clz(unsigned int x) { +static inline int clz(unsigned int x) { unsigned long r = 0; - if (x != 0) - { - _BitScanReverse(&r, x); - } - return r; + if (_BitScanReverse(&r, x)) + return 31 - r; + return 32; } -#define PVG_FT_MSB(x) (clz(x)) +#define PVG_FT_MSB(x) (31 - clz(x)) #elif defined(__GNUC__) #define PVG_FT_MSB(x) (31 - __builtin_clz(x)) #else -static unsigned int __inline clz(unsigned int x) { - int c = 31; - x &= ~x + 1; - if (n & 0x0000FFFF) c -= 16; - if (n & 0x00FF00FF) c -= 8; - if (n & 0x0F0F0F0F) c -= 4; - if (n & 0x33333333) c -= 2; - if (n & 0x55555555) c -= 1; - return c; +static inline int clz(unsigned int x) { + int n = 0; + if (x == 0) return 32; + if (x <= 0x0000FFFFU) { n += 16; x <<= 16; } + if (x <= 0x00FFFFFFU) { n += 8; x <<= 8; } + if (x <= 0x0FFFFFFFU) { n += 4; x <<= 4; } + if (x <= 0x3FFFFFFFU) { n += 2; x <<= 2; } + if (x <= 0x7FFFFFFFU) { n += 1; } + return n; } -#define PVG_FT_MSB(x) (clz(x)) +#define PVG_FT_MSB(x) (31 - clz(x)) #endif #define PVG_FT_PAD_FLOOR(x, n) ((x) & ~((n)-1)) diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-math.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-math.h index 81c66b81b1..2d15c5b603 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-math.h +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-math.h @@ -9,7 +9,7 @@ /* */ /* This file is part of the FreeType project, and may only be used, */ /* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* license, FTL.TXT. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-raster.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-raster.c index 5642c5ef22..b31633ce29 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-raster.c +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-raster.c @@ -9,7 +9,7 @@ /* */ /* This file is part of the FreeType project, and may only be used, */ /* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* license, FTL.TXT. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ @@ -915,6 +915,7 @@ PVG_FT_END_STMNT { PVG_FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */ PVG_FT_Vector* arc = bez_stack; + PVG_FT_Vector* limit = bez_stack + 45; TPos dx, dy, dx_, dy_; TPos dx1, dy1, dx2, dy2; TPos L, s, s_limit; @@ -997,6 +998,8 @@ PVG_FT_END_STMNT continue; Split: + if( arc == limit ) + return; gray_split_cubic( arc ); arc += 3; } @@ -1161,6 +1164,77 @@ PVG_FT_END_STMNT } } +PVG_FT_Error PVG_FT_Outline_Check(PVG_FT_Outline* outline) +{ + if (outline) { + PVG_FT_Int n_points = outline->n_points; + PVG_FT_Int n_contours = outline->n_contours; + PVG_FT_Int end0, end; + PVG_FT_Int n; + + /* empty glyph? */ + if (n_points == 0 && n_contours == 0) return 0; + + /* check point and contour counts */ + if (n_points <= 0 || n_contours <= 0) goto Bad; + + end0 = end = -1; + for (n = 0; n < n_contours; n++) { + end = outline->contours[n]; + + /* note that we don't accept empty contours */ + if (end <= end0 || end >= n_points) goto Bad; + + end0 = end; + } + + if (end != n_points - 1) goto Bad; + + /* XXX: check the tags array */ + return 0; + } + +Bad: + return ErrRaster_Invalid_Outline; +} + +void PVG_FT_Outline_Get_CBox(const PVG_FT_Outline* outline, PVG_FT_BBox* acbox) +{ + PVG_FT_Pos xMin, yMin, xMax, yMax; + + if (outline && acbox) { + if (outline->n_points == 0) { + xMin = 0; + yMin = 0; + xMax = 0; + yMax = 0; + } else { + PVG_FT_Vector* vec = outline->points; + PVG_FT_Vector* limit = vec + outline->n_points; + + xMin = xMax = vec->x; + yMin = yMax = vec->y; + vec++; + + for (; vec < limit; vec++) { + PVG_FT_Pos x, y; + + x = vec->x; + if (x < xMin) xMin = x; + if (x > xMax) xMax = x; + + y = vec->y; + if (y < yMin) yMin = y; + if (y > yMax) yMax = y; + } + } + acbox->xMin = xMin; + acbox->xMax = xMax; + acbox->yMin = yMin; + acbox->yMax = yMax; + } +} + /*************************************************************************/ /* */ /* The following function should only compile in stand_alone mode, */ diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-raster.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-raster.h index 5f5d934c61..e83ccc6e73 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-raster.h +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-raster.h @@ -10,7 +10,7 @@ /* */ /* This file is part of the FreeType project, and may only be used, */ /* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* license, FTL.TXT. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-stroker.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-stroker.c index 2d2f446066..b20cfea849 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-stroker.c +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-stroker.c @@ -10,7 +10,7 @@ /* */ /* This file is part of the FreeType project, and may only be used, */ /* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* license, FTL.TXT. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ @@ -238,77 +238,6 @@ typedef struct PVG_FT_StrokeBorderRec_ { } PVG_FT_StrokeBorderRec, *PVG_FT_StrokeBorder; -PVG_FT_Error PVG_FT_Outline_Check(PVG_FT_Outline* outline) -{ - if (outline) { - PVG_FT_Int n_points = outline->n_points; - PVG_FT_Int n_contours = outline->n_contours; - PVG_FT_Int end0, end; - PVG_FT_Int n; - - /* empty glyph? */ - if (n_points == 0 && n_contours == 0) return 0; - - /* check point and contour counts */ - if (n_points <= 0 || n_contours <= 0) goto Bad; - - end0 = end = -1; - for (n = 0; n < n_contours; n++) { - end = outline->contours[n]; - - /* note that we don't accept empty contours */ - if (end <= end0 || end >= n_points) goto Bad; - - end0 = end; - } - - if (end != n_points - 1) goto Bad; - - /* XXX: check the tags array */ - return 0; - } - -Bad: - return -1; // PVG_FT_THROW( Invalid_Argument ); -} - -void PVG_FT_Outline_Get_CBox(const PVG_FT_Outline* outline, PVG_FT_BBox* acbox) -{ - PVG_FT_Pos xMin, yMin, xMax, yMax; - - if (outline && acbox) { - if (outline->n_points == 0) { - xMin = 0; - yMin = 0; - xMax = 0; - yMax = 0; - } else { - PVG_FT_Vector* vec = outline->points; - PVG_FT_Vector* limit = vec + outline->n_points; - - xMin = xMax = vec->x; - yMin = yMax = vec->y; - vec++; - - for (; vec < limit; vec++) { - PVG_FT_Pos x, y; - - x = vec->x; - if (x < xMin) xMin = x; - if (x > xMax) xMax = x; - - y = vec->y; - if (y < yMin) yMin = y; - if (y > yMax) yMax = y; - } - } - acbox->xMin = xMin; - acbox->xMax = xMax; - acbox->yMin = yMin; - acbox->yMax = yMax; - } -} - static PVG_FT_Error ft_stroke_border_grow(PVG_FT_StrokeBorder border, PVG_FT_UInt new_points) { @@ -402,8 +331,8 @@ static PVG_FT_Error ft_stroke_border_lineto(PVG_FT_StrokeBorder border, /* move last point */ border->points[border->num_points - 1] = *to; } else { - /* don't add zero-length lineto */ - if (border->num_points > 0 && + /* don't add zero-length lineto, but always add moveto */ + if (border->num_points > border->start && PVG_FT_IS_SMALL(border->points[border->num_points - 1].x - to->x) && PVG_FT_IS_SMALL(border->points[border->num_points - 1].y - to->y)) return error; @@ -629,12 +558,10 @@ static void ft_stroke_border_export(PVG_FT_StrokeBorder border, PVG_FT_Outline* outline) { /* copy point locations */ - if (outline->points != NULL && border->points != NULL) - memcpy(outline->points + outline->n_points, border->points, - border->num_points * sizeof(PVG_FT_Vector)); + memcpy(outline->points + outline->n_points, border->points, + border->num_points * sizeof(PVG_FT_Vector)); /* copy tags */ - if (outline->tags) { PVG_FT_UInt count = border->num_points; PVG_FT_Byte* read = border->tags; @@ -651,7 +578,6 @@ static void ft_stroke_border_export(PVG_FT_StrokeBorder border, } /* copy contours */ - if (outline->contours) { PVG_FT_UInt count = border->num_points; PVG_FT_Byte* tags = border->tags; diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-stroker.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-stroker.h index 09e1c50df9..530a6f2021 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-stroker.h +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-stroker.h @@ -9,7 +9,7 @@ /* */ /* This file is part of the FreeType project, and may only be used, */ /* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* license, FTL.TXT. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-types.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-types.h index 61b77787a0..06580d12ce 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-types.h +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-ft-types.h @@ -9,7 +9,7 @@ * * This file is part of the FreeType project, and may only be used, * modified, and distributed under the terms of the FreeType project - * license, LICENSE.TXT. By continuing to use, modify, or distribute + * license, FTL.TXT. By continuing to use, modify, or distribute * this file you indicate that you have read the license and * understand and accept it fully. * diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-geometry.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-geometry.c deleted file mode 100644 index 6bc7489825..0000000000 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-geometry.c +++ /dev/null @@ -1,581 +0,0 @@ -#include "plutovg-private.h" - -#include - -void plutovg_rect_init(plutovg_rect_t* rect, double x, double y, double w, double h) -{ - rect->x = x; - rect->y = y; - rect->w = w; - rect->h = h; -} - -void plutovg_rect_init_zero(plutovg_rect_t* rect) -{ - rect->x = 0.0; - rect->y = 0.0; - rect->w = 0.0; - rect->h = 0.0; -} - -void plutovg_matrix_init(plutovg_matrix_t* matrix, double m00, double m10, double m01, double m11, double m02, double m12) -{ - matrix->m00 = m00; matrix->m10 = m10; - matrix->m01 = m01; matrix->m11 = m11; - matrix->m02 = m02; matrix->m12 = m12; -} - -void plutovg_matrix_init_identity(plutovg_matrix_t* matrix) -{ - matrix->m00 = 1.0; matrix->m10 = 0.0; - matrix->m01 = 0.0; matrix->m11 = 1.0; - matrix->m02 = 0.0; matrix->m12 = 0.0; -} - -void plutovg_matrix_init_translate(plutovg_matrix_t* matrix, double x, double y) -{ - plutovg_matrix_init(matrix, 1.0, 0.0, 0.0, 1.0, x, y); -} - -void plutovg_matrix_init_scale(plutovg_matrix_t* matrix, double x, double y) -{ - plutovg_matrix_init(matrix, x, 0.0, 0.0, y, 0.0, 0.0); -} - -void plutovg_matrix_init_shear(plutovg_matrix_t* matrix, double x, double y) -{ - plutovg_matrix_init(matrix, 1.0, tan(y), tan(x), 1.0, 0.0, 0.0); -} - -void plutovg_matrix_init_rotate(plutovg_matrix_t* matrix, double radians, double x, double y) -{ - double c = cos(radians); - double s = sin(radians); - - double cx = x * (1 - c) + y * s; - double cy = y * (1 - c) - x * s; - - plutovg_matrix_init(matrix, c, s, -s, c, cx, cy); -} - -void plutovg_matrix_translate(plutovg_matrix_t* matrix, double x, double y) -{ - plutovg_matrix_t m; - plutovg_matrix_init_translate(&m, x, y); - plutovg_matrix_multiply(matrix, &m, matrix); -} - -void plutovg_matrix_scale(plutovg_matrix_t* matrix, double x, double y) -{ - plutovg_matrix_t m; - plutovg_matrix_init_scale(&m, x, y); - plutovg_matrix_multiply(matrix, &m, matrix); -} - -void plutovg_matrix_shear(plutovg_matrix_t* matrix, double x, double y) -{ - plutovg_matrix_t m; - plutovg_matrix_init_shear(&m, x, y); - plutovg_matrix_multiply(matrix, &m, matrix); -} - -void plutovg_matrix_rotate(plutovg_matrix_t* matrix, double radians, double x, double y) -{ - plutovg_matrix_t m; - plutovg_matrix_init_rotate(&m, radians, x, y); - plutovg_matrix_multiply(matrix, &m, matrix); -} - -void plutovg_matrix_multiply(plutovg_matrix_t* matrix, const plutovg_matrix_t* a, const plutovg_matrix_t* b) -{ - double m00 = a->m00 * b->m00 + a->m10 * b->m01; - double m10 = a->m00 * b->m10 + a->m10 * b->m11; - double m01 = a->m01 * b->m00 + a->m11 * b->m01; - double m11 = a->m01 * b->m10 + a->m11 * b->m11; - double m02 = a->m02 * b->m00 + a->m12 * b->m01 + b->m02; - double m12 = a->m02 * b->m10 + a->m12 * b->m11 + b->m12; - - plutovg_matrix_init(matrix, m00, m10, m01, m11, m02, m12); -} - -int plutovg_matrix_invert(plutovg_matrix_t* matrix) -{ - double det = (matrix->m00 * matrix->m11 - matrix->m10 * matrix->m01); - if(det == 0.0) - return 0; - - double inv_det = 1.0 / det; - double m00 = matrix->m00 * inv_det; - double m10 = matrix->m10 * inv_det; - double m01 = matrix->m01 * inv_det; - double m11 = matrix->m11 * inv_det; - double m02 = (matrix->m01 * matrix->m12 - matrix->m11 * matrix->m02) * inv_det; - double m12 = (matrix->m10 * matrix->m02 - matrix->m00 * matrix->m12) * inv_det; - - plutovg_matrix_init(matrix, m11, -m10, -m01, m00, m02, m12); - return 1; -} - -void plutovg_matrix_map(const plutovg_matrix_t* matrix, double x, double y, double* _x, double* _y) -{ - *_x = x * matrix->m00 + y * matrix->m01 + matrix->m02; - *_y = x * matrix->m10 + y * matrix->m11 + matrix->m12; -} - -void plutovg_matrix_map_point(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst) -{ - plutovg_matrix_map(matrix, src->x, src->y, &dst->x, &dst->y); -} - -void plutovg_matrix_map_rect(const plutovg_matrix_t* matrix, const plutovg_rect_t* src, plutovg_rect_t* dst) -{ - plutovg_point_t p[4]; - p[0].x = src->x; - p[0].y = src->y; - p[1].x = src->x + src->w; - p[1].y = src->y; - p[2].x = src->x + src->w; - p[2].y = src->y + src->h; - p[3].x = src->x; - p[3].y = src->y + src->h; - - plutovg_matrix_map_point(matrix, &p[0], &p[0]); - plutovg_matrix_map_point(matrix, &p[1], &p[1]); - plutovg_matrix_map_point(matrix, &p[2], &p[2]); - plutovg_matrix_map_point(matrix, &p[3], &p[3]); - - double l = p[0].x; - double t = p[0].y; - double r = p[0].x; - double b = p[0].y; - - for(int i = 0;i < 4;i++) - { - if(p[i].x < l) l = p[i].x; - if(p[i].x > r) r = p[i].x; - if(p[i].y < t) t = p[i].y; - if(p[i].y > b) b = p[i].y; - } - - dst->x = l; - dst->y = t; - dst->w = r - l; - dst->h = b - t; -} - -plutovg_path_t* plutovg_path_create(void) -{ - plutovg_path_t* path = malloc(sizeof(plutovg_path_t)); - path->ref = 1; - path->contours = 0; - path->start.x = 0.0; - path->start.y = 0.0; - plutovg_array_init(path->elements); - plutovg_array_init(path->points); - return path; -} - -plutovg_path_t* plutovg_path_reference(plutovg_path_t* path) -{ - ++path->ref; - return path; -} - -void plutovg_path_destroy(plutovg_path_t* path) -{ - if(path==NULL) - return; - - if(--path->ref==0) - { - free(path->elements.data); - free(path->points.data); - free(path); - } -} - -int plutovg_path_get_reference_count(const plutovg_path_t* path) -{ - return path->ref; -} - -void plutovg_path_move_to(plutovg_path_t* path, double x, double y) -{ - plutovg_array_ensure(path->elements, 1); - plutovg_array_ensure(path->points, 1); - - path->elements.data[path->elements.size] = plutovg_path_element_move_to; - plutovg_point_t* points = path->points.data + path->points.size; - points[0].x = x; - points[0].y = y; - - path->elements.size += 1; - path->points.size += 1; - path->contours += 1; - - path->start.x = x; - path->start.y = y; -} - -void plutovg_path_line_to(plutovg_path_t* path, double x, double y) -{ - plutovg_array_ensure(path->elements, 1); - plutovg_array_ensure(path->points, 1); - - path->elements.data[path->elements.size] = plutovg_path_element_line_to; - plutovg_point_t* points = path->points.data + path->points.size; - points[0].x = x; - points[0].y = y; - - path->elements.size += 1; - path->points.size += 1; -} - -void plutovg_path_quad_to(plutovg_path_t* path, double x1, double y1, double x2, double y2) -{ - double x, y; - plutovg_path_get_current_point(path, &x, &y); - - double cx = 2.0 / 3.0 * x1 + 1.0 / 3.0 * x; - double cy = 2.0 / 3.0 * y1 + 1.0 / 3.0 * y; - double cx1 = 2.0 / 3.0 * x1 + 1.0 / 3.0 * x2; - double cy1 = 2.0 / 3.0 * y1 + 1.0 / 3.0 * y2; - plutovg_path_cubic_to(path, cx, cy, cx1, cy1, x2, y2); -} - -void plutovg_path_cubic_to(plutovg_path_t* path, double x1, double y1, double x2, double y2, double x3, double y3) -{ - plutovg_array_ensure(path->elements, 1); - plutovg_array_ensure(path->points, 3); - - path->elements.data[path->elements.size] = plutovg_path_element_cubic_to; - plutovg_point_t* points = path->points.data + path->points.size; - points[0].x = x1; - points[0].y = y1; - points[1].x = x2; - points[1].y = y2; - points[2].x = x3; - points[2].y = y3; - - path->elements.size += 1; - path->points.size += 3; -} - -void plutovg_path_close(plutovg_path_t* path) -{ - if(path->elements.size == 0) - return; - - if(path->elements.data[path->elements.size - 1] == plutovg_path_element_close) - return; - - plutovg_array_ensure(path->elements, 1); - plutovg_array_ensure(path->points, 1); - - path->elements.data[path->elements.size] = plutovg_path_element_close; - plutovg_point_t* points = path->points.data + path->points.size; - points[0].x = path->start.x; - points[0].y = path->start.y; - - path->elements.size += 1; - path->points.size += 1; -} - -static inline void rel_to_abs(const plutovg_path_t* path, double* x, double* y) -{ - double _x, _y; - plutovg_path_get_current_point(path, &_x, &_y); - - *x += _x; - *y += _y; -} - -void plutovg_path_rel_move_to(plutovg_path_t* path, double x, double y) -{ - rel_to_abs(path, &x, &y); - plutovg_path_move_to(path, x, y); -} - -void plutovg_path_rel_line_to(plutovg_path_t* path, double x, double y) -{ - rel_to_abs(path, &x, &y); - plutovg_path_line_to(path, x, y); -} - -void plutovg_path_rel_quad_to(plutovg_path_t* path, double x1, double y1, double x2, double y2) -{ - rel_to_abs(path, &x1, &y1); - rel_to_abs(path, &x2, &y2); - plutovg_path_quad_to(path, x1, y1, x2, y2); -} - -void plutovg_path_rel_cubic_to(plutovg_path_t* path, double x1, double y1, double x2, double y2, double x3, double y3) -{ - rel_to_abs(path, &x1, &y1); - rel_to_abs(path, &x2, &y2); - rel_to_abs(path, &x3, &y3); - plutovg_path_cubic_to(path, x1, y1, x2, y2, x3, y3); -} - -void plutovg_path_add_rect(plutovg_path_t* path, double x, double y, double w, double h) -{ - plutovg_path_move_to(path, x, y); - plutovg_path_line_to(path, x + w, y); - plutovg_path_line_to(path, x + w, y + h); - plutovg_path_line_to(path, x, y + h); - plutovg_path_line_to(path, x, y); - plutovg_path_close(path); -} - -void plutovg_path_add_round_rect(plutovg_path_t* path, double x, double y, double w, double h, double rx, double ry) -{ - double right = x + w; - double bottom = y + h; - - double cpx = rx * plutovg_kappa; - double cpy = ry * plutovg_kappa; - - plutovg_path_move_to(path, x, y+ry); - plutovg_path_cubic_to(path, x, y+ry-cpy, x+rx-cpx, y, x+rx, y); - plutovg_path_line_to(path, right-rx, y); - plutovg_path_cubic_to(path, right-rx+cpx, y, right, y+ry-cpy, right, y+ry); - plutovg_path_line_to(path, right, bottom-ry); - plutovg_path_cubic_to(path, right, bottom-ry+cpy, right-rx+cpx, bottom, right-rx, bottom); - plutovg_path_line_to(path, x+rx, bottom); - plutovg_path_cubic_to(path, x+rx-cpx, bottom, x, bottom-ry+cpy, x, bottom-ry); - plutovg_path_line_to(path, x, y+ry); - plutovg_path_close(path); -} - -void plutovg_path_add_ellipse(plutovg_path_t* path, double cx, double cy, double rx, double ry) -{ - double left = cx - rx; - double top = cy - ry; - double right = cx + rx; - double bottom = cy + ry; - - double cpx = rx * plutovg_kappa; - double cpy = ry * plutovg_kappa; - - plutovg_path_move_to(path, cx, top); - plutovg_path_cubic_to(path, cx+cpx, top, right, cy-cpy, right, cy); - plutovg_path_cubic_to(path, right, cy+cpy, cx+cpx, bottom, cx, bottom); - plutovg_path_cubic_to(path, cx-cpx, bottom, left, cy+cpy, left, cy); - plutovg_path_cubic_to(path, left, cy-cpy, cx-cpx, top, cx, top); - plutovg_path_close(path); -} - -void plutovg_path_add_circle(plutovg_path_t* path, double cx, double cy, double r) -{ - plutovg_path_add_ellipse(path, cx, cy, r, r); -} - -void plutovg_path_add_path(plutovg_path_t* path, const plutovg_path_t* source, const plutovg_matrix_t* matrix) -{ - plutovg_array_ensure(path->elements, source->elements.size); - plutovg_array_ensure(path->points, source->points.size); - - plutovg_point_t* points = path->points.data + path->points.size; - const plutovg_point_t* data = source->points.data; - const plutovg_point_t* end = data + source->points.size; - while(data < end) - { - if(matrix) - plutovg_matrix_map_point(matrix, data, points); - else - memcpy(points, data, sizeof(plutovg_point_t)); - - points += 1; - data += 1; - } - - plutovg_path_element_t* elements = path->elements.data + path->elements.size; - memcpy(elements, source->elements.data, (size_t)source->elements.size * sizeof(plutovg_path_element_t)); - - path->elements.size += source->elements.size; - path->points.size += source->points.size; - path->contours += source->contours; - path->start = source->start; -} - -void plutovg_path_transform(plutovg_path_t* path, const plutovg_matrix_t* matrix) -{ - plutovg_point_t* points = path->points.data; - plutovg_point_t* end = points + path->points.size; - while(points < end) - { - plutovg_matrix_map_point(matrix, points, points); - points += 1; - } -} - -void plutovg_path_get_current_point(const plutovg_path_t* path, double* x, double* y) -{ - *x = 0.0; - *y = 0.0; - - if(path->points.size == 0) - return; - - *x = path->points.data[path->points.size - 1].x; - *y = path->points.data[path->points.size - 1].y; -} - -int plutovg_path_get_element_count(const plutovg_path_t* path) -{ - return path->elements.size; -} - -plutovg_path_element_t* plutovg_path_get_elements(const plutovg_path_t* path) -{ - return path->elements.data; -} - -int plutovg_path_get_point_count(const plutovg_path_t* path) -{ - return path->points.size; -} - -plutovg_point_t* plutovg_path_get_points(const plutovg_path_t* path) -{ - return path->points.data; -} - -void plutovg_path_clear(plutovg_path_t* path) -{ - path->elements.size = 0; - path->points.size = 0; - path->contours = 0; - path->start.x = 0.0; - path->start.y = 0.0; -} - -int plutovg_path_empty(const plutovg_path_t* path) -{ - return path->elements.size == 0; -} - -plutovg_path_t* plutovg_path_clone(const plutovg_path_t* path) -{ - plutovg_path_t* result = plutovg_path_create(); - plutovg_array_ensure(result->elements, path->elements.size); - plutovg_array_ensure(result->points, path->points.size); - - memcpy(result->elements.data, path->elements.data, (size_t)path->elements.size * sizeof(plutovg_path_element_t)); - memcpy(result->points.data, path->points.data, (size_t)path->points.size * sizeof(plutovg_point_t)); - - result->elements.size = path->elements.size; - result->points.size = path->points.size; - result->contours = path->contours; - result->start = path->start; - return result; -} - -typedef struct { - double x1; double y1; - double x2; double y2; - double x3; double y3; - double x4; double y4; -} bezier_t; - -static inline void split(const bezier_t* b, bezier_t* first, bezier_t* second) -{ - double c = (b->x2 + b->x3) * 0.5; - first->x2 = (b->x1 + b->x2) * 0.5; - second->x3 = (b->x3 + b->x4) * 0.5; - first->x1 = b->x1; - second->x4 = b->x4; - first->x3 = (first->x2 + c) * 0.5; - second->x2 = (second->x3 + c) * 0.5; - first->x4 = second->x1 = (first->x3 + second->x2) * 0.5; - - c = (b->y2 + b->y3) * 0.5; - first->y2 = (b->y1 + b->y2) * 0.5; - second->y3 = (b->y3 + b->y4) * 0.5; - first->y1 = b->y1; - second->y4 = b->y4; - first->y3 = (first->y2 + c) * 0.5; - second->y2 = (second->y3 + c) * 0.5; - first->y4 = second->y1 = (first->y3 + second->y2) * 0.5; -} - -static void flatten(plutovg_path_t* path, const plutovg_point_t* p0, const plutovg_point_t* p1, const plutovg_point_t* p2, const plutovg_point_t* p3) -{ - bezier_t beziers[32]; - beziers[0].x1 = p0->x; - beziers[0].y1 = p0->y; - beziers[0].x2 = p1->x; - beziers[0].y2 = p1->y; - beziers[0].x3 = p2->x; - beziers[0].y3 = p2->y; - beziers[0].x4 = p3->x; - beziers[0].y4 = p3->y; - - const double threshold = 0.25; - - bezier_t* b = beziers; - while(b >= beziers) - { - double y4y1 = b->y4 - b->y1; - double x4x1 = b->x4 - b->x1; - double l = fabs(x4x1) + fabs(y4y1); - double d; - if(l > 1.0) - { - d = fabs((x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2)) + fabs((x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3)); - } - else - { - d = fabs(b->x1 - b->x2) + fabs(b->y1 - b->y2) + fabs(b->x1 - b->x3) + fabs(b->y1 - b->y3); - l = 1.0; - } - - if(d < threshold*l || b == beziers + 31) - { - plutovg_path_line_to(path, b->x4, b->y4); - --b; - } - else - { - split(b, b+1, b); - ++b; - } - } -} - -plutovg_path_t* plutovg_path_clone_flat(const plutovg_path_t* path) -{ - plutovg_path_t* result = plutovg_path_create(); - plutovg_array_ensure(result->elements, path->elements.size); - plutovg_array_ensure(result->points, path->points.size); - plutovg_point_t* points = path->points.data; - - for(int i = 0;i < path->elements.size;i++) - { - switch(path->elements.data[i]) - { - case plutovg_path_element_move_to: - plutovg_path_move_to(result, points[0].x, points[0].y); - points += 1; - break; - case plutovg_path_element_line_to: - plutovg_path_line_to(result, points[0].x, points[0].y); - points += 1; - break; - case plutovg_path_element_close: - plutovg_path_line_to(result, points[0].x, points[0].y); - points += 1; - break; - case plutovg_path_element_cubic_to: - { - plutovg_point_t p0; - plutovg_path_get_current_point(result, &p0.x, &p0.y); - flatten(result, &p0, points, points + 1, points + 2); - points += 3; - break; - } - } - } - - return result; -} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-matrix.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-matrix.c new file mode 100644 index 0000000000..312a7009cb --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-matrix.c @@ -0,0 +1,231 @@ +#include "plutovg.h" +#include "plutovg-utils.h" + +void plutovg_matrix_init(plutovg_matrix_t* matrix, float a, float b, float c, float d, float e, float f) +{ + matrix->a = a; matrix->b = b; + matrix->c = c; matrix->d = d; + matrix->e = e; matrix->f = f; +} + +void plutovg_matrix_init_identity(plutovg_matrix_t* matrix) +{ + matrix->a = 1; matrix->b = 0; + matrix->c = 0; matrix->d = 1; + matrix->e = 0; matrix->f = 0; +} + +void plutovg_matrix_init_translate(plutovg_matrix_t* matrix, float tx, float ty) +{ + plutovg_matrix_init(matrix, 1, 0, 0, 1, tx, ty); +} + +void plutovg_matrix_init_scale(plutovg_matrix_t* matrix, float sx, float sy) +{ + plutovg_matrix_init(matrix, sx, 0, 0, sy, 0, 0); +} + +void plutovg_matrix_init_rotate(plutovg_matrix_t* matrix, float angle) +{ + float c = cosf(angle); + float s = sinf(angle); + plutovg_matrix_init(matrix, c, s, -s, c, 0, 0); +} + +void plutovg_matrix_init_shear(plutovg_matrix_t* matrix, float shx, float shy) +{ + plutovg_matrix_init(matrix, 1, tanf(shy), tanf(shx), 1, 0, 0); +} + +void plutovg_matrix_translate(plutovg_matrix_t* matrix, float tx, float ty) +{ + plutovg_matrix_t m; + plutovg_matrix_init_translate(&m, tx, ty); + plutovg_matrix_multiply(matrix, &m, matrix); +} + +void plutovg_matrix_scale(plutovg_matrix_t* matrix, float sx, float sy) +{ + plutovg_matrix_t m; + plutovg_matrix_init_scale(&m, sx, sy); + plutovg_matrix_multiply(matrix, &m, matrix); +} + +void plutovg_matrix_rotate(plutovg_matrix_t* matrix, float angle) +{ + plutovg_matrix_t m; + plutovg_matrix_init_rotate(&m, angle); + plutovg_matrix_multiply(matrix, &m, matrix); +} + +void plutovg_matrix_shear(plutovg_matrix_t* matrix, float shx, float shy) +{ + plutovg_matrix_t m; + plutovg_matrix_init_shear(&m, shx, shy); + plutovg_matrix_multiply(matrix, &m, matrix); +} + +void plutovg_matrix_multiply(plutovg_matrix_t* matrix, const plutovg_matrix_t* left, const plutovg_matrix_t* right) +{ + float a = left->a * right->a + left->b * right->c; + float b = left->a * right->b + left->b * right->d; + float c = left->c * right->a + left->d * right->c; + float d = left->c * right->b + left->d * right->d; + float e = left->e * right->a + left->f * right->c + right->e; + float f = left->e * right->b + left->f * right->d + right->f; + plutovg_matrix_init(matrix, a, b, c, d, e, f); +} + +bool plutovg_matrix_invert(const plutovg_matrix_t* matrix, plutovg_matrix_t* inverse) +{ + float det = (matrix->a * matrix->d - matrix->b * matrix->c); + if(det == 0.f) + return false; + if(inverse) { + float inv_det = 1.f / det; + float a = matrix->a * inv_det; + float b = matrix->b * inv_det; + float c = matrix->c * inv_det; + float d = matrix->d * inv_det; + float e = (matrix->c * matrix->f - matrix->d * matrix->e) * inv_det; + float f = (matrix->b * matrix->e - matrix->a * matrix->f) * inv_det; + plutovg_matrix_init(inverse, d, -b, -c, a, e, f); + } + + return true; +} + +void plutovg_matrix_map(const plutovg_matrix_t* matrix, float x, float y, float* xx, float* yy) +{ + *xx = x * matrix->a + y * matrix->c + matrix->e; + *yy = x * matrix->b + y * matrix->d + matrix->f; +} + +void plutovg_matrix_map_point(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst) +{ + plutovg_matrix_map(matrix, src->x, src->y, &dst->x, &dst->y); +} + +void plutovg_matrix_map_points(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst, int count) +{ + for(int i = 0; i < count; ++i) { + plutovg_matrix_map_point(matrix, &src[i], &dst[i]); + } +} + +void plutovg_matrix_map_rect(const plutovg_matrix_t* matrix, const plutovg_rect_t* src, plutovg_rect_t* dst) +{ + plutovg_point_t p[4]; + p[0].x = src->x; + p[0].y = src->y; + p[1].x = src->x + src->w; + p[1].y = src->y; + p[2].x = src->x + src->w; + p[2].y = src->y + src->h; + p[3].x = src->x; + p[3].y = src->y + src->h; + plutovg_matrix_map_points(matrix, p, p, 4); + + float l = p[0].x; + float t = p[0].y; + float r = p[0].x; + float b = p[0].y; + + for(int i = 1; i < 4; i++) { + if(p[i].x < l) l = p[i].x; + if(p[i].x > r) r = p[i].x; + if(p[i].y < t) t = p[i].y; + if(p[i].y > b) b = p[i].y; + } + + dst->x = l; + dst->y = t; + dst->w = r - l; + dst->h = b - t; +} + +static int parse_matrix_parameters(const char** begin, const char* end, float values[6], int required, int optional) +{ + if(!plutovg_skip_ws_and_delim(begin, end, '(')) + return 0; + int count = 0; + int max_count = required + optional; + bool has_trailing_comma = false; + for(; count < max_count; ++count) { + if(!plutovg_parse_number(begin, end, values + count)) + break; + plutovg_skip_ws_or_comma(begin, end, &has_trailing_comma); + } + + if(!has_trailing_comma && (count == required || count == max_count) + && plutovg_skip_delim(begin, end, ')')) { + return count; + } + + return 0; +} + +bool plutovg_matrix_parse(plutovg_matrix_t* matrix, const char* data, int length) +{ + float values[6]; + plutovg_matrix_init_identity(matrix); + if(length == -1) + length = strlen(data); + const char* it = data; + const char* end = it + length; + bool has_trailing_comma = false; + plutovg_skip_ws(&it, end); + while(it < end) { + if(plutovg_skip_string(&it, end, "matrix")) { + int count = parse_matrix_parameters(&it, end, values, 6, 0); + if(count == 0) + return false; + plutovg_matrix_t m = { values[0], values[1], values[2], values[3], values[4], values[5] }; + plutovg_matrix_multiply(matrix, &m, matrix); + } else if(plutovg_skip_string(&it, end, "translate")) { + int count = parse_matrix_parameters(&it, end, values, 1, 1); + if(count == 0) + return false; + if(count == 1) { + plutovg_matrix_translate(matrix, values[0], 0); + } else { + plutovg_matrix_translate(matrix, values[0], values[1]); + } + } else if(plutovg_skip_string(&it, end, "scale")) { + int count = parse_matrix_parameters(&it, end, values, 1, 1); + if(count == 0) + return false; + if(count == 1) { + plutovg_matrix_scale(matrix, values[0], values[0]); + } else { + plutovg_matrix_scale(matrix, values[0], values[1]); + } + } else if(plutovg_skip_string(&it, end, "rotate")) { + int count = parse_matrix_parameters(&it, end, values, 1, 2); + if(count == 0) + return false; + if(count == 3) + plutovg_matrix_translate(matrix, values[1], values[2]); + plutovg_matrix_rotate(matrix, PLUTOVG_DEG2RAD(values[0])); + if(count == 3) { + plutovg_matrix_translate(matrix, -values[1], -values[2]); + } + } else if(plutovg_skip_string(&it, end, "skewX")) { + int count = parse_matrix_parameters(&it, end, values, 1, 0); + if(count == 0) + return false; + plutovg_matrix_shear(matrix, PLUTOVG_DEG2RAD(values[0]), 0); + } else if(plutovg_skip_string(&it, end, "skewY")) { + int count = parse_matrix_parameters(&it, end, values, 1, 0); + if(count == 0) + return false; + plutovg_matrix_shear(matrix, 0, PLUTOVG_DEG2RAD(values[0])); + } else { + return false; + } + + plutovg_skip_ws_or_comma(&it, end, &has_trailing_comma); + } + + return !has_trailing_comma; +} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-paint.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-paint.c index 9b8acb4010..44fe3a967d 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-paint.c +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-paint.c @@ -1,265 +1,497 @@ #include "plutovg-private.h" +#include "plutovg-utils.h" -void plutovg_color_init_rgb(plutovg_color_t* color, double r, double g, double b) -{ - plutovg_color_init_rgba(color, r, g, b, 1.0); -} - -void plutovg_color_init_rgba(plutovg_color_t* color, double r, double g, double b, double a) -{ - color->r = plutovg_clamp(r, 0.0, 1.0); - color->g = plutovg_clamp(g, 0.0, 1.0); - color->b = plutovg_clamp(b, 0.0, 1.0); - color->a = plutovg_clamp(a, 0.0, 1.0); -} +#include -void plutovg_gradient_init_linear(plutovg_gradient_t* gradient, double x1, double y1, double x2, double y2) +void plutovg_color_init_rgb(plutovg_color_t* color, float r, float g, float b) { - gradient->type = plutovg_gradient_type_linear; - gradient->spread = plutovg_spread_method_pad; - gradient->opacity = 1.0; - plutovg_array_clear(gradient->stops); - plutovg_matrix_init_identity(&gradient->matrix); - plutovg_gradient_set_values_linear(gradient, x1, y1, x2, y2); + plutovg_color_init_rgba(color, r, g, b, 1.f); } -void plutovg_gradient_init_radial(plutovg_gradient_t* gradient, double cx, double cy, double cr, double fx, double fy, double fr) +void plutovg_color_init_rgba(plutovg_color_t* color, float r, float g, float b, float a) { - gradient->type = plutovg_gradient_type_radial; - gradient->spread = plutovg_spread_method_pad; - gradient->opacity = 1.0; - plutovg_array_clear(gradient->stops); - plutovg_matrix_init_identity(&gradient->matrix); - plutovg_gradient_set_values_radial(gradient, cx, cy, cr, fx, fy, fr); + color->r = plutovg_clamp(r, 0.f, 1.f); + color->g = plutovg_clamp(g, 0.f, 1.f); + color->b = plutovg_clamp(b, 0.f, 1.f); + color->a = plutovg_clamp(a, 0.f, 1.f); } -void plutovg_gradient_set_spread(plutovg_gradient_t* gradient, plutovg_spread_method_t spread) +void plutovg_color_init_rgb8(plutovg_color_t* color, int r, int g, int b) { - gradient->spread = spread; + plutovg_color_init_rgba8(color, r, g, b, 255); } -plutovg_spread_method_t plutovg_gradient_get_spread(const plutovg_gradient_t* gradient) +void plutovg_color_init_rgba8(plutovg_color_t* color, int r, int g, int b, int a) { - return gradient->spread; + plutovg_color_init_rgba(color, r / 255.f, g / 255.f, b / 255.f, a / 255.f); } -void plutovg_gradient_set_matrix(plutovg_gradient_t* gradient, const plutovg_matrix_t* matrix) +void plutovg_color_init_rgba32(plutovg_color_t* color, unsigned int value) { - gradient->matrix = *matrix; + uint8_t r = (value >> 24) & 0xFF; + uint8_t g = (value >> 16) & 0xFF; + uint8_t b = (value >> 8) & 0xFF; + uint8_t a = (value >> 0) & 0xFF; + plutovg_color_init_rgba8(color, r, g, b, a); } -void plutovg_gradient_get_matrix(const plutovg_gradient_t* gradient, plutovg_matrix_t *matrix) +void plutovg_color_init_argb32(plutovg_color_t* color, unsigned int value) { - *matrix = gradient->matrix; -} - -void plutovg_gradient_add_stop_rgb(plutovg_gradient_t* gradient, double offset, double r, double g, double b) -{ - plutovg_gradient_add_stop_rgba(gradient, offset, r, g, b, 1.0); -} - -void plutovg_gradient_add_stop_rgba(plutovg_gradient_t* gradient, double offset, double r, double g, double b, double a) -{ - if(offset < 0.0) offset = 0.0; - if(offset > 1.0) offset = 1.0; - - plutovg_array_ensure(gradient->stops, 1); - plutovg_gradient_stop_t* stops = gradient->stops.data; - int nstops = gradient->stops.size; - int i = 0; - for(; i < nstops; i++) { - if(offset < stops[i].offset) { - memmove(&stops[i+1], &stops[i], (size_t)(nstops - i) * sizeof(plutovg_gradient_stop_t)); - break; - } - } - - plutovg_gradient_stop_t* stop = &stops[i]; - stop->offset = offset; - plutovg_color_init_rgba(&stop->color, r, g, b, a); - gradient->stops.size += 1; + uint8_t a = (value >> 24) & 0xFF; + uint8_t r = (value >> 16) & 0xFF; + uint8_t g = (value >> 8) & 0xFF; + uint8_t b = (value >> 0) & 0xFF; + plutovg_color_init_rgba8(color, r, g, b, a); } -void plutovg_gradient_add_stop_color(plutovg_gradient_t* gradient, double offset, const plutovg_color_t* color) +void plutovg_color_init_hsl(plutovg_color_t* color, float h, float s, float l) { - plutovg_gradient_add_stop_rgba(gradient, offset, color->r, color->g, color->b, color->a); + plutovg_color_init_hsla(color, h, s, l, 1.f); } -void plutovg_gradient_add_stop(plutovg_gradient_t* gradient, const plutovg_gradient_stop_t* stop) +static inline float hsl_component(float h, float s, float l, float n) { - plutovg_gradient_add_stop_rgba(gradient, stop->offset, stop->color.r, stop->color.g, stop->color.b, stop->color.a); + const float k = fmodf(n + h / 30.f, 12.f); + const float a = s * plutovg_min(l, 1.f - l); + return l - a * plutovg_max(-1.f, plutovg_min(1.f, plutovg_min(k - 3.f, 9.f - k))); } -void plutovg_gradient_clear_stops(plutovg_gradient_t* gradient) +void plutovg_color_init_hsla(plutovg_color_t* color, float h, float s, float l, float a) { - gradient->stops.size = 0; -} + h = fmodf(h, 360.f); + if(h < 0.f) { h += 360.f; } -int plutovg_gradient_get_stop_count(const plutovg_gradient_t* gradient) -{ - return gradient->stops.size; + float r = hsl_component(h, s, l, 0); + float g = hsl_component(h, s, l, 8); + float b = hsl_component(h, s, l, 4); + plutovg_color_init_rgba(color, r, g, b, a); } -plutovg_gradient_stop_t* plutovg_gradient_get_stops(const plutovg_gradient_t* gradient) +unsigned int plutovg_color_to_rgba32(const plutovg_color_t* color) { - return gradient->stops.data; + uint32_t r = lroundf(color->r * 255); + uint32_t g = lroundf(color->g * 255); + uint32_t b = lroundf(color->b * 255); + uint32_t a = lroundf(color->a * 255); + return (r << 24) | (g << 16) | (b << 8) | (a); } -plutovg_gradient_type_t plutovg_gradient_get_type(const plutovg_gradient_t* gradient) +unsigned int plutovg_color_to_argb32(const plutovg_color_t* color) { - return gradient->type; + uint32_t a = lroundf(color->a * 255); + uint32_t r = lroundf(color->r * 255); + uint32_t g = lroundf(color->g * 255); + uint32_t b = lroundf(color->b * 255); + return (a << 24) | (r << 16) | (g << 8) | (b); } -void plutovg_gradient_get_values_linear(const plutovg_gradient_t* gradient, double* x1, double* y1, double* x2, double* y2) +static inline uint8_t hex_digit(uint8_t c) { - if(x1) *x1 = gradient->values[0]; - if(y1) *y1 = gradient->values[1]; - if(x2) *x2 = gradient->values[2]; - if(y2) *y2 = gradient->values[3]; + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'a' && c <= 'f') + return 10 + c - 'a'; + if(c >= 'A' && c <= 'F') + return 10 + c - 'A'; + return 0; } -void plutovg_gradient_get_values_radial(const plutovg_gradient_t* gradient, double* cx, double* cy, double* cr, double* fx, double* fy, double* fr) +static inline uint8_t hex_byte(uint8_t c1, uint8_t c2) { - if(cx) *cx = gradient->values[0]; - if(cy) *cy = gradient->values[1]; - if(cr) *cr = gradient->values[2]; - if(fx) *fx = gradient->values[3]; - if(fy) *fy = gradient->values[4]; - if(fr) *fr = gradient->values[5]; + uint8_t h1 = hex_digit(c1); + uint8_t h2 = hex_digit(c2); + return (h1 << 4) | h2; } -void plutovg_gradient_set_values_linear(plutovg_gradient_t* gradient, double x1, double y1, double x2, double y2) -{ - gradient->values[0] = x1; - gradient->values[1] = y1; - gradient->values[2] = x2; - gradient->values[3] = y2; -} +#define MAX_NAME 20 +typedef struct { + const char* name; + uint32_t value; +} color_entry_t; -void plutovg_gradient_set_values_radial(plutovg_gradient_t* gradient, double cx, double cy, double cr, double fx, double fy, double fr) +static int color_entry_compare(const void* a, const void* b) { - gradient->values[0] = cx; - gradient->values[1] = cy; - gradient->values[2] = cr; - gradient->values[3] = fx; - gradient->values[4] = fy; - gradient->values[5] = fr; + const char* name = a; + const color_entry_t* entry = b; + return strcmp(name, entry->name); } -void plutovg_gradient_set_opacity(plutovg_gradient_t* gradient, double opacity) +static bool parse_rgb_component(const char** begin, const char* end, float* component) { - gradient->opacity = plutovg_clamp(opacity, 0.0, 1.0); + float value = 0; + if(!plutovg_parse_number(begin, end, &value)) + return false; + if(plutovg_skip_delim(begin, end, '%')) + value *= 2.55f; + *component = plutovg_clamp(value, 0.f, 255.f) / 255.f; + return true; } -double plutovg_gradient_get_opacity(const plutovg_gradient_t* gradient) +static bool parse_alpha_component(const char** begin, const char* end, float* component) { - return gradient->opacity; + float value = 0; + if(!plutovg_parse_number(begin, end, &value)) + return false; + if(plutovg_skip_delim(begin, end, '%')) + value /= 100.f; + *component = plutovg_clamp(value, 0.f, 1.f); + return true; } -void plutovg_gradient_copy(plutovg_gradient_t* gradient, const plutovg_gradient_t* source) +int plutovg_color_parse(plutovg_color_t* color, const char* data, int length) { - gradient->type = source->type; - gradient->spread = source->spread; - gradient->matrix = source->matrix; - gradient->opacity = source->opacity; - plutovg_array_ensure(gradient->stops, source->stops.size); - memcpy(gradient->values, source->values, sizeof(source->values)); - memcpy(gradient->stops.data, source->stops.data, source->stops.size * sizeof(plutovg_gradient_stop_t)); -} - -void plutovg_gradient_destroy(plutovg_gradient_t* gradient) -{ - plutovg_array_destroy(gradient->stops); -} + if(length == -1) + length = strlen(data); + const char* it = data; + const char* end = it + length; + plutovg_skip_ws(&it, end); + if(plutovg_skip_delim(&it, end, '#')) { + int r, g, b, a = 255; + const char* begin = it; + while(it < end && isxdigit(*it)) + ++it; + int count = it - begin; + if(count == 3 || count == 4) { + r = hex_byte(begin[0], begin[0]); + g = hex_byte(begin[1], begin[1]); + b = hex_byte(begin[2], begin[2]); + if(count == 4) { + a = hex_byte(begin[3], begin[3]); + } + } else if(count == 6 || count == 8) { + r = hex_byte(begin[0], begin[1]); + g = hex_byte(begin[2], begin[3]); + b = hex_byte(begin[4], begin[5]); + if(count == 8) { + a = hex_byte(begin[6], begin[7]); + } + } else { + return 0; + } -void plutovg_texture_init(plutovg_texture_t* texture, plutovg_surface_t* surface, plutovg_texture_type_t type) -{ - surface = plutovg_surface_reference(surface); - plutovg_surface_destroy(texture->surface); - texture->type = type; - texture->surface = surface; - texture->opacity = 1.0; - plutovg_matrix_init_identity(&texture->matrix); -} + plutovg_color_init_rgba8(color, r, g, b, a); + } else { + int name_length = 0; + char name[MAX_NAME + 1]; + while(it < end && name_length < MAX_NAME && isalpha(*it)) + name[name_length++] = tolower(*it++); + name[name_length] = '\0'; + + if(strcmp(name, "transparent") == 0) { + plutovg_color_init_rgba(color, 0, 0, 0, 0); + } else if(strcmp(name, "rgb") == 0 || strcmp(name, "rgba") == 0) { + if(!plutovg_skip_ws_and_delim(&it, end, '(')) + return 0; + float r, g, b, a = 1.f; + if(!parse_rgb_component(&it, end, &r) + || !plutovg_skip_ws_and_comma(&it, end) + || !parse_rgb_component(&it, end, &g) + || !plutovg_skip_ws_and_comma(&it, end) + || !parse_rgb_component(&it, end, &b)) { + return 0; + } + + if(plutovg_skip_ws_and_comma(&it, end) + && !parse_alpha_component(&it, end, &a)) { + return 0; + } + + plutovg_skip_ws(&it, end); + if(!plutovg_skip_delim(&it, end, ')')) + return 0; + plutovg_color_init_rgba(color, r, g, b, a); + } else if(strcmp(name, "hsl") == 0 || strcmp(name, "hsla") == 0) { + if(!plutovg_skip_ws_and_delim(&it, end, '(')) + return 0; + float h, s, l, a = 1.f; + if(!plutovg_parse_number(&it, end, &h) + || !plutovg_skip_ws_and_comma(&it, end) + || !parse_alpha_component(&it, end, &s) + || !plutovg_skip_ws_and_comma(&it, end) + || !parse_alpha_component(&it, end, &l)) { + return 0; + } + + if(plutovg_skip_ws_and_comma(&it, end) + && !parse_alpha_component(&it, end, &a)) { + return 0; + } + + plutovg_skip_ws(&it, end); + if(!plutovg_skip_delim(&it, end, ')')) + return 0; + plutovg_color_init_hsla(color, h, s, l, a); + } else { + static const color_entry_t colormap[] = { + {"aliceblue", 0xF0F8FF}, + {"antiquewhite", 0xFAEBD7}, + {"aqua", 0x00FFFF}, + {"aquamarine", 0x7FFFD4}, + {"azure", 0xF0FFFF}, + {"beige", 0xF5F5DC}, + {"bisque", 0xFFE4C4}, + {"black", 0x000000}, + {"blanchedalmond", 0xFFEBCD}, + {"blue", 0x0000FF}, + {"blueviolet", 0x8A2BE2}, + {"brown", 0xA52A2A}, + {"burlywood", 0xDEB887}, + {"cadetblue", 0x5F9EA0}, + {"chartreuse", 0x7FFF00}, + {"chocolate", 0xD2691E}, + {"coral", 0xFF7F50}, + {"cornflowerblue", 0x6495ED}, + {"cornsilk", 0xFFF8DC}, + {"crimson", 0xDC143C}, + {"cyan", 0x00FFFF}, + {"darkblue", 0x00008B}, + {"darkcyan", 0x008B8B}, + {"darkgoldenrod", 0xB8860B}, + {"darkgray", 0xA9A9A9}, + {"darkgreen", 0x006400}, + {"darkgrey", 0xA9A9A9}, + {"darkkhaki", 0xBDB76B}, + {"darkmagenta", 0x8B008B}, + {"darkolivegreen", 0x556B2F}, + {"darkorange", 0xFF8C00}, + {"darkorchid", 0x9932CC}, + {"darkred", 0x8B0000}, + {"darksalmon", 0xE9967A}, + {"darkseagreen", 0x8FBC8F}, + {"darkslateblue", 0x483D8B}, + {"darkslategray", 0x2F4F4F}, + {"darkslategrey", 0x2F4F4F}, + {"darkturquoise", 0x00CED1}, + {"darkviolet", 0x9400D3}, + {"deeppink", 0xFF1493}, + {"deepskyblue", 0x00BFFF}, + {"dimgray", 0x696969}, + {"dimgrey", 0x696969}, + {"dodgerblue", 0x1E90FF}, + {"firebrick", 0xB22222}, + {"floralwhite", 0xFFFAF0}, + {"forestgreen", 0x228B22}, + {"fuchsia", 0xFF00FF}, + {"gainsboro", 0xDCDCDC}, + {"ghostwhite", 0xF8F8FF}, + {"gold", 0xFFD700}, + {"goldenrod", 0xDAA520}, + {"gray", 0x808080}, + {"green", 0x008000}, + {"greenyellow", 0xADFF2F}, + {"grey", 0x808080}, + {"honeydew", 0xF0FFF0}, + {"hotpink", 0xFF69B4}, + {"indianred", 0xCD5C5C}, + {"indigo", 0x4B0082}, + {"ivory", 0xFFFFF0}, + {"khaki", 0xF0E68C}, + {"lavender", 0xE6E6FA}, + {"lavenderblush", 0xFFF0F5}, + {"lawngreen", 0x7CFC00}, + {"lemonchiffon", 0xFFFACD}, + {"lightblue", 0xADD8E6}, + {"lightcoral", 0xF08080}, + {"lightcyan", 0xE0FFFF}, + {"lightgoldenrodyellow", 0xFAFAD2}, + {"lightgray", 0xD3D3D3}, + {"lightgreen", 0x90EE90}, + {"lightgrey", 0xD3D3D3}, + {"lightpink", 0xFFB6C1}, + {"lightsalmon", 0xFFA07A}, + {"lightseagreen", 0x20B2AA}, + {"lightskyblue", 0x87CEFA}, + {"lightslategray", 0x778899}, + {"lightslategrey", 0x778899}, + {"lightsteelblue", 0xB0C4DE}, + {"lightyellow", 0xFFFFE0}, + {"lime", 0x00FF00}, + {"limegreen", 0x32CD32}, + {"linen", 0xFAF0E6}, + {"magenta", 0xFF00FF}, + {"maroon", 0x800000}, + {"mediumaquamarine", 0x66CDAA}, + {"mediumblue", 0x0000CD}, + {"mediumorchid", 0xBA55D3}, + {"mediumpurple", 0x9370DB}, + {"mediumseagreen", 0x3CB371}, + {"mediumslateblue", 0x7B68EE}, + {"mediumspringgreen", 0x00FA9A}, + {"mediumturquoise", 0x48D1CC}, + {"mediumvioletred", 0xC71585}, + {"midnightblue", 0x191970}, + {"mintcream", 0xF5FFFA}, + {"mistyrose", 0xFFE4E1}, + {"moccasin", 0xFFE4B5}, + {"navajowhite", 0xFFDEAD}, + {"navy", 0x000080}, + {"oldlace", 0xFDF5E6}, + {"olive", 0x808000}, + {"olivedrab", 0x6B8E23}, + {"orange", 0xFFA500}, + {"orangered", 0xFF4500}, + {"orchid", 0xDA70D6}, + {"palegoldenrod", 0xEEE8AA}, + {"palegreen", 0x98FB98}, + {"paleturquoise", 0xAFEEEE}, + {"palevioletred", 0xDB7093}, + {"papayawhip", 0xFFEFD5}, + {"peachpuff", 0xFFDAB9}, + {"peru", 0xCD853F}, + {"pink", 0xFFC0CB}, + {"plum", 0xDDA0DD}, + {"powderblue", 0xB0E0E6}, + {"purple", 0x800080}, + {"rebeccapurple", 0x663399}, + {"red", 0xFF0000}, + {"rosybrown", 0xBC8F8F}, + {"royalblue", 0x4169E1}, + {"saddlebrown", 0x8B4513}, + {"salmon", 0xFA8072}, + {"sandybrown", 0xF4A460}, + {"seagreen", 0x2E8B57}, + {"seashell", 0xFFF5EE}, + {"sienna", 0xA0522D}, + {"silver", 0xC0C0C0}, + {"skyblue", 0x87CEEB}, + {"slateblue", 0x6A5ACD}, + {"slategray", 0x708090}, + {"slategrey", 0x708090}, + {"snow", 0xFFFAFA}, + {"springgreen", 0x00FF7F}, + {"steelblue", 0x4682B4}, + {"tan", 0xD2B48C}, + {"teal", 0x008080}, + {"thistle", 0xD8BFD8}, + {"tomato", 0xFF6347}, + {"turquoise", 0x40E0D0}, + {"violet", 0xEE82EE}, + {"wheat", 0xF5DEB3}, + {"white", 0xFFFFFF}, + {"whitesmoke", 0xF5F5F5}, + {"yellow", 0xFFFF00}, + {"yellowgreen", 0x9ACD32} + }; + + const color_entry_t* entry = bsearch(name, colormap, sizeof(colormap) / sizeof(color_entry_t), sizeof(color_entry_t), color_entry_compare); + if(entry == NULL) + return 0; + plutovg_color_init_argb32(color, 0xFF000000 | entry->value); + } + } -void plutovg_texture_set_type(plutovg_texture_t* texture, plutovg_texture_type_t type) -{ - texture->type = type; + plutovg_skip_ws(&it, end); + return it - data; } -plutovg_texture_type_t plutovg_texture_get_type(const plutovg_texture_t* texture) +static void* plutovg_paint_create(plutovg_paint_type_t type, size_t size) { - return texture->type; + plutovg_paint_t* paint = malloc(size); + paint->ref_count = 1; + paint->type = type; + return paint; } -void plutovg_texture_set_matrix(plutovg_texture_t* texture, const plutovg_matrix_t* matrix) +plutovg_paint_t* plutovg_paint_create_rgb(float r, float g, float b) { - texture->matrix = *matrix; + return plutovg_paint_create_rgba(r, g, b, 1.f); } -void plutovg_texture_get_matrix(const plutovg_texture_t* texture, plutovg_matrix_t* matrix) +plutovg_paint_t* plutovg_paint_create_rgba(float r, float g, float b, float a) { - *matrix = texture->matrix; + plutovg_solid_paint_t* solid = plutovg_paint_create(PLUTOVG_PAINT_TYPE_COLOR, sizeof(plutovg_solid_paint_t)); + solid->color.r = plutovg_clamp(r, 0.f, 1.f); + solid->color.g = plutovg_clamp(g, 0.f, 1.f); + solid->color.b = plutovg_clamp(b, 0.f, 1.f); + solid->color.a = plutovg_clamp(a, 0.f, 1.f); + return &solid->base; } -void plutovg_texture_set_surface(plutovg_texture_t* texture, plutovg_surface_t* surface) +plutovg_paint_t* plutovg_paint_create_color(const plutovg_color_t* color) { - surface = plutovg_surface_reference(surface); - plutovg_surface_destroy(texture->surface); - texture->surface = surface; + return plutovg_paint_create_rgba(color->r, color->g, color->b, color->a); } -plutovg_surface_t* plutovg_texture_get_surface(const plutovg_texture_t* texture) +static plutovg_gradient_paint_t* plutovg_gradient_create(plutovg_gradient_type_t type, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix) { - return texture->surface; -} + plutovg_gradient_paint_t* gradient = plutovg_paint_create(PLUTOVG_PAINT_TYPE_GRADIENT, sizeof(plutovg_gradient_paint_t) + nstops * sizeof(plutovg_gradient_stop_t)); + gradient->type = type; + gradient->spread = spread; + gradient->matrix = matrix ? *matrix : PLUTOVG_IDENTITY_MATRIX; + gradient->stops = (plutovg_gradient_stop_t*)(gradient + 1); + gradient->nstops = nstops; + + float prev_offset = 0.f; + for(int i = 0; i < nstops; ++i) { + const plutovg_gradient_stop_t* stop = stops + i; + gradient->stops[i].offset = plutovg_max(prev_offset, plutovg_clamp(stop->offset, 0.f, 1.f)); + gradient->stops[i].color.r = plutovg_clamp(stop->color.r, 0.f, 1.f); + gradient->stops[i].color.g = plutovg_clamp(stop->color.g, 0.f, 1.f); + gradient->stops[i].color.b = plutovg_clamp(stop->color.b, 0.f, 1.f); + gradient->stops[i].color.a = plutovg_clamp(stop->color.a, 0.f, 1.f); + prev_offset = gradient->stops[i].offset; + } -void plutovg_texture_set_opacity(plutovg_texture_t* texture, double opacity) -{ - texture->opacity = plutovg_clamp(opacity, 0.0, 1.0); + return gradient; } -double plutovg_texture_get_opacity(const plutovg_texture_t* texture) +plutovg_paint_t* plutovg_paint_create_linear_gradient(float x1, float y1, float x2, float y2, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix) { - return texture->opacity; + plutovg_gradient_paint_t* gradient = plutovg_gradient_create(PLUTOVG_GRADIENT_TYPE_LINEAR, spread, stops, nstops, matrix); + gradient->values[0] = x1; + gradient->values[1] = y1; + gradient->values[2] = x2; + gradient->values[3] = y2; + return &gradient->base; } -void plutovg_texture_copy(plutovg_texture_t* texture, const plutovg_texture_t* source) +plutovg_paint_t* plutovg_paint_create_radial_gradient(float cx, float cy, float cr, float fx, float fy, float fr, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix) { - plutovg_surface_t* surface = plutovg_surface_reference(source->surface); - plutovg_surface_destroy(texture->surface); - texture->type = source->type; - texture->surface = surface; - texture->opacity = source->opacity; - texture->matrix = source->matrix; + plutovg_gradient_paint_t* gradient = plutovg_gradient_create(PLUTOVG_GRADIENT_TYPE_RADIAL, spread, stops, nstops, matrix); + gradient->values[0] = cx; + gradient->values[1] = cy; + gradient->values[2] = cr; + gradient->values[3] = fx; + gradient->values[4] = fy; + gradient->values[5] = fr; + return &gradient->base; } -void plutovg_texture_destroy(plutovg_texture_t* texture) +plutovg_paint_t* plutovg_paint_create_texture(plutovg_surface_t* surface, plutovg_texture_type_t type, float opacity, const plutovg_matrix_t* matrix) { - plutovg_surface_destroy(texture->surface); + plutovg_texture_paint_t* texture = plutovg_paint_create(PLUTOVG_PAINT_TYPE_TEXTURE, sizeof(plutovg_texture_paint_t)); + texture->type = type; + texture->opacity = plutovg_clamp(opacity, 0.f, 1.f); + texture->matrix = matrix ? *matrix : PLUTOVG_IDENTITY_MATRIX; + texture->surface = plutovg_surface_reference(surface); + return &texture->base; } -void plutovg_paint_init(plutovg_paint_t* paint) +plutovg_paint_t* plutovg_paint_reference(plutovg_paint_t* paint) { - paint->type = plutovg_paint_type_color; - paint->texture.surface = NULL; - plutovg_array_init(paint->gradient.stops); - plutovg_color_init_rgb(&paint->color, 0, 0, 0); + if(paint == NULL) + return NULL; + ++paint->ref_count; + return paint; } void plutovg_paint_destroy(plutovg_paint_t* paint) { - plutovg_texture_destroy(&paint->texture); - plutovg_gradient_destroy(&paint->gradient); + if(paint == NULL) + return; + if(--paint->ref_count == 0) { + if(paint->type == PLUTOVG_PAINT_TYPE_TEXTURE) { + plutovg_texture_paint_t* texture = (plutovg_texture_paint_t*)(paint); + plutovg_surface_destroy(texture->surface); + } + + free(paint); + } } -void plutovg_paint_copy(plutovg_paint_t* paint, const plutovg_paint_t* source) +int plutovg_paint_get_reference_count(const plutovg_paint_t* paint) { - paint->type = source->type; - if(source->type == plutovg_paint_type_color) - paint->color = source->color; - else if(source->type == plutovg_paint_type_color) - plutovg_gradient_copy(&paint->gradient, &paint->gradient); - else - plutovg_texture_copy(&paint->texture, &paint->texture); + if(paint) + return paint->ref_count; + return 0; } diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-path.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-path.c new file mode 100644 index 0000000000..cfcc0d7faa --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-path.c @@ -0,0 +1,924 @@ +#include "plutovg-private.h" +#include "plutovg-utils.h" + +#include + +void plutovg_path_iterator_init(plutovg_path_iterator_t* it, const plutovg_path_t* path) +{ + it->elements = path->elements.data; + it->size = path->elements.size; + it->index = 0; +} + +bool plutovg_path_iterator_has_next(const plutovg_path_iterator_t* it) +{ + return it->index < it->size; +} + +plutovg_path_command_t plutovg_path_iterator_next(plutovg_path_iterator_t* it, plutovg_point_t points[3]) +{ + const plutovg_path_element_t* elements = it->elements + it->index; + switch(elements[0].header.command) { + case PLUTOVG_PATH_COMMAND_MOVE_TO: + case PLUTOVG_PATH_COMMAND_LINE_TO: + case PLUTOVG_PATH_COMMAND_CLOSE: + points[0] = elements[1].point; + break; + case PLUTOVG_PATH_COMMAND_CUBIC_TO: + points[0] = elements[1].point; + points[1] = elements[2].point; + points[2] = elements[3].point; + break; + } + + it->index += elements[0].header.length; + return elements[0].header.command; +} + +plutovg_path_t* plutovg_path_create(void) +{ + plutovg_path_t* path = malloc(sizeof(plutovg_path_t)); + path->ref_count = 1; + path->num_points = 0; + path->num_contours = 0; + path->num_curves = 0; + path->start_point = PLUTOVG_MAKE_POINT(0, 0); + plutovg_array_init(path->elements); + return path; +} + +plutovg_path_t* plutovg_path_reference(plutovg_path_t* path) +{ + if(path == NULL) + return NULL; + ++path->ref_count; + return path; +} + +void plutovg_path_destroy(plutovg_path_t* path) +{ + if(path == NULL) + return; + if(--path->ref_count == 0) { + plutovg_array_destroy(path->elements); + free(path); + } +} + +int plutovg_path_get_reference_count(const plutovg_path_t* path) +{ + if(path) + return path->ref_count; + return 0; +} + +int plutovg_path_get_elements(const plutovg_path_t* path, const plutovg_path_element_t** elements) +{ + if(elements) + *elements = path->elements.data; + return path->elements.size; +} + +static plutovg_path_element_t* plutovg_path_add_command(plutovg_path_t* path, plutovg_path_command_t command, int npoints) +{ + const int length = npoints + 1; + plutovg_array_ensure(path->elements, length); + plutovg_path_element_t* elements = path->elements.data + path->elements.size; + elements->header.command = command; + elements->header.length = length; + path->elements.size += length; + path->num_points += npoints; + return elements + 1; +} + +void plutovg_path_move_to(plutovg_path_t* path, float x, float y) +{ + plutovg_path_element_t* elements = plutovg_path_add_command(path, PLUTOVG_PATH_COMMAND_MOVE_TO, 1); + elements[0].point = PLUTOVG_MAKE_POINT(x, y); + path->start_point = PLUTOVG_MAKE_POINT(x, y); + path->num_contours += 1; +} + +void plutovg_path_line_to(plutovg_path_t* path, float x, float y) +{ + if(path->elements.size == 0) + plutovg_path_move_to(path, 0, 0); + plutovg_path_element_t* elements = plutovg_path_add_command(path, PLUTOVG_PATH_COMMAND_LINE_TO, 1); + elements[0].point = PLUTOVG_MAKE_POINT(x, y); +} + +void plutovg_path_quad_to(plutovg_path_t* path, float x1, float y1, float x2, float y2) +{ + float current_x, current_y; + plutovg_path_get_current_point(path, ¤t_x, ¤t_y); + float cp1x = 2.f / 3.f * x1 + 1.f / 3.f * current_x; + float cp1y = 2.f / 3.f * y1 + 1.f / 3.f * current_y; + float cp2x = 2.f / 3.f * x1 + 1.f / 3.f * x2; + float cp2y = 2.f / 3.f * y1 + 1.f / 3.f * y2; + plutovg_path_cubic_to(path, cp1x, cp1y, cp2x, cp2y, x2, y2); +} + +void plutovg_path_cubic_to(plutovg_path_t* path, float x1, float y1, float x2, float y2, float x3, float y3) +{ + if(path->elements.size == 0) + plutovg_path_move_to(path, 0, 0); + plutovg_path_element_t* elements = plutovg_path_add_command(path, PLUTOVG_PATH_COMMAND_CUBIC_TO, 3); + elements[0].point = PLUTOVG_MAKE_POINT(x1, y1); + elements[1].point = PLUTOVG_MAKE_POINT(x2, y2); + elements[2].point = PLUTOVG_MAKE_POINT(x3, y3); + path->num_curves += 1; +} + +void plutovg_path_arc_to(plutovg_path_t* path, float rx, float ry, float angle, bool large_arc_flag, bool sweep_flag, float x, float y) +{ + float current_x, current_y; + plutovg_path_get_current_point(path, ¤t_x, ¤t_y); + if(rx == 0.f || ry == 0.f || (current_x == x && current_y == y)) { + plutovg_path_line_to(path, x, y); + return; + } + + if(rx < 0.f) rx = -rx; + if(ry < 0.f) ry = -ry; + + float dx = (current_x - x) * 0.5f; + float dy = (current_y - y) * 0.5f; + + plutovg_matrix_t matrix; + plutovg_matrix_init_rotate(&matrix, -angle); + plutovg_matrix_map(&matrix, dx, dy, &dx, &dy); + + float rxrx = rx * rx; + float ryry = ry * ry; + float dxdx = dx * dx; + float dydy = dy * dy; + float radius = dxdx / rxrx + dydy / ryry; + if(radius > 1.f) { + rx *= sqrtf(radius); + ry *= sqrtf(radius); + } + + plutovg_matrix_init_scale(&matrix, 1.f / rx, 1.f / ry); + plutovg_matrix_rotate(&matrix, -angle); + + float x1, y1; + float x2, y2; + plutovg_matrix_map(&matrix, current_x, current_y, &x1, &y1); + plutovg_matrix_map(&matrix, x, y, &x2, &y2); + + float dx1 = x2 - x1; + float dy1 = y2 - y1; + float d = dx1 * dx1 + dy1 * dy1; + float scale_sq = 1.f / d - 0.25f; + if(scale_sq < 0.f) scale_sq = 0.f; + float scale = sqrtf(scale_sq); + if(sweep_flag == large_arc_flag) + scale = -scale; + dx1 *= scale; + dy1 *= scale; + + float cx1 = 0.5f * (x1 + x2) - dy1; + float cy1 = 0.5f * (y1 + y2) + dx1; + + float th1 = atan2f(y1 - cy1, x1 - cx1); + float th2 = atan2f(y2 - cy1, x2 - cx1); + float th_arc = th2 - th1; + if(th_arc < 0.f && sweep_flag) + th_arc += PLUTOVG_TWO_PI; + else if(th_arc > 0.f && !sweep_flag) + th_arc -= PLUTOVG_TWO_PI; + plutovg_matrix_init_rotate(&matrix, angle); + plutovg_matrix_scale(&matrix, rx, ry); + int segments = (int)(ceilf(fabsf(th_arc / (PLUTOVG_HALF_PI + 0.001f)))); + for(int i = 0; i < segments; i++) { + float th_start = th1 + i * th_arc / segments; + float th_end = th1 + (i + 1) * th_arc / segments; + float t = (8.f / 6.f) * tanf(0.25f * (th_end - th_start)); + + float x3 = cosf(th_end) + cx1; + float y3 = sinf(th_end) + cy1; + + float cp2x = x3 + t * sinf(th_end); + float cp2y = y3 - t * cosf(th_end); + + float cp1x = cosf(th_start) - t * sinf(th_start); + float cp1y = sinf(th_start) + t * cosf(th_start); + + cp1x += cx1; + cp1y += cy1; + + plutovg_matrix_map(&matrix, cp1x, cp1y, &cp1x, &cp1y); + plutovg_matrix_map(&matrix, cp2x, cp2y, &cp2x, &cp2y); + plutovg_matrix_map(&matrix, x3, y3, &x3, &y3); + + plutovg_path_cubic_to(path, cp1x, cp1y, cp2x, cp2y, x3, y3); + } +} + +void plutovg_path_close(plutovg_path_t* path) +{ + if(path->elements.size == 0) + return; + plutovg_path_element_t* elements = plutovg_path_add_command(path, PLUTOVG_PATH_COMMAND_CLOSE, 1); + elements[0].point = path->start_point; +} + +void plutovg_path_get_current_point(const plutovg_path_t* path, float* x, float* y) +{ + float xx = 0.f; + float yy = 0.f; + if(path->num_points > 0) { + xx = path->elements.data[path->elements.size - 1].point.x; + yy = path->elements.data[path->elements.size - 1].point.y; + } + + if(x) *x = xx; + if(y) *y = yy; +} + +void plutovg_path_reserve(plutovg_path_t* path, int count) +{ + plutovg_array_ensure(path->elements, count); +} + +void plutovg_path_reset(plutovg_path_t* path) +{ + plutovg_array_clear(path->elements); + path->start_point = PLUTOVG_MAKE_POINT(0, 0); + path->num_points = 0; + path->num_contours = 0; + path->num_curves = 0; +} + +void plutovg_path_add_rect(plutovg_path_t* path, float x, float y, float w, float h) +{ + plutovg_path_reserve(path, 6 * 2); + plutovg_path_move_to(path, x, y); + plutovg_path_line_to(path, x + w, y); + plutovg_path_line_to(path, x + w, y + h); + plutovg_path_line_to(path, x, y + h); + plutovg_path_line_to(path, x, y); + plutovg_path_close(path); +} + +void plutovg_path_add_round_rect(plutovg_path_t* path, float x, float y, float w, float h, float rx, float ry) +{ + rx = plutovg_min(rx, w * 0.5f); + ry = plutovg_min(ry, h * 0.5f); + if(rx == 0.f && ry == 0.f) { + plutovg_path_add_rect(path, x, y, w, h); + return; + } + + float right = x + w; + float bottom = y + h; + + float cpx = rx * PLUTOVG_KAPPA; + float cpy = ry * PLUTOVG_KAPPA; + + plutovg_path_reserve(path, 6 * 2 + 4 * 4); + plutovg_path_move_to(path, x, y+ry); + plutovg_path_cubic_to(path, x, y+ry-cpy, x+rx-cpx, y, x+rx, y); + plutovg_path_line_to(path, right-rx, y); + plutovg_path_cubic_to(path, right-rx+cpx, y, right, y+ry-cpy, right, y+ry); + plutovg_path_line_to(path, right, bottom-ry); + plutovg_path_cubic_to(path, right, bottom-ry+cpy, right-rx+cpx, bottom, right-rx, bottom); + plutovg_path_line_to(path, x+rx, bottom); + plutovg_path_cubic_to(path, x+rx-cpx, bottom, x, bottom-ry+cpy, x, bottom-ry); + plutovg_path_line_to(path, x, y+ry); + plutovg_path_close(path); +} + +void plutovg_path_add_ellipse(plutovg_path_t* path, float cx, float cy, float rx, float ry) +{ + float left = cx - rx; + float top = cy - ry; + float right = cx + rx; + float bottom = cy + ry; + + float cpx = rx * PLUTOVG_KAPPA; + float cpy = ry * PLUTOVG_KAPPA; + + plutovg_path_reserve(path, 2 * 2 + 4 * 4); + plutovg_path_move_to(path, cx, top); + plutovg_path_cubic_to(path, cx+cpx, top, right, cy-cpy, right, cy); + plutovg_path_cubic_to(path, right, cy+cpy, cx+cpx, bottom, cx, bottom); + plutovg_path_cubic_to(path, cx-cpx, bottom, left, cy+cpy, left, cy); + plutovg_path_cubic_to(path, left, cy-cpy, cx-cpx, top, cx, top); + plutovg_path_close(path); +} + +void plutovg_path_add_circle(plutovg_path_t* path, float cx, float cy, float r) +{ + plutovg_path_add_ellipse(path, cx, cy, r, r); +} + +void plutovg_path_add_arc(plutovg_path_t* path, float cx, float cy, float r, float a0, float a1, bool ccw) +{ + float da = a1 - a0; + if(fabsf(da) > PLUTOVG_TWO_PI) { + da = PLUTOVG_TWO_PI; + } else if(da != 0.f && ccw != (da < 0.f)) { + da += PLUTOVG_TWO_PI * (ccw ? -1 : 1); + } + + int seg_n = (int)(ceilf(fabsf(da) / PLUTOVG_HALF_PI)); + if(seg_n == 0) + return; + float a = a0; + float ax = cx + cosf(a) * r; + float ay = cy + sinf(a) * r; + + float seg_a = da / seg_n; + float d = (seg_a / PLUTOVG_HALF_PI) * PLUTOVG_KAPPA * r; + float dx = -sinf(a) * d; + float dy = cosf(a) * d; + + plutovg_path_reserve(path, 2 + 4 * seg_n); + if(path->elements.size == 0) { + plutovg_path_move_to(path, ax, ay); + } else { + plutovg_path_line_to(path, ax, ay); + } + + for(int i = 0; i < seg_n; i++) { + float cp1x = ax + dx; + float cp1y = ay + dy; + + a += seg_a; + ax = cx + cosf(a) * r; + ay = cy + sinf(a) * r; + + dx = -sinf(a) * d; + dy = cosf(a) * d; + + float cp2x = ax - dx; + float cp2y = ay - dy; + + plutovg_path_cubic_to(path, cp1x, cp1y, cp2x, cp2y, ax, ay); + } +} + +void plutovg_path_transform(plutovg_path_t* path, const plutovg_matrix_t* matrix) +{ + plutovg_path_element_t* elements = path->elements.data; + for(int i = 0; i < path->elements.size; i += elements[i].header.length) { + switch(elements[i].header.command) { + case PLUTOVG_PATH_COMMAND_MOVE_TO: + case PLUTOVG_PATH_COMMAND_LINE_TO: + case PLUTOVG_PATH_COMMAND_CLOSE: + plutovg_matrix_map_point(matrix, &elements[i + 1].point, &elements[i + 1].point); + break; + case PLUTOVG_PATH_COMMAND_CUBIC_TO: + plutovg_matrix_map_point(matrix, &elements[i + 1].point, &elements[i + 1].point); + plutovg_matrix_map_point(matrix, &elements[i + 2].point, &elements[i + 2].point); + plutovg_matrix_map_point(matrix, &elements[i + 3].point, &elements[i + 3].point); + break; + } + } +} + +void plutovg_path_add_path(plutovg_path_t* path, const plutovg_path_t* source, const plutovg_matrix_t* matrix) +{ + if(matrix == NULL) { + plutovg_array_append(path->elements, source->elements); + path->start_point = source->start_point; + path->num_points += source->num_points; + path->num_contours += source->num_contours; + path->num_curves += source->num_curves; + return; + } + + plutovg_path_iterator_t it; + plutovg_path_iterator_init(&it, source); + + plutovg_point_t points[3]; + plutovg_array_ensure(path->elements, source->elements.size); + while(plutovg_path_iterator_has_next(&it)) { + switch(plutovg_path_iterator_next(&it, points)) { + case PLUTOVG_PATH_COMMAND_MOVE_TO: + plutovg_matrix_map_points(matrix, points, points, 1); + plutovg_path_move_to(path, points[0].x, points[0].y); + break; + case PLUTOVG_PATH_COMMAND_LINE_TO: + plutovg_matrix_map_points(matrix, points, points, 1); + plutovg_path_line_to(path, points[0].x, points[0].y); + break; + case PLUTOVG_PATH_COMMAND_CUBIC_TO: + plutovg_matrix_map_points(matrix, points, points, 3); + plutovg_path_cubic_to(path, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); + break; + case PLUTOVG_PATH_COMMAND_CLOSE: + plutovg_path_close(path); + break; + } + } +} + +void plutovg_path_traverse(const plutovg_path_t* path, plutovg_path_traverse_func_t traverse_func, void* closure) +{ + plutovg_path_iterator_t it; + plutovg_path_iterator_init(&it, path); + + plutovg_point_t points[3]; + while(plutovg_path_iterator_has_next(&it)) { + switch(plutovg_path_iterator_next(&it, points)) { + case PLUTOVG_PATH_COMMAND_MOVE_TO: + traverse_func(closure, PLUTOVG_PATH_COMMAND_MOVE_TO, points, 1); + break; + case PLUTOVG_PATH_COMMAND_LINE_TO: + traverse_func(closure, PLUTOVG_PATH_COMMAND_LINE_TO, points, 1); + break; + case PLUTOVG_PATH_COMMAND_CUBIC_TO: + traverse_func(closure, PLUTOVG_PATH_COMMAND_CUBIC_TO, points, 3); + break; + case PLUTOVG_PATH_COMMAND_CLOSE: + traverse_func(closure, PLUTOVG_PATH_COMMAND_CLOSE, points, 1); + break; + } + } +} + +typedef struct { + float x1; float y1; + float x2; float y2; + float x3; float y3; + float x4; float y4; +} bezier_t; + +static inline void split_bezier(const bezier_t* b, bezier_t* first, bezier_t* second) +{ + float c = (b->x2 + b->x3) * 0.5f; + first->x2 = (b->x1 + b->x2) * 0.5f; + second->x3 = (b->x3 + b->x4) * 0.5f; + first->x1 = b->x1; + second->x4 = b->x4; + first->x3 = (first->x2 + c) * 0.5f; + second->x2 = (second->x3 + c) * 0.5f; + first->x4 = second->x1 = (first->x3 + second->x2) * 0.5f; + + c = (b->y2 + b->y3) * 0.5f; + first->y2 = (b->y1 + b->y2) * 0.5f; + second->y3 = (b->y3 + b->y4) * 0.5f; + first->y1 = b->y1; + second->y4 = b->y4; + first->y3 = (first->y2 + c) * 0.5f; + second->y2 = (second->y3 + c) * 0.5f; + first->y4 = second->y1 = (first->y3 + second->y2) * 0.5f; +} + +void plutovg_path_traverse_flatten(const plutovg_path_t* path, plutovg_path_traverse_func_t traverse_func, void* closure) +{ + if(path->num_curves == 0) { + plutovg_path_traverse(path, traverse_func, closure); + return; + } + + const float threshold = 0.25f; + + plutovg_path_iterator_t it; + plutovg_path_iterator_init(&it, path); + + bezier_t beziers[32]; + plutovg_point_t points[3]; + plutovg_point_t current_point = {0, 0}; + while(plutovg_path_iterator_has_next(&it)) { + plutovg_path_command_t command = plutovg_path_iterator_next(&it, points); + switch(command) { + case PLUTOVG_PATH_COMMAND_MOVE_TO: + case PLUTOVG_PATH_COMMAND_LINE_TO: + case PLUTOVG_PATH_COMMAND_CLOSE: + traverse_func(closure, command, points, 1); + current_point = points[0]; + break; + case PLUTOVG_PATH_COMMAND_CUBIC_TO: + beziers[0].x1 = current_point.x; + beziers[0].y1 = current_point.y; + beziers[0].x2 = points[0].x; + beziers[0].y2 = points[0].y; + beziers[0].x3 = points[1].x; + beziers[0].y3 = points[1].y; + beziers[0].x4 = points[2].x; + beziers[0].y4 = points[2].y; + bezier_t* b = beziers; + while(b >= beziers) { + float y4y1 = b->y4 - b->y1; + float x4x1 = b->x4 - b->x1; + float l = fabsf(x4x1) + fabsf(y4y1); + float d; + if(l > 1.f) { + d = fabsf((x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2)) + fabsf((x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3)); + } else { + d = fabsf(b->x1 - b->x2) + fabsf(b->y1 - b->y2) + fabsf(b->x1 - b->x3) + fabsf(b->y1 - b->y3); + l = 1.f; + } + + if(d < threshold*l || b == beziers + 31) { + plutovg_point_t p = { b->x4, b->y4 }; + traverse_func(closure, PLUTOVG_PATH_COMMAND_LINE_TO, &p, 1); + --b; + } else { + split_bezier(b, b + 1, b); + ++b; + } + } + + current_point = points[2]; + break; + } + } +} + +typedef struct { + const float* dashes; int ndashes; + float start_phase; float phase; + int start_index; int index; + bool start_toggle; bool toggle; + plutovg_point_t current_point; + plutovg_path_traverse_func_t traverse_func; + void* closure; +} dasher_t; + +static void dash_traverse_func(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints) +{ + dasher_t* dasher = (dasher_t*)(closure); + if(command == PLUTOVG_PATH_COMMAND_MOVE_TO) { + if(dasher->start_toggle) + dasher->traverse_func(dasher->closure, PLUTOVG_PATH_COMMAND_MOVE_TO, points, npoints); + dasher->current_point = points[0]; + dasher->phase = dasher->start_phase; + dasher->index = dasher->start_index; + dasher->toggle = dasher->start_toggle; + return; + } + + assert(command == PLUTOVG_PATH_COMMAND_LINE_TO || command == PLUTOVG_PATH_COMMAND_CLOSE); + plutovg_point_t p0 = dasher->current_point; + plutovg_point_t p1 = points[0]; + float dx = p1.x - p0.x; + float dy = p1.y - p0.y; + float dist0 = sqrtf(dx*dx + dy*dy); + float dist1 = 0.f; + while(dist0 - dist1 > dasher->dashes[dasher->index % dasher->ndashes] - dasher->phase) { + dist1 += dasher->dashes[dasher->index % dasher->ndashes] - dasher->phase; + float a = dist1 / dist0; + plutovg_point_t p = { p0.x + a * dx, p0.y + a * dy }; + if(dasher->toggle) { + dasher->traverse_func(dasher->closure, PLUTOVG_PATH_COMMAND_LINE_TO, &p, 1); + } else { + dasher->traverse_func(dasher->closure, PLUTOVG_PATH_COMMAND_MOVE_TO, &p, 1); + } + + dasher->phase = 0.f; + dasher->toggle = !dasher->toggle; + dasher->index++; + } + + if(dasher->toggle) { + dasher->traverse_func(dasher->closure, PLUTOVG_PATH_COMMAND_LINE_TO, &p1, 1); + } + + dasher->phase += dist0 - dist1; + dasher->current_point = p1; +} + +void plutovg_path_traverse_dashed(const plutovg_path_t* path, float offset, const float* dashes, int ndashes, plutovg_path_traverse_func_t traverse_func, void* closure) +{ + float dash_sum = 0.f; + for(int i = 0; i < ndashes; ++i) + dash_sum += dashes[i]; + if(ndashes % 2 == 1) + dash_sum *= 2.f; + if(dash_sum <= 0.f) { + plutovg_path_traverse(path, traverse_func, closure); + return; + } + + dasher_t dasher; + dasher.dashes = dashes; + dasher.ndashes = ndashes; + dasher.start_phase = fmodf(offset, dash_sum); + if(dasher.start_phase < 0.f) + dasher.start_phase += dash_sum; + dasher.start_index = 0; + dasher.start_toggle = true; + while(dasher.start_phase > 0.f && dasher.start_phase >= dasher.dashes[dasher.start_index % dasher.ndashes]) { + dasher.start_phase -= dashes[dasher.start_index % dasher.ndashes]; + dasher.start_toggle = !dasher.start_toggle; + dasher.start_index++; + } + + dasher.phase = dasher.start_phase; + dasher.index = dasher.start_index; + dasher.toggle = dasher.start_toggle; + dasher.current_point = PLUTOVG_MAKE_POINT(0, 0); + dasher.traverse_func = traverse_func; + dasher.closure = closure; + plutovg_path_traverse_flatten(path, dash_traverse_func, &dasher); +} + +plutovg_path_t* plutovg_path_clone(const plutovg_path_t* path) +{ + plutovg_path_t* clone = plutovg_path_create(); + plutovg_array_append(clone->elements, path->elements); + clone->start_point = path->start_point; + clone->num_points = path->num_points; + clone->num_contours = path->num_contours; + clone->num_curves = path->num_curves; + return clone; +} + +static void clone_traverse_func(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints) +{ + plutovg_path_t* path = (plutovg_path_t*)(closure); + switch(command) { + case PLUTOVG_PATH_COMMAND_MOVE_TO: + plutovg_path_move_to(path, points[0].x, points[0].y); + break; + case PLUTOVG_PATH_COMMAND_LINE_TO: + plutovg_path_line_to(path, points[0].x, points[0].y); + break; + case PLUTOVG_PATH_COMMAND_CUBIC_TO: + plutovg_path_cubic_to(path, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); + break; + case PLUTOVG_PATH_COMMAND_CLOSE: + plutovg_path_close(path); + break; + } +} + +plutovg_path_t* plutovg_path_clone_flatten(const plutovg_path_t* path) +{ + plutovg_path_t* clone = plutovg_path_create(); + plutovg_path_reserve(clone, path->elements.size + path->num_curves * 32); + plutovg_path_traverse_flatten(path, clone_traverse_func, clone); + return clone; +} + +plutovg_path_t* plutovg_path_clone_dashed(const plutovg_path_t* path, float offset, const float* dashes, int ndashes) +{ + plutovg_path_t* clone = plutovg_path_create(); + plutovg_path_reserve(clone, path->elements.size + path->num_curves * 32); + plutovg_path_traverse_dashed(path, offset, dashes, ndashes, clone_traverse_func, clone); + return clone; +} + +typedef struct { + plutovg_point_t current_point; + bool is_first_point; + float length; + float x1; + float y1; + float x2; + float y2; +} extents_calculator_t; + +static void extents_traverse_func(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints) +{ + extents_calculator_t* calculator = (extents_calculator_t*)(closure); + if(calculator->is_first_point) { + assert(command == PLUTOVG_PATH_COMMAND_MOVE_TO); + calculator->is_first_point = false; + calculator->current_point = points[0]; + calculator->x1 = points[0].x; + calculator->y1 = points[0].y; + calculator->x2 = points[0].x; + calculator->y2 = points[0].y; + calculator->length = 0; + return; + } + + for(int i = 0; i < npoints; ++i) { + calculator->x1 = plutovg_min(calculator->x1, points[i].x); + calculator->y1 = plutovg_min(calculator->y1, points[i].y); + calculator->x2 = plutovg_max(calculator->x2, points[i].x); + calculator->y2 = plutovg_max(calculator->y2, points[i].y); + if(command != PLUTOVG_PATH_COMMAND_MOVE_TO) + calculator->length += hypotf(points[i].x - calculator->current_point.x, points[i].y - calculator->current_point.y); + calculator->current_point = points[i]; + } +} + +float plutovg_path_extents(const plutovg_path_t* path, plutovg_rect_t* extents, bool tight) +{ + extents_calculator_t calculator = {{0, 0}, true, 0, 0, 0, 0, 0}; + if(tight) { + plutovg_path_traverse_flatten(path, extents_traverse_func, &calculator); + } else { + plutovg_path_traverse(path, extents_traverse_func, &calculator); + } + + if(extents) { + extents->x = calculator.x1; + extents->y = calculator.y1; + extents->w = calculator.x2 - calculator.x1; + extents->h = calculator.y2 - calculator.y1; + } + + return calculator.length; +} + +float plutovg_path_length(const plutovg_path_t* path) +{ + return plutovg_path_extents(path, NULL, true); +} + +static inline bool parse_arc_flag(const char** begin, const char* end, bool* flag) +{ + if(plutovg_skip_delim(begin, end, '0')) + *flag = 0; + else if(plutovg_skip_delim(begin, end, '1')) + *flag = 1; + else + return false; + plutovg_skip_ws_or_comma(begin, end, NULL); + return true; +} + +static inline bool parse_path_coordinates(const char** begin, const char* end, float values[6], int offset, int count) +{ + for(int i = 0; i < count; i++) { + if(!plutovg_parse_number(begin, end, values + offset + i)) + return false; + plutovg_skip_ws_or_comma(begin, end, NULL); + } + + return true; +} + +bool plutovg_path_parse(plutovg_path_t* path, const char* data, int length) +{ + if(length == -1) + length = strlen(data); + const char* it = data; + const char* end = it + length; + + float values[6]; + bool flags[2]; + + float start_x = 0; + float start_y = 0; + float current_x = 0; + float current_y = 0; + float last_control_x = 0; + float last_control_y = 0; + + char command = 0; + char last_command = 0; + plutovg_skip_ws(&it, end); + while(it < end) { + if(PLUTOVG_IS_ALPHA(*it)) { + command = *it++; + plutovg_skip_ws(&it, end); + } + + if(!last_command && !(command == 'M' || command == 'm')) + return false; + if(command == 'M' || command == 'm') { + if(!parse_path_coordinates(&it, end, values, 0, 2)) + return false; + if(command == 'm') { + values[0] += current_x; + values[1] += current_y; + } + + plutovg_path_move_to(path, values[0], values[1]); + current_x = start_x = values[0]; + current_y = start_y = values[1]; + command = command == 'm' ? 'l' : 'L'; + } else if(command == 'L' || command == 'l') { + if(!parse_path_coordinates(&it, end, values, 0, 2)) + return false; + if(command == 'l') { + values[0] += current_x; + values[1] += current_y; + } + + plutovg_path_line_to(path, values[0], values[1]); + current_x = values[0]; + current_y = values[1]; + } else if(command == 'H' || command == 'h') { + if(!parse_path_coordinates(&it, end, values, 0, 1)) + return false; + if(command == 'h') { + values[0] += current_x; + } + + plutovg_path_line_to(path, values[0], current_y); + current_x = values[0]; + } else if(command == 'V' || command == 'v') { + if(!parse_path_coordinates(&it, end, values, 1, 1)) + return false; + if(command == 'v') { + values[1] += current_y; + } + + plutovg_path_line_to(path, current_x, values[1]); + current_y = values[1]; + } else if(command == 'Q' || command == 'q') { + if(!parse_path_coordinates(&it, end, values, 0, 4)) + return false; + if(command == 'q') { + values[0] += current_x; + values[1] += current_y; + values[2] += current_x; + values[3] += current_y; + } + + plutovg_path_quad_to(path, values[0], values[1], values[2], values[3]); + last_control_x = values[0]; + last_control_y = values[1]; + current_x = values[2]; + current_y = values[3]; + } else if(command == 'C' || command == 'c') { + if(!parse_path_coordinates(&it, end, values, 0, 6)) + return false; + if(command == 'c') { + values[0] += current_x; + values[1] += current_y; + values[2] += current_x; + values[3] += current_y; + values[4] += current_x; + values[5] += current_y; + } + + plutovg_path_cubic_to(path, values[0], values[1], values[2], values[3], values[4], values[5]); + last_control_x = values[2]; + last_control_y = values[3]; + current_x = values[4]; + current_y = values[5]; + } else if(command == 'T' || command == 't') { + if(last_command != 'Q' && last_command != 'q' && last_command != 'T' && last_command != 't') { + values[0] = current_x; + values[1] = current_y; + } else { + values[0] = 2 * current_x - last_control_x; + values[1] = 2 * current_y - last_control_y; + } + + if(!parse_path_coordinates(&it, end, values, 2, 2)) + return false; + if(command == 't') { + values[2] += current_x; + values[3] += current_y; + } + + plutovg_path_quad_to(path, values[0], values[1], values[2], values[3]); + last_control_x = values[0]; + last_control_y = values[1]; + current_x = values[2]; + current_y = values[3]; + } else if(command == 'S' || command == 's') { + if(last_command != 'C' && last_command != 'c' && last_command != 'S' && last_command != 's') { + values[0] = current_x; + values[1] = current_y; + } else { + values[0] = 2 * current_x - last_control_x; + values[1] = 2 * current_y - last_control_y; + } + + if(!parse_path_coordinates(&it, end, values, 2, 4)) + return false; + if(command == 's') { + values[2] += current_x; + values[3] += current_y; + values[4] += current_x; + values[5] += current_y; + } + + plutovg_path_cubic_to(path, values[0], values[1], values[2], values[3], values[4], values[5]); + last_control_x = values[2]; + last_control_y = values[3]; + current_x = values[4]; + current_y = values[5]; + } else if(command == 'A' || command == 'a') { + if(!parse_path_coordinates(&it, end, values, 0, 3) + || !parse_arc_flag(&it, end, &flags[0]) + || !parse_arc_flag(&it, end, &flags[1]) + || !parse_path_coordinates(&it, end, values, 3, 2)) { + return false; + } + + if(command == 'a') { + values[3] += current_x; + values[4] += current_y; + } + + plutovg_path_arc_to(path, values[0], values[1], PLUTOVG_DEG2RAD(values[2]), flags[0], flags[1], values[3], values[4]); + current_x = values[3]; + current_y = values[4]; + } else if(command == 'Z' || command == 'z') { + if(last_command == 'Z' || last_command == 'z') + return false; + plutovg_path_close(path); + current_x = start_x; + current_y = start_y; + } else { + return false; + } + + last_command = command; + } + + return true; +} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-private.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-private.h index 58766f62a7..334e8b80d4 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-private.h +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-private.h @@ -1,74 +1,67 @@ #ifndef PLUTOVG_PRIVATE_H #define PLUTOVG_PRIVATE_H -#include -#include -#include -#include - #include "plutovg.h" struct plutovg_surface { - int ref; - unsigned char* data; - int owndata; + int ref_count; int width; int height; int stride; + unsigned char* data; }; struct plutovg_path { - int ref; - int contours; - plutovg_point_t start; + int ref_count; + int num_points; + int num_contours; + int num_curves; + plutovg_point_t start_point; struct { plutovg_path_element_t* data; int size; int capacity; } elements; - struct { - plutovg_point_t* data; - int size; - int capacity; - } points; }; -struct plutovg_gradient { - int ref; - plutovg_gradient_type_t type; - plutovg_spread_method_t spread; - plutovg_matrix_t matrix; - double values[6]; - double opacity; - struct { - plutovg_gradient_stop_t* data; - int size; - int capacity; - } stops; -}; +typedef enum { + PLUTOVG_PAINT_TYPE_COLOR, + PLUTOVG_PAINT_TYPE_GRADIENT, + PLUTOVG_PAINT_TYPE_TEXTURE +} plutovg_paint_type_t; -struct plutovg_texture { - int ref; - plutovg_texture_type_t type; - plutovg_surface_t* surface; - plutovg_matrix_t matrix; - double opacity; +struct plutovg_paint { + int ref_count; + plutovg_paint_type_t type; }; -typedef int plutovg_paint_type_t; +typedef struct { + plutovg_paint_t base; + plutovg_color_t color; +} plutovg_solid_paint_t; -enum { - plutovg_paint_type_color, - plutovg_paint_type_gradient, - plutovg_paint_type_texture -}; +typedef enum { + PLUTOVG_GRADIENT_TYPE_LINEAR, + PLUTOVG_GRADIENT_TYPE_RADIAL +} plutovg_gradient_type_t; typedef struct { - plutovg_paint_type_t type; - plutovg_color_t color; - plutovg_gradient_t gradient; - plutovg_texture_t texture; -} plutovg_paint_t; + plutovg_paint_t base; + plutovg_gradient_type_t type; + plutovg_spread_method_t spread; + plutovg_matrix_t matrix; + plutovg_gradient_stop_t* stops; + int nstops; + float values[6]; +} plutovg_gradient_paint_t; + +typedef struct { + plutovg_paint_t base; + plutovg_texture_type_t type; + float opacity; + plutovg_matrix_t matrix; + plutovg_surface_t* surface; +} plutovg_texture_paint_t; typedef struct { int x; @@ -88,112 +81,65 @@ typedef struct { int y; int w; int h; -} plutovg_rle_t; +} plutovg_span_buffer_t; typedef struct { - double offset; - double* data; - int size; -} plutovg_dash_t; + float offset; + struct { + float* data; + int size; + int capacity; + } array; +} plutovg_stroke_dash_t; typedef struct { - double width; - double miterlimit; + float width; plutovg_line_cap_t cap; plutovg_line_join_t join; - plutovg_dash_t* dash; + float miter_limit; +} plutovg_stroke_style_t; + +typedef struct { + plutovg_stroke_style_t style; + plutovg_stroke_dash_t dash; } plutovg_stroke_data_t; typedef struct plutovg_state { - plutovg_rle_t* clippath; - plutovg_paint_t paint; + plutovg_paint_t* paint; + plutovg_font_face_t* font_face; + plutovg_color_t color; plutovg_matrix_t matrix; - plutovg_fill_rule_t winding; plutovg_stroke_data_t stroke; + plutovg_span_buffer_t clip_spans; + plutovg_fill_rule_t winding; plutovg_operator_t op; - double opacity; + float font_size; + float opacity; + bool clipping; struct plutovg_state* next; } plutovg_state_t; -struct plutovg { - int ref; +struct plutovg_canvas { + int ref_count; plutovg_surface_t* surface; - plutovg_state_t* state; plutovg_path_t* path; - plutovg_rle_t* rle; - plutovg_rle_t* clippath; - plutovg_rect_t clip; - void* outline_data; - size_t outline_size; + plutovg_state_t* state; + plutovg_state_t* freed_state; + plutovg_rect_t clip_rect; + plutovg_span_buffer_t clip_spans; + plutovg_span_buffer_t fill_spans; }; -void plutovg_paint_init(plutovg_paint_t* paint); -void plutovg_paint_destroy(plutovg_paint_t* paint); -void plutovg_paint_copy(plutovg_paint_t* paint, const plutovg_paint_t* source); - -void plutovg_gradient_copy(plutovg_gradient_t* gradient, const plutovg_gradient_t* source); -void plutovg_gradient_destroy(plutovg_gradient_t* gradient); - -void plutovg_texture_copy(plutovg_texture_t* texture, const plutovg_texture_t* source); -void plutovg_texture_destroy(plutovg_texture_t* texture); - -plutovg_rle_t* plutovg_rle_create(void); -void plutovg_rle_destroy(plutovg_rle_t* rle); -void plutovg_rle_rasterize(plutovg_t* pluto, plutovg_rle_t* rle, const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_rect_t* clip, const plutovg_stroke_data_t* stroke, plutovg_fill_rule_t winding); -plutovg_rle_t* plutovg_rle_intersection(const plutovg_rle_t* a, const plutovg_rle_t* b); -void plutovg_rle_clip_path(plutovg_rle_t* rle, const plutovg_rle_t* clip); -plutovg_rle_t* plutovg_rle_clone(const plutovg_rle_t* rle); -void plutovg_rle_clear(plutovg_rle_t* rle); - -plutovg_dash_t* plutovg_dash_create(double offset, const double* data, int size); -plutovg_dash_t* plutovg_dash_clone(const plutovg_dash_t* dash); -void plutovg_dash_destroy(plutovg_dash_t* dash); -plutovg_path_t* plutovg_dash_path(const plutovg_dash_t* dash, const plutovg_path_t* path); - -plutovg_state_t* plutovg_state_create(void); -plutovg_state_t* plutovg_state_clone(const plutovg_state_t* state); -void plutovg_state_destroy(plutovg_state_t* state); - -void plutovg_blend(plutovg_t* pluto, const plutovg_rle_t* rle); -void plutovg_blend_color(plutovg_t* pluto, const plutovg_rle_t* rle, const plutovg_color_t* color); -void plutovg_blend_gradient(plutovg_t* pluto, const plutovg_rle_t* rle, const plutovg_gradient_t* gradient); -void plutovg_blend_texture(plutovg_t* pluto, const plutovg_rle_t* rle, const plutovg_texture_t* texture); - -#define plutovg_sqrt2 1.41421356237309504880 -#define plutovg_pi 3.14159265358979323846 -#define plutovg_two_pi 6.28318530717958647693 -#define plutovg_half_pi 1.57079632679489661923 -#define plutovg_kappa 0.55228474983079339840 - -#define plutovg_min(a, b) ((a) < (b) ? (a) : (b)) -#define plutovg_max(a, b) ((a) > (b) ? (a) : (b)) -#define plutovg_clamp(v, lo, hi) ((v) < (lo) ? (lo) : (hi) < (v) ? (hi) : (v)) -#define plutovg_div255(x) (((x) + ((x) >> 8) + 0x80) >> 8) - -#define plutovg_alpha(c) ((c) >> 24) -#define plutovg_red(c) (((c) >> 16) & 0xff) -#define plutovg_green(c) (((c) >> 8) & 0xff) -#define plutovg_blue(c) (((c) >> 0) & 0xff) - -#define plutovg_array_init(array) \ -do { \ - array.data = NULL; \ - array.size = 0; \ - array.capacity = 0; \ -} while(0) - -#define plutovg_array_ensure(array, count) \ - do { \ - if(array.size + count > array.capacity) { \ - int capacity = array.size + count; \ - int newcapacity = array.capacity == 0 ? 8 : array.capacity; \ - while(newcapacity < capacity) { newcapacity *= 2; } \ - array.data = realloc(array.data, newcapacity * sizeof(array.data[0])); \ - array.capacity = newcapacity; \ - } \ -} while(0) - -#define plutovg_array_clear(array) (array.size = 0) -#define plutovg_array_destroy(array) free(array.data) +void plutovg_span_buffer_init(plutovg_span_buffer_t* span_buffer); +void plutovg_span_buffer_init_rect(plutovg_span_buffer_t* span_buffer, int x, int y, int width, int height); +void plutovg_span_buffer_reset(plutovg_span_buffer_t* span_buffer); +void plutovg_span_buffer_destroy(plutovg_span_buffer_t* span_buffer); +void plutovg_span_buffer_copy(plutovg_span_buffer_t* span_buffer, const plutovg_span_buffer_t* source); +void plutovg_span_buffer_extents(plutovg_span_buffer_t* span_buffer, plutovg_rect_t* extents); +void plutovg_span_buffer_intersect(plutovg_span_buffer_t* span_buffer, const plutovg_span_buffer_t* a, const plutovg_span_buffer_t* b); + +void plutovg_rasterize(plutovg_span_buffer_t* span_buffer, const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_rect_t* clip_rect, const plutovg_stroke_data_t* stroke_data, plutovg_fill_rule_t winding); +void plutovg_blend(plutovg_canvas_t* canvas, const plutovg_span_buffer_t* span_buffer); +void plutovg_memfill32(unsigned int* dest, int length, unsigned int value); #endif // PLUTOVG_PRIVATE_H diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-rasterize.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-rasterize.c new file mode 100644 index 0000000000..2b6ea80553 --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-rasterize.c @@ -0,0 +1,377 @@ +#include "plutovg-private.h" +#include "plutovg-utils.h" + +#include "plutovg-ft-raster.h" +#include "plutovg-ft-stroker.h" + +#include + +void plutovg_span_buffer_init(plutovg_span_buffer_t* span_buffer) +{ + plutovg_array_init(span_buffer->spans); + plutovg_span_buffer_reset(span_buffer); +} + +void plutovg_span_buffer_init_rect(plutovg_span_buffer_t* span_buffer, int x, int y, int width, int height) +{ + plutovg_array_clear(span_buffer->spans); + plutovg_array_ensure(span_buffer->spans, height); + plutovg_span_t* spans = span_buffer->spans.data; + for(int i = 0; i < height; i++) { + spans[i].x = x; + spans[i].y = y + i; + spans[i].len = width; + spans[i].coverage = 255; + } + + span_buffer->x = x; + span_buffer->y = y; + span_buffer->w = width; + span_buffer->h = height; + span_buffer->spans.size = height; +} + +void plutovg_span_buffer_reset(plutovg_span_buffer_t* span_buffer) +{ + plutovg_array_clear(span_buffer->spans); + span_buffer->x = 0; + span_buffer->y = 0; + span_buffer->w = -1; + span_buffer->h = -1; +} + +void plutovg_span_buffer_destroy(plutovg_span_buffer_t* span_buffer) +{ + plutovg_array_destroy(span_buffer->spans); +} + +void plutovg_span_buffer_copy(plutovg_span_buffer_t* span_buffer, const plutovg_span_buffer_t* source) +{ + plutovg_array_clear(span_buffer->spans); + plutovg_array_append(span_buffer->spans, source->spans); + span_buffer->x = source->x; + span_buffer->y = source->y; + span_buffer->w = source->w; + span_buffer->h = source->h; +} + +static void plutovg_span_buffer_update_extents(plutovg_span_buffer_t* span_buffer) +{ + if(span_buffer->w != -1 && span_buffer->h != -1) + return; + if(span_buffer->spans.size == 0) { + span_buffer->x = 0; + span_buffer->y = 0; + span_buffer->w = 0; + span_buffer->h = 0; + return; + } + + plutovg_span_t* spans = span_buffer->spans.data; + int x1 = INT_MAX; + int y1 = spans[0].y; + int x2 = 0; + int y2 = spans[span_buffer->spans.size - 1].y; + for(int i = 0; i < span_buffer->spans.size; i++) { + if(spans[i].x < x1) x1 = spans[i].x; + if(spans[i].x + spans[i].len > x2) x2 = spans[i].x + spans[i].len; + } + + span_buffer->x = x1; + span_buffer->y = y1; + span_buffer->w = x2 - x1; + span_buffer->h = y2 - y1 + 1; +} + +void plutovg_span_buffer_extents(plutovg_span_buffer_t* span_buffer, plutovg_rect_t* extents) +{ + plutovg_span_buffer_update_extents(span_buffer); + extents->x = span_buffer->x; + extents->y = span_buffer->y; + extents->w = span_buffer->w; + extents->h = span_buffer->h; +} + +void plutovg_span_buffer_intersect(plutovg_span_buffer_t* span_buffer, const plutovg_span_buffer_t* a, const plutovg_span_buffer_t* b) +{ + plutovg_span_buffer_reset(span_buffer); + plutovg_array_ensure(span_buffer->spans, plutovg_max(a->spans.size, b->spans.size)); + + plutovg_span_t* a_spans = a->spans.data; + plutovg_span_t* a_end = a_spans + a->spans.size; + + plutovg_span_t* b_spans = b->spans.data; + plutovg_span_t* b_end = b_spans + b->spans.size; + while(a_spans < a_end && b_spans < b_end) { + if(b_spans->y > a_spans->y) { + ++a_spans; + continue; + } + + if(a_spans->y != b_spans->y) { + ++b_spans; + continue; + } + + int ax1 = a_spans->x; + int ax2 = ax1 + a_spans->len; + int bx1 = b_spans->x; + int bx2 = bx1 + b_spans->len; + if(bx1 < ax1 && bx2 < ax1) { + ++b_spans; + continue; + } + + if(ax1 < bx1 && ax2 < bx1) { + ++a_spans; + continue; + } + + int x = plutovg_max(ax1, bx1); + int len = plutovg_min(ax2, bx2) - x; + if(len) { + plutovg_array_ensure(span_buffer->spans, 1); + plutovg_span_t* span = span_buffer->spans.data + span_buffer->spans.size; + span->x = x; + span->len = len; + span->y = a_spans->y; + span->coverage = (a_spans->coverage * b_spans->coverage) / 255; + span_buffer->spans.size += 1; + } + + if(ax2 < bx2) { + ++a_spans; + } else { + ++b_spans; + } + } +} + +#define ALIGN_SIZE(size) (((size) + 7ul) & ~7ul) +static PVG_FT_Outline* ft_outline_create(int points, int contours) +{ + size_t points_size = ALIGN_SIZE((points + contours) * sizeof(PVG_FT_Vector)); + size_t tags_size = ALIGN_SIZE((points + contours) * sizeof(char)); + size_t contours_size = ALIGN_SIZE(contours * sizeof(int)); + size_t contours_flag_size = ALIGN_SIZE(contours * sizeof(char)); + PVG_FT_Outline* outline = malloc(points_size + tags_size + contours_size + contours_flag_size + sizeof(PVG_FT_Outline)); + + PVG_FT_Byte* outline_data = (PVG_FT_Byte*)(outline + 1); + outline->points = (PVG_FT_Vector*)(outline_data); + outline->tags = (char*)(outline_data + points_size); + outline->contours = (int*)(outline_data + points_size + tags_size); + outline->contours_flag = (char*)(outline_data + points_size + tags_size + contours_size); + outline->n_points = 0; + outline->n_contours = 0; + outline->flags = 0x0; + return outline; +} + +static void ft_outline_destroy(PVG_FT_Outline* outline) +{ + free(outline); +} + +#define FT_COORD(x) (PVG_FT_Pos)((x) * 64) +static void ft_outline_move_to(PVG_FT_Outline* ft, float x, float y) +{ + ft->points[ft->n_points].x = FT_COORD(x); + ft->points[ft->n_points].y = FT_COORD(y); + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; + if(ft->n_points) { + ft->contours[ft->n_contours] = ft->n_points - 1; + ft->n_contours++; + } + + ft->contours_flag[ft->n_contours] = 1; + ft->n_points++; +} + +static void ft_outline_line_to(PVG_FT_Outline* ft, float x, float y) +{ + ft->points[ft->n_points].x = FT_COORD(x); + ft->points[ft->n_points].y = FT_COORD(y); + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; + ft->n_points++; +} + +static void ft_outline_cubic_to(PVG_FT_Outline* ft, float x1, float y1, float x2, float y2, float x3, float y3) +{ + ft->points[ft->n_points].x = FT_COORD(x1); + ft->points[ft->n_points].y = FT_COORD(y1); + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_CUBIC; + ft->n_points++; + + ft->points[ft->n_points].x = FT_COORD(x2); + ft->points[ft->n_points].y = FT_COORD(y2); + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_CUBIC; + ft->n_points++; + + ft->points[ft->n_points].x = FT_COORD(x3); + ft->points[ft->n_points].y = FT_COORD(y3); + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; + ft->n_points++; +} + +static void ft_outline_close(PVG_FT_Outline* ft) +{ + ft->contours_flag[ft->n_contours] = 0; + int index = ft->n_contours ? ft->contours[ft->n_contours - 1] + 1 : 0; + if(index == ft->n_points) + return; + ft->points[ft->n_points].x = ft->points[index].x; + ft->points[ft->n_points].y = ft->points[index].y; + ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; + ft->n_points++; +} + +static void ft_outline_end(PVG_FT_Outline* ft) +{ + if(ft->n_points) { + ft->contours[ft->n_contours] = ft->n_points - 1; + ft->n_contours++; + } +} + +static PVG_FT_Outline* ft_outline_convert_stroke(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_stroke_data_t* stroke_data); + +static PVG_FT_Outline* ft_outline_convert(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_stroke_data_t* stroke_data) +{ + if(stroke_data) { + return ft_outline_convert_stroke(path, matrix, stroke_data); + } + + plutovg_path_iterator_t it; + plutovg_path_iterator_init(&it, path); + + plutovg_point_t points[3]; + PVG_FT_Outline* outline = ft_outline_create(path->num_points, path->num_contours); + while(plutovg_path_iterator_has_next(&it)) { + switch(plutovg_path_iterator_next(&it, points)) { + case PLUTOVG_PATH_COMMAND_MOVE_TO: + plutovg_matrix_map_points(matrix, points, points, 1); + ft_outline_move_to(outline, points[0].x, points[0].y); + break; + case PLUTOVG_PATH_COMMAND_LINE_TO: + plutovg_matrix_map_points(matrix, points, points, 1); + ft_outline_line_to(outline, points[0].x, points[0].y); + break; + case PLUTOVG_PATH_COMMAND_CUBIC_TO: + plutovg_matrix_map_points(matrix, points, points, 3); + ft_outline_cubic_to(outline, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); + break; + case PLUTOVG_PATH_COMMAND_CLOSE: + ft_outline_close(outline); + break; + } + } + + ft_outline_end(outline); + return outline; +} + +static PVG_FT_Outline* ft_outline_convert_dash(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_stroke_dash_t* stroke_dash) +{ + if(stroke_dash->array.size == 0) + return ft_outline_convert(path, matrix, NULL); + plutovg_path_t* dashed = plutovg_path_clone_dashed(path, stroke_dash->offset, stroke_dash->array.data, stroke_dash->array.size); + PVG_FT_Outline* outline = ft_outline_convert(dashed, matrix, NULL); + plutovg_path_destroy(dashed); + return outline; +} + +static PVG_FT_Outline* ft_outline_convert_stroke(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_stroke_data_t* stroke_data) +{ + double scale_x = sqrt(matrix->a * matrix->a + matrix->b * matrix->b); + double scale_y = sqrt(matrix->c * matrix->c + matrix->d * matrix->d); + + double scale = hypot(scale_x, scale_y) / PLUTOVG_SQRT2; + double width = stroke_data->style.width * scale; + + PVG_FT_Fixed ftWidth = (PVG_FT_Fixed)(width * 0.5 * (1 << 6)); + PVG_FT_Fixed ftMiterLimit = (PVG_FT_Fixed)(stroke_data->style.miter_limit * (1 << 16)); + + PVG_FT_Stroker_LineCap ftCap; + switch(stroke_data->style.cap) { + case PLUTOVG_LINE_CAP_SQUARE: + ftCap = PVG_FT_STROKER_LINECAP_SQUARE; + break; + case PLUTOVG_LINE_CAP_ROUND: + ftCap = PVG_FT_STROKER_LINECAP_ROUND; + break; + default: + ftCap = PVG_FT_STROKER_LINECAP_BUTT; + break; + } + + PVG_FT_Stroker_LineJoin ftJoin; + switch(stroke_data->style.join) { + case PLUTOVG_LINE_JOIN_BEVEL: + ftJoin = PVG_FT_STROKER_LINEJOIN_BEVEL; + break; + case PLUTOVG_LINE_JOIN_ROUND: + ftJoin = PVG_FT_STROKER_LINEJOIN_ROUND; + break; + default: + ftJoin = PVG_FT_STROKER_LINEJOIN_MITER_FIXED; + break; + } + + PVG_FT_Stroker stroker; + PVG_FT_Stroker_New(&stroker); + PVG_FT_Stroker_Set(stroker, ftWidth, ftCap, ftJoin, ftMiterLimit); + + PVG_FT_Outline* outline = ft_outline_convert_dash(path, matrix, &stroke_data->dash); + PVG_FT_Stroker_ParseOutline(stroker, outline); + + PVG_FT_UInt points; + PVG_FT_UInt contours; + PVG_FT_Stroker_GetCounts(stroker, &points, &contours); + + PVG_FT_Outline* stroke_outline = ft_outline_create(points, contours); + PVG_FT_Stroker_Export(stroker, stroke_outline); + + PVG_FT_Stroker_Done(stroker); + ft_outline_destroy(outline); + return stroke_outline; +} + +static void spans_generation_callback(int count, const PVG_FT_Span* spans, void* user) +{ + plutovg_span_buffer_t* span_buffer = (plutovg_span_buffer_t*)(user); + plutovg_array_append_data(span_buffer->spans, spans, count); +} + +void plutovg_rasterize(plutovg_span_buffer_t* span_buffer, const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_rect_t* clip_rect, const plutovg_stroke_data_t* stroke_data, plutovg_fill_rule_t winding) +{ + PVG_FT_Outline* outline = ft_outline_convert(path, matrix, stroke_data); + if(stroke_data) { + outline->flags = PVG_FT_OUTLINE_NONE; + } else { + switch(winding) { + case PLUTOVG_FILL_RULE_EVEN_ODD: + outline->flags = PVG_FT_OUTLINE_EVEN_ODD_FILL; + break; + default: + outline->flags = PVG_FT_OUTLINE_NONE; + break; + } + } + + PVG_FT_Raster_Params params; + params.flags = PVG_FT_RASTER_FLAG_DIRECT | PVG_FT_RASTER_FLAG_AA; + params.gray_spans = spans_generation_callback; + params.user = span_buffer; + params.source = outline; + if(clip_rect) { + params.flags |= PVG_FT_RASTER_FLAG_CLIP; + params.clip_box.xMin = (PVG_FT_Pos)clip_rect->x; + params.clip_box.yMin = (PVG_FT_Pos)clip_rect->y; + params.clip_box.xMax = (PVG_FT_Pos)(clip_rect->x + clip_rect->w); + params.clip_box.yMax = (PVG_FT_Pos)(clip_rect->y + clip_rect->h); + } + + plutovg_span_buffer_reset(span_buffer); + PVG_FT_Raster_Render(¶ms); + ft_outline_destroy(outline); +} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-rle.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-rle.c deleted file mode 100644 index 38c83cdc07..0000000000 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg-rle.c +++ /dev/null @@ -1,424 +0,0 @@ -#include "plutovg-private.h" - -#include "plutovg-ft-raster.h" -#include "plutovg-ft-stroker.h" - -#include -#include - -#define ALIGN_SIZE(size) (((size) + 7ul) & ~7ul) -static void ft_outline_init(PVG_FT_Outline* outline, plutovg_t* pluto, int points, int contours) -{ - size_t size_a = ALIGN_SIZE((points + contours) * sizeof(PVG_FT_Vector)); - size_t size_b = ALIGN_SIZE((points + contours) * sizeof(char)); - size_t size_c = ALIGN_SIZE(contours * sizeof(int)); - size_t size_d = ALIGN_SIZE(contours * sizeof(char)); - size_t size_n = size_a + size_b + size_c + size_d; - if(size_n > pluto->outline_size) { - pluto->outline_data = realloc(pluto->outline_data, size_n); - pluto->outline_size = size_n; - } - - PVG_FT_Byte* data = pluto->outline_data; - outline->points = (PVG_FT_Vector*)(data); - outline->tags = outline->contours_flag = NULL; - outline->contours = NULL; - if(data){ - outline->tags = (char*)(data + size_a); - outline->contours = (int*)(data + size_a + size_b); - outline->contours_flag = (char*)(data + size_a + size_b + size_c); - } - outline->n_points = 0; - outline->n_contours = 0; - outline->flags = 0x0; -} - -#define FT_COORD(x) (PVG_FT_Pos)((x) * 64) -static void ft_outline_move_to(PVG_FT_Outline* ft, double x, double y) -{ - ft->points[ft->n_points].x = FT_COORD(x); - ft->points[ft->n_points].y = FT_COORD(y); - ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; - if(ft->n_points) { - ft->contours[ft->n_contours] = ft->n_points - 1; - ft->n_contours++; - } - - ft->contours_flag[ft->n_contours] = 1; - ft->n_points++; -} - -static void ft_outline_line_to(PVG_FT_Outline* ft, double x, double y) -{ - ft->points[ft->n_points].x = FT_COORD(x); - ft->points[ft->n_points].y = FT_COORD(y); - ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; - ft->n_points++; -} - -static void ft_outline_cubic_to(PVG_FT_Outline* ft, double x1, double y1, double x2, double y2, double x3, double y3) -{ - ft->points[ft->n_points].x = FT_COORD(x1); - ft->points[ft->n_points].y = FT_COORD(y1); - ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_CUBIC; - ft->n_points++; - - ft->points[ft->n_points].x = FT_COORD(x2); - ft->points[ft->n_points].y = FT_COORD(y2); - ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_CUBIC; - ft->n_points++; - - ft->points[ft->n_points].x = FT_COORD(x3); - ft->points[ft->n_points].y = FT_COORD(y3); - ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; - ft->n_points++; -} - -static void ft_outline_close(PVG_FT_Outline* ft) -{ - ft->contours_flag[ft->n_contours] = 0; - int index = ft->n_contours ? ft->contours[ft->n_contours - 1] + 1 : 0; - if(index == ft->n_points) - return; - - ft->points[ft->n_points].x = ft->points[index].x; - ft->points[ft->n_points].y = ft->points[index].y; - ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON; - ft->n_points++; -} - -static void ft_outline_end(PVG_FT_Outline* ft) -{ - if(ft->n_points) { - ft->contours[ft->n_contours] = ft->n_points - 1; - ft->n_contours++; - } -} - -static void ft_outline_convert(PVG_FT_Outline* outline, plutovg_t* pluto, const plutovg_path_t* path, const plutovg_matrix_t* matrix) -{ - ft_outline_init(outline, pluto, path->points.size, path->contours); - plutovg_path_element_t* elements = path->elements.data; - plutovg_point_t* points = path->points.data; - plutovg_point_t p[3]; - for(int i = 0;i < path->elements.size;i++) { - switch(elements[i]) { - case plutovg_path_element_move_to: - plutovg_matrix_map_point(matrix, &points[0], &p[0]); - ft_outline_move_to(outline, p[0].x, p[0].y); - points += 1; - break; - case plutovg_path_element_line_to: - plutovg_matrix_map_point(matrix, &points[0], &p[0]); - ft_outline_line_to(outline, p[0].x, p[0].y); - points += 1; - break; - case plutovg_path_element_cubic_to: - plutovg_matrix_map_point(matrix, &points[0], &p[0]); - plutovg_matrix_map_point(matrix, &points[1], &p[1]); - plutovg_matrix_map_point(matrix, &points[2], &p[2]); - ft_outline_cubic_to(outline, p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y); - points += 3; - break; - case plutovg_path_element_close: - ft_outline_close(outline); - points += 1; - break; - } - } - - ft_outline_end(outline); -} - -static void ft_outline_convert_dash(PVG_FT_Outline* outline, plutovg_t* pluto, const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_dash_t* dash) -{ - plutovg_path_t* dashed = plutovg_dash_path(dash, path); - ft_outline_convert(outline, pluto, dashed, matrix); - plutovg_path_destroy(dashed); -} - -static void generation_callback(int count, const PVG_FT_Span* spans, void* user) -{ - plutovg_rle_t* rle = user; - plutovg_array_ensure(rle->spans, count); - plutovg_span_t* data = rle->spans.data + rle->spans.size; - memcpy(data, spans, (size_t)count * sizeof(plutovg_span_t)); - rle->spans.size += count; -} - -plutovg_rle_t* plutovg_rle_create(void) -{ - plutovg_rle_t* rle = malloc(sizeof(plutovg_rle_t)); - plutovg_array_init(rle->spans); - rle->x = 0; - rle->y = 0; - rle->w = 0; - rle->h = 0; - return rle; -} - -void plutovg_rle_destroy(plutovg_rle_t* rle) -{ - if(rle==NULL) - return; - - free(rle->spans.data); - free(rle); -} - -void plutovg_rle_rasterize(plutovg_t* pluto, plutovg_rle_t* rle, const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_rect_t* clip, const plutovg_stroke_data_t* stroke, plutovg_fill_rule_t winding) -{ - PVG_FT_Raster_Params params; - params.flags = PVG_FT_RASTER_FLAG_DIRECT | PVG_FT_RASTER_FLAG_AA; - params.gray_spans = generation_callback; - params.user = rle; - if(clip) { - params.flags |= PVG_FT_RASTER_FLAG_CLIP; - params.clip_box.xMin = (PVG_FT_Pos)(clip->x); - params.clip_box.yMin = (PVG_FT_Pos)(clip->y); - params.clip_box.xMax = (PVG_FT_Pos)(clip->x + clip->w); - params.clip_box.yMax = (PVG_FT_Pos)(clip->y + clip->h); - } - - if(stroke) { - PVG_FT_Outline outline; - if(stroke->dash == NULL) - ft_outline_convert(&outline, pluto, path, matrix); - else - ft_outline_convert_dash(&outline, pluto, path, matrix, stroke->dash); - PVG_FT_Stroker_LineCap ftCap; - PVG_FT_Stroker_LineJoin ftJoin; - PVG_FT_Fixed ftWidth; - PVG_FT_Fixed ftMiterLimit; - - plutovg_point_t p1 = {0, 0}; - plutovg_point_t p2 = {plutovg_sqrt2, plutovg_sqrt2}; - plutovg_point_t p3; - - plutovg_matrix_map_point(matrix, &p1, &p1); - plutovg_matrix_map_point(matrix, &p2, &p2); - - p3.x = p2.x - p1.x; - p3.y = p2.y - p1.y; - - double scale = sqrt(p3.x*p3.x + p3.y*p3.y) / 2.0; - - ftWidth = (PVG_FT_Fixed)(stroke->width * scale * 0.5 * (1 << 6)); - ftMiterLimit = (PVG_FT_Fixed)(stroke->miterlimit * (1 << 16)); - - switch(stroke->cap) { - case plutovg_line_cap_square: - ftCap = PVG_FT_STROKER_LINECAP_SQUARE; - break; - case plutovg_line_cap_round: - ftCap = PVG_FT_STROKER_LINECAP_ROUND; - break; - default: - ftCap = PVG_FT_STROKER_LINECAP_BUTT; - break; - } - - switch(stroke->join) { - case plutovg_line_join_bevel: - ftJoin = PVG_FT_STROKER_LINEJOIN_BEVEL; - break; - case plutovg_line_join_round: - ftJoin = PVG_FT_STROKER_LINEJOIN_ROUND; - break; - default: - ftJoin = PVG_FT_STROKER_LINEJOIN_MITER_FIXED; - break; - } - - PVG_FT_Stroker stroker; - PVG_FT_Stroker_New(&stroker); - PVG_FT_Stroker_Set(stroker, ftWidth, ftCap, ftJoin, ftMiterLimit); - PVG_FT_Stroker_ParseOutline(stroker, &outline); - - PVG_FT_UInt points; - PVG_FT_UInt contours; - PVG_FT_Stroker_GetCounts(stroker, &points, &contours); - - ft_outline_init(&outline, pluto, points, contours); - PVG_FT_Stroker_Export(stroker, &outline); - PVG_FT_Stroker_Done(stroker); - - outline.flags = PVG_FT_OUTLINE_NONE; - params.source = &outline; - PVG_FT_Raster_Render(¶ms); - } else { - PVG_FT_Outline outline; - ft_outline_convert(&outline, pluto, path, matrix); - switch(winding) { - case plutovg_fill_rule_even_odd: - outline.flags = PVG_FT_OUTLINE_EVEN_ODD_FILL; - break; - default: - outline.flags = PVG_FT_OUTLINE_NONE; - break; - } - - params.source = &outline; - PVG_FT_Raster_Render(¶ms); - } - - if(rle->spans.size == 0) { - rle->x = 0; - rle->y = 0; - rle->w = 0; - rle->h = 0; - return; - } - - plutovg_span_t* spans = rle->spans.data; - int x1 = INT_MAX; - int y1 = spans[0].y; - int x2 = 0; - int y2 = spans[rle->spans.size - 1].y; - for(int i = 0;i < rle->spans.size;i++) - { - if(spans[i].x < x1) x1 = spans[i].x; - if(spans[i].x + spans[i].len > x2) x2 = spans[i].x + spans[i].len; - } - - rle->x = x1; - rle->y = y1; - rle->w = x2 - x1; - rle->h = y2 - y1 + 1; -} - -plutovg_rle_t* plutovg_rle_intersection(const plutovg_rle_t* a, const plutovg_rle_t* b) -{ - int count = plutovg_max(a->spans.size, b->spans.size); - plutovg_rle_t* result = malloc(sizeof(plutovg_rle_t)); - plutovg_array_init(result->spans); - plutovg_array_ensure(result->spans, count); - - plutovg_span_t* a_spans = a->spans.data; - plutovg_span_t* a_end = a_spans + a->spans.size; - - plutovg_span_t* b_spans = b->spans.data; - plutovg_span_t* b_end = b_spans + b->spans.size; - - while(count && a_spans < a_end && b_spans < b_end) - { - if(b_spans->y > a_spans->y) - { - ++a_spans; - continue; - } - - if(a_spans->y != b_spans->y) - { - ++b_spans; - continue; - } - - int ax1 = a_spans->x; - int ax2 = ax1 + a_spans->len; - int bx1 = b_spans->x; - int bx2 = bx1 + b_spans->len; - - if(bx1 < ax1 && bx2 < ax1) - { - ++b_spans; - continue; - } - else if(ax1 < bx1 && ax2 < bx1) - { - ++a_spans; - continue; - } - - int x = plutovg_max(ax1, bx1); - int len = plutovg_min(ax2, bx2) - x; - if(len) - { - plutovg_span_t* span = result->spans.data + result->spans.size; - span->x = (short)x; - span->len = (unsigned short)len; - span->y = a_spans->y; - span->coverage = plutovg_div255(a_spans->coverage * b_spans->coverage); - ++result->spans.size; - --count; - } - - if(ax2 < bx2) - { - ++a_spans; - } - else - { - ++b_spans; - } - } - - if(result->spans.size==0) - { - result->x = 0; - result->y = 0; - result->w = 0; - result->h = 0; - return result; - } - - plutovg_span_t* spans = result->spans.data; - int x1 = INT_MAX; - int y1 = spans[0].y; - int x2 = 0; - int y2 = spans[result->spans.size - 1].y; - for(int i = 0;i < result->spans.size;i++) - { - if(spans[i].x < x1) x1 = spans[i].x; - if(spans[i].x + spans[i].len > x2) x2 = spans[i].x + spans[i].len; - } - - result->x = x1; - result->y = y1; - result->w = x2 - x1; - result->h = y2 - y1 + 1; - return result; -} - -void plutovg_rle_clip_path(plutovg_rle_t* rle, const plutovg_rle_t* clip) -{ - if(rle==NULL || clip==NULL) - return; - - plutovg_rle_t* result = plutovg_rle_intersection(rle, clip); - plutovg_array_ensure(rle->spans, result->spans.size); - memcpy(rle->spans.data, result->spans.data, (size_t)result->spans.size * sizeof(plutovg_span_t)); - rle->spans.size = result->spans.size; - rle->x = result->x; - rle->y = result->y; - rle->w = result->w; - rle->h = result->h; - plutovg_rle_destroy(result); -} - -plutovg_rle_t* plutovg_rle_clone(const plutovg_rle_t* rle) -{ - if(rle==NULL) - return NULL; - - plutovg_rle_t* result = malloc(sizeof(plutovg_rle_t)); - plutovg_array_init(result->spans); - plutovg_array_ensure(result->spans, rle->spans.size); - - memcpy(result->spans.data, rle->spans.data, (size_t)rle->spans.size * sizeof(plutovg_span_t)); - result->spans.size = rle->spans.size; - result->x = rle->x; - result->y = rle->y; - result->w = rle->w; - result->h = rle->h; - return result; -} - -void plutovg_rle_clear(plutovg_rle_t* rle) -{ - rle->spans.size = 0; - rle->x = 0; - rle->y = 0; - rle->w = 0; - rle->h = 0; -} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-image-write.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-image-write.h new file mode 100644 index 0000000000..dba9089ee7 --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-image-write.h @@ -0,0 +1,1724 @@ +/* stb_image_write - v1.16 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio or a callback. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + Andrew Kensler + +LICENSE + + See end of file for license information. + +*/ + +#ifndef PLUTOVG_STB_IMAGE_WRITE_H +#define PLUTOVG_STB_IMAGE_WRITE_H + +#include + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +STBIWDEF int stbi_write_tga_with_rle; +STBIWDEF int stbi_write_png_compression_level; +STBIWDEF int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBIW_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//PLUTOVG_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +static int stbi__flip_vertically_on_write = 0; + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; + unsigned char buffer[64]; + int buf_used; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__write_flush(stbi__write_context *s) +{ + if (s->buf_used) { + s->func(s->context, &s->buffer, s->buf_used); + s->buf_used = 0; + } +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write1(stbi__write_context *s, unsigned char a) +{ + if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) + stbiw__write_flush(s); + s->buffer[s->buf_used++] = a; +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + int n; + if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) + stbiw__write_flush(s); + n = s->buf_used; + s->buf_used = n+3; + s->buffer[n+0] = a; + s->buffer[n+1] = b; + s->buffer[n+2] = c; +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + stbiw__write1(s, d[comp - 1]); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + stbiw__write1(s, d[0]); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + stbiw__write1(s, d[comp - 1]); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + stbiw__write_flush(s); + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + if (comp != 4) { + // write RGB bitmap + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header + } else { + // RGBA bitmaps need a v4 header + // use BI_BITFIELDS mode with 32bpp and alpha mask + // (straight BI_RGB with alpha mask doesn't work in most readers) + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, + "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", + 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header + 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header + } +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + stbiw__write1(s, header); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + stbiw__write1(s, header); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + stbiw__write_flush(s); + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +#ifndef STBI_WRITE_NO_STDIO + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef __STDC_LIB_EXT1__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) { best=d; bestloc=hlist[j]; } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + // store uncompressed instead if compression was worse + if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { + stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 + for (j = 0; j < data_len;) { + int blocklen = data_len - j; + if (blocklen > 32767) blocklen = 32767; + stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression + stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN + stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN + stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); + memcpy(out+stbiw__sbn(out), data+j, blocklen); + stbiw__sbn(out) += blocklen; + j += blocklen; + } + } + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.16 (2021-07-11) + make Deflate code emit uncompressed blocks when it would otherwise expand + support writing BMPs with alpha channel + 1.15 (2020-07-13) unknown + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-image.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-image.h new file mode 100644 index 0000000000..3938bafbc0 --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-image.h @@ -0,0 +1,7988 @@ +/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.30 (2024-05-31) avoid erroneous gcc warning + 2.29 (2023-05-xx) optimizations + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef PLUTOVG_STB_IMAGE_H +#define PLUTOVG_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data); +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // PLUTOVG_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if defined(_MSC_VER) || defined(__SYMBIAN32__) +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { + h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + j->marker = stbi__skip_jpeg_junk_at_end(j); + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); + } else { + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); + } + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + int hit_zeof_once; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); + } + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } + return 1; + } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (len > a->zout_end - zout) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + a->hit_zeof_once = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub +}; + +static int stbi__paeth(int a, int b, int c) +{ + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + + for (j=0; j < y; ++j) { + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; + int filter = *raw++; + + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; + } + + raw += nk; + + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; + + // expand bits to bytes first + if (depth == 4) { + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; + } + } else if (depth == 2) { + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; + } + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; + } + } + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); + if (img_n == 1) { + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; + } + } else { + STBI_ASSERT(img_n == 3); + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; + } + } + } + } + } + + STBI_FREE(filter_buf); + if (!all_ok) return 0; + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + } + // even with SCAN_header, have to scan to see if we have a tRNS + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } + if (z->depth == 16) { + for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n && k < 3; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } + + if (req_comp && req_comp != s->img_n) { + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-truetype.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-truetype.h new file mode 100644 index 0000000000..a66c5b46cc --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-stb-truetype.h @@ -0,0 +1,5077 @@ +// stb_truetype.h - v1.26 - public domain +// authored from 2009-2021 by Sean Barrett / RAD Game Tools +// +// ======================================================================= +// +// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES +// +// This library does no range checking of the offsets found in the file, +// meaning an attacker can use it to read arbitrary memory. +// +// ======================================================================= +// +// This library processes TrueType files: +// parse files +// extract glyph metrics +// extract glyph shapes +// render glyphs to one-channel bitmaps with antialiasing (box filter) +// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// +// Todo: +// non-MS cmaps +// crashproof on bad data +// hinting? (no longer patented) +// cleartype-style AA? +// optimize: use simple memory allocator for intermediates +// optimize: build edge-list directly from curves +// optimize: rasterize directly from curves? +// +// ADDITIONAL CONTRIBUTORS +// +// Mikko Mononen: compound shape support, more cmap formats +// Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning +// +// Misc other: +// Ryan Gordon +// Simon Glass +// github:IntellectualKitty +// Imanol Celaya +// Daniel Ribeiro Maciel +// +// Bug/warning reports/fixes: +// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe +// Cass Everitt Martins Mozeiko github:aloucks +// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam +// Brian Hook Omar Cornut github:vassvik +// Walter van Niftrik Ryan Griege +// David Gow Peter LaValle +// David Given Sergey Popov +// Ivan-Assen Ivanov Giumo X. Clanjor +// Anthony Pesch Higor Euripedes +// Johan Duparc Thomas Fields +// Hou Qiming Derek Vinyard +// Rob Loach Cort Stratton +// Kenney Phillis Jr. Brian Costabile +// Ken Voskuil (kaesve) +// +// VERSION HISTORY +// +// 1.26 (2021-08-28) fix broken rasterizer +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// variant PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// +// Full history can be found at the end of this file. +// +// LICENSE +// +// See end of file for license information. +// +// USAGE +// +// Include this file in whatever places need to refer to it. In ONE C/C++ +// file, write: +// #define STB_TRUETYPE_IMPLEMENTATION +// before the #include of this file. This expands out the actual +// implementation into that C/C++ file. +// +// To make the implementation private to the file that generates the implementation, +// #define STBTT_STATIC +// +// Simple 3D API (don't ship this, but it's fine for tools and quick start) +// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture +// stbtt_GetBakedQuad() -- compute quad to draw for a given char +// +// Improved 3D API (more shippable): +// #include "stb_rect_pack.h" -- optional, but you really want it +// stbtt_PackBegin() +// stbtt_PackSetOversampling() -- for improved quality on small fonts +// stbtt_PackFontRanges() -- pack and renders +// stbtt_PackEnd() +// stbtt_GetPackedQuad() +// +// "Load" a font file from a memory buffer (you have to keep the buffer loaded) +// stbtt_InitFont() +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections +// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections +// +// Render a unicode codepoint to a bitmap +// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap +// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide +// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be +// +// Character advance/positioning +// stbtt_GetCodepointHMetrics() +// stbtt_GetFontVMetrics() +// stbtt_GetFontVMetricsOS2() +// stbtt_GetCodepointKernAdvance() +// +// Starting with version 1.06, the rasterizer was replaced with a new, +// faster and generally-more-precise rasterizer. The new rasterizer more +// accurately measures pixel coverage for anti-aliasing, except in the case +// where multiple shapes overlap, in which case it overestimates the AA pixel +// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If +// this turns out to be a problem, you can re-enable the old rasterizer with +// #define STBTT_RASTERIZER_VERSION 1 +// which will incur about a 15% speed hit. +// +// ADDITIONAL DOCUMENTATION +// +// Immediately after this block comment are a series of sample programs. +// +// After the sample programs is the "header file" section. This section +// includes documentation for each API function. +// +// Some important concepts to understand to use this library: +// +// Codepoint +// Characters are defined by unicode codepoints, e.g. 65 is +// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is +// the hiragana for "ma". +// +// Glyph +// A visual character shape (every codepoint is rendered as +// some glyph) +// +// Glyph index +// A font-specific integer ID representing a glyph +// +// Baseline +// Glyph shapes are defined relative to a baseline, which is the +// bottom of uppercase characters. Characters extend both above +// and below the baseline. +// +// Current Point +// As you draw text to the screen, you keep track of a "current point" +// which is the origin of each character. The current point's vertical +// position is the baseline. Even "baked fonts" use this model. +// +// Vertical Font Metrics +// The vertical qualities of the font, used to vertically position +// and space the characters. See docs for stbtt_GetFontVMetrics. +// +// Font Size in Pixels or Points +// The preferred interface for specifying font sizes in stb_truetype +// is to specify how tall the font's vertical extent should be in pixels. +// If that sounds good enough, skip the next paragraph. +// +// Most font APIs instead use "points", which are a common typographic +// measurement for describing font size, defined as 72 points per inch. +// stb_truetype provides a point API for compatibility. However, true +// "per inch" conventions don't make much sense on computer displays +// since different monitors have different number of pixels per +// inch. For example, Windows traditionally uses a convention that +// there are 96 pixels per inch, thus making 'inch' measurements have +// nothing to do with inches, and thus effectively defining a point to +// be 1.333 pixels. Additionally, the TrueType font data provides +// an explicit scale factor to scale a given font's glyphs to points, +// but the author has observed that this scale factor is often wrong +// for non-commercial fonts, thus making fonts scaled in points +// according to the TrueType spec incoherently sized in practice. +// +// DETAILED USAGE: +// +// Scale: +// Select how high you want the font to be, in points or pixels. +// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute +// a scale factor SF that will be used by all other functions. +// +// Baseline: +// You need to select a y-coordinate that is the baseline of where +// your text will appear. Call GetFontBoundingBox to get the baseline-relative +// bounding box for all characters. SF*-y0 will be the distance in pixels +// that the worst-case character could extend above the baseline, so if +// you want the top edge of characters to appear at the top of the +// screen where y=0, then you would set the baseline to SF*-y0. +// +// Current point: +// Set the current point where the first character will appear. The +// first character could extend left of the current point; this is font +// dependent. You can either choose a current point that is the leftmost +// point and hope, or add some padding, or check the bounding box or +// left-side-bearing of the first character to be displayed and set +// the current point based on that. +// +// Displaying a character: +// Compute the bounding box of the character. It will contain signed values +// relative to . I.e. if it returns x0,y0,x1,y1, +// then the character should be displayed in the rectangle from +// to = 32 && *text < 128) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); + } + ++text; + } + glEnd(); +} +#endif +// +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program (this compiles): get a single bitmap, print as ASCII art +// +#if 0 +#include +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#include "stb_truetype.h" + +char ttf_buffer[1<<25]; + +int main(int argc, char **argv) +{ + stbtt_fontinfo font; + unsigned char *bitmap; + int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); + + fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); + + stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); + bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); + + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) + putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); + putchar('\n'); + } + return 0; +} +#endif +// +// Output: +// +// .ii. +// @@@@@@. +// V@Mio@@o +// :i. V@V +// :oM@@M +// :@@@MM@M +// @@o o@M +// :@@. M@M +// @@@o@@@@ +// :M@@V:@@. +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program: print "Hello World!" banner, with bugs +// +#if 0 +char buffer[24<<20]; +unsigned char screen[20][79]; + +int main(int arg, char **argv) +{ + stbtt_fontinfo font; + int i,j,ascent,baseline,ch=0; + float scale, xpos=2; // leave a little padding in case the character extends left + char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness + + fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); + stbtt_InitFont(&font, buffer, 0); + + scale = stbtt_ScaleForPixelHeight(&font, 15); + stbtt_GetFontVMetrics(&font, &ascent,0,0); + baseline = (int) (ascent*scale); + + while (text[ch]) { + int advance,lsb,x0,y0,x1,y1; + float x_shift = xpos - (float) floor(xpos); + stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); + stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); + stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); + // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong + // because this API is really for baking character bitmaps into textures. if you want to render + // a sequence of characters, you really need to render each bitmap to a temp buffer, then + // "alpha blend" that into the working buffer + xpos += (advance * scale); + if (text[ch+1]) + xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); + ++ch; + } + + for (j=0; j < 20; ++j) { + for (i=0; i < 78; ++i) + putchar(" .:ioVM@"[screen[j][i]>>5]); + putchar('\n'); + } + + return 0; +} +#endif + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +//// +//// INTEGRATION WITH YOUR CODEBASE +//// +//// The following sections allow you to supply alternate definitions +//// of C library functions used by stb_truetype, e.g. if you don't +//// link with the C runtime library. + +#ifdef STB_TRUETYPE_IMPLEMENTATION + // #define your own (u)stbtt_int8/16/32 before including to override this + #ifndef stbtt_uint8 + typedef unsigned char stbtt_uint8; + typedef signed char stbtt_int8; + typedef unsigned short stbtt_uint16; + typedef signed short stbtt_int16; + typedef unsigned int stbtt_uint32; + typedef signed int stbtt_int32; + #endif + + typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; + typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; + + // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h + #ifndef STBTT_ifloor + #include + #define STBTT_ifloor(x) ((int) floor(x)) + #define STBTT_iceil(x) ((int) ceil(x)) + #endif + + #ifndef STBTT_sqrt + #include + #define STBTT_sqrt(x) sqrt(x) + #define STBTT_pow(x,y) pow(x,y) + #endif + + #ifndef STBTT_fmod + #include + #define STBTT_fmod(x,y) fmod(x,y) + #endif + + #ifndef STBTT_cos + #include + #define STBTT_cos(x) cos(x) + #define STBTT_acos(x) acos(x) + #endif + + #ifndef STBTT_fabs + #include + #define STBTT_fabs(x) fabs(x) + #endif + + // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h + #ifndef STBTT_malloc + #include + #define STBTT_malloc(x,u) ((void)(u),malloc(x)) + #define STBTT_free(x,u) ((void)(u),free(x)) + #endif + + #ifndef STBTT_assert + #include + #define STBTT_assert(x) assert(x) + #endif + + #ifndef STBTT_strlen + #include + #define STBTT_strlen(x) strlen(x) + #endif + + #ifndef STBTT_memcpy + #include + #define STBTT_memcpy memcpy + #define STBTT_memset memset + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// INTERFACE +//// +//// + +#ifndef PLUTOVG_STB_TRUETYPE_H +#define PLUTOVG_STB_TRUETYPE_H + +#ifdef STBTT_STATIC +#define STBTT_DEF static +#else +#define STBTT_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// private structure +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + +////////////////////////////////////////////////////////////////////////////// +// +// TEXTURE BAKING API +// +// If you use this API, you only have to call two functions ever. +// + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; +} stbtt_bakedchar; + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +// if return is positive, the first unused row of the bitmap +// if return is negative, returns the negative of the number of characters that fit +// if return is 0, no characters fit and no rows were used +// This uses a very crappy packing. + +typedef struct +{ + float x0,y0,s0,t0; // top-left + float x1,y1,s1,t1; // bottom-right +} stbtt_aligned_quad; + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +// Call GetBakedQuad with char_index = 'character - first_char', and it +// creates the quad you need to draw and advances the current position. +// +// The coordinate system used assumes y increases downwards. +// +// Characters will extend both above and below the current position; +// see discussion of "BASELINE" above. +// +// It's inefficient; you might want to c&p it and optimize it. + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +// Query the font vertical metrics without having to create a font first. + + +////////////////////////////////////////////////////////////////////////////// +// +// NEW TEXTURE BAKING API +// +// This provides options for packing multiple fonts into one atlas, not +// perfectly but better than nothing. + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; + float xoff2,yoff2; +} stbtt_packedchar; + +typedef struct stbtt_pack_context stbtt_pack_context; +typedef struct stbtt_fontinfo stbtt_fontinfo; +#ifndef STB_RECT_PACK_VERSION +typedef struct stbrp_rect stbrp_rect; +#endif + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +// Initializes a packing context stored in the passed-in stbtt_pack_context. +// Future calls using this context will pack characters into the bitmap passed +// in here: a 1-channel bitmap that is width * height. stride_in_bytes is +// the distance from one row to the next (or 0 to mean they are packed tightly +// together). "padding" is the amount of padding to leave between each +// character (normally you want '1' for bitmaps you'll use as textures with +// bilinear filtering). +// +// Returns 0 on failure, 1 on success. + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +// Cleans up the packing context and frees all memory. + +#define STBTT_POINT_SIZE(x) (-(x)) + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +// Creates character bitmaps from the font_index'th font found in fontdata (use +// font_index=0 if you don't know what that is). It creates num_chars_in_range +// bitmaps for characters with unicode values starting at first_unicode_char_in_range +// and increasing. Data for how to render them is stored in chardata_for_range; +// pass these to stbtt_GetPackedQuad to get back renderable quads. +// +// font_size is the full height of the character from ascender to descender, +// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed +// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() +// and pass that result as 'font_size': +// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall + +typedef struct +{ + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, v_oversample; // don't set these, they're used internally +} stbtt_pack_range; + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +// Creates character bitmaps from multiple ranges of characters stored in +// ranges. This will usually create a better-packed bitmap than multiple +// calls to stbtt_PackFontRange. Note that you can call this multiple +// times within a single PackBegin/PackEnd. + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +// Oversampling a font increases the quality by allowing higher-quality subpixel +// positioning, and is especially valuable at smaller text sizes. +// +// This function sets the amount of oversampling for all following calls to +// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given +// pack context. The default (no oversampling) is achieved by h_oversample=1 +// and v_oversample=1. The total number of pixels required is +// h_oversample*v_oversample larger than the default; for example, 2x2 +// oversampling requires 4x the storage of 1x1. For best results, render +// oversampled textures with bilinear filtering. Look at the readme in +// stb/tests/oversample for information about oversampled fonts +// +// To use with PackFontRangesGather etc., you must set it before calls +// call to PackFontRangesGatherRects. + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +// If skip != 0, this tells stb_truetype to skip any codepoints for which +// there is no corresponding glyph. If skip=0, which is the default, then +// codepoints without a glyph recived the font's "missing character" glyph, +// typically an empty box by convention. + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); + +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +// Calling these functions in sequence is roughly equivalent to calling +// stbtt_PackFontRanges(). If you more control over the packing of multiple +// fonts, or if you want to pack custom data into a font texture, take a look +// at the source to of stbtt_PackFontRanges() and create a custom version +// using these functions, e.g. call GatherRects multiple times, +// building up a single array of rects, then call PackRects once, +// then call RenderIntoRects repeatedly. This may result in a +// better packing than calling PackFontRanges multiple times +// (or it may not). + +// this is an opaque structure that you shouldn't mess with which holds +// all the context needed from PackBegin to PackEnd. +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// FONT LOADING +// +// + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +// This function will determine the number of fonts in a font file. TrueType +// collection (.ttc) files may contain multiple fonts, while TrueType font +// (.ttf) files only contain one font. The number of fonts can be used for +// indexing with the previous function where the index is between zero and one +// less than the total fonts. If an error occurs, -1 is returned. + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); +// Each .ttf/.ttc file may have more than one font. Each font has a sequential +// index number starting from 0. Call this function to get the font offset for +// a given index; it returns -1 if the index is out of range. A regular .ttf +// file will only define one font and it always be at offset 0, so it will +// return '0' for index 0, and -1 for all other indices. + +// The following structure is defined publicly so you can declare one on +// the stack or as a global or etc, but you should treat it as opaque. +struct stbtt_fontinfo +{ + void * userdata; + unsigned char * data; // pointer to .ttf file + int fontstart; // offset of start of font + + int numGlyphs; // number of glyphs, needed for range checking + + int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict +}; + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); +// Given an offset into the file that defines a font, this function builds +// the necessary cached info for the rest of the system. You must allocate +// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't +// need to do anything special to free it, because the contents are pure +// value data with no additional data structures. Returns 0 on failure. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER TO GLYPH-INDEX CONVERSIOn + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); +// If you're going to perform multiple operations on the same character +// and you want a speed-up, call this function with the character you're +// going to process, then use glyph-based functions instead of the +// codepoint-based functions. +// Returns 0 if the character codepoint is not defined in the font. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER PROPERTIES +// + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose "height" is 'pixels' tall. +// Height is measured as the distance from the highest ascender to the lowest +// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics +// and computing: +// scale = pixels / (ascent - descent) +// so if you prefer to measure height by the ascent only, use a similar calculation. + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose EM size is mapped to +// 'pixels' tall. This is probably what traditional APIs compute, but +// I'm not positive. + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +// ascent is the coordinate above the baseline the font extends; descent +// is the coordinate below the baseline the font extends (i.e. it is typically negative) +// lineGap is the spacing between one row's descent and the next row's ascent... +// so you should advance the vertical position by "*ascent - *descent + *lineGap" +// these are expressed in unscaled coordinates, so you must multiply by +// the scale factor for a given size + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 +// table (specific to MS/Windows TTF files). +// +// Returns 1 on success (table present), 0 on failure. + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +// the bounding box around all possible characters + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +// leftSideBearing is the offset from the current horizontal position to the left edge of the character +// advanceWidth is the offset from the current horizontal position to the next horizontal position +// these are expressed in unscaled coordinates + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +// an additional amount to add to the 'advance' value between ch1 and ch2 + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); +// Gets the bounding box of the visible part of the glyph, in unscaled coordinates + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); +// as above, but takes one or more glyph indices for greater efficiency + +typedef struct stbtt_kerningentry +{ + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; +} stbtt_kerningentry; + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +// Retrieves a complete list of all of the kerning pairs provided by the font +// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. +// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) + +////////////////////////////////////////////////////////////////////////////// +// +// GLYPH SHAPES (you probably don't need these, but they have to go before +// the bitmaps for C declaration-order reasons) +// + +#ifndef STBTT_vmove // you can predefine these to use different values (but why?) + enum { + STBTT_vmove=1, + STBTT_vline, + STBTT_vcurve, + STBTT_vcubic + }; +#endif + +#ifndef stbtt_vertex // you can predefine this to use different values + // (we share this with other code at RAD) + #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file + typedef struct + { + stbtt_vertex_type x,y,cx,cy,cx1,cy1; + unsigned char type,padding; + } stbtt_vertex; +#endif + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); +// returns non-zero if nothing is drawn for this glyph + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); +// returns # of vertices and fills *vertices with the pointer to them +// these are expressed in "unscaled" coordinates +// +// The shape is a series of contours. Each one starts with +// a STBTT_moveto, then consists of a series of mixed +// STBTT_lineto and STBTT_curveto segments. A lineto +// draws a line from previous endpoint to its x,y; a curveto +// draws a quadratic bezier from previous endpoint to +// its x,y, using cx,cy as the bezier control point. + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +// frees the data allocated above + +STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); +// fills svg with the character's SVG data. +// returns data size or 0 if SVG not found. + +////////////////////////////////////////////////////////////////////////////// +// +// BITMAP RENDERING +// + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); +// frees the bitmap allocated below + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// allocates a large-enough single-channel 8bpp bitmap and renders the +// specified character/glyph at the specified scale into it, with +// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). +// *width & *height are filled out with the width & height of the bitmap, +// which is stored left-to-right, top-to-bottom. +// +// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap +// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap +// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the +// width and height and positioning info for it first. + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering +// is performed (see stbtt_PackSetOversampling) + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +// get the bbox of the bitmap centered around the glyph origin; so the +// bitmap width is ix1-ix0, height is iy1-iy0, and location to place +// the bitmap top left is (leftSideBearing*scale,iy0). +// (Note that the bitmap uses y-increases-down, but the shape uses +// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel +// shift for the character + +// the following functions are equivalent to the above functions, but operate +// on glyph indices instead of Unicode codepoints (for efficiency) +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); + + +// @TODO: don't expose this structure +typedef struct +{ + int w,h,stride; + unsigned char *pixels; +} stbtt__bitmap; + +// rasterize a shape with quadratic beziers into a bitmap +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC + +////////////////////////////////////////////////////////////////////////////// +// +// Signed Distance Function (or Field) rendering + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); +// frees the SDF bitmap allocated below + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +// These functions compute a discretized SDF field for a single character, suitable for storing +// in a single-channel texture, sampling with bilinear filtering, and testing against +// larger than some threshold to produce scalable fonts. +// info -- the font +// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap +// glyph/codepoint -- the character to generate the SDF for +// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// which allows effects like bit outlines +// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) +// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) +// if positive, > onedge_value is inside; if negative, < onedge_value is inside +// width,height -- output height & width of the SDF bitmap (including padding) +// xoff,yoff -- output origin of the character +// return value -- a 2D array of bytes 0..255, width*height in size +// +// pixel_dist_scale & onedge_value are a scale & bias that allows you to make +// optimal use of the limited 0..255 for your application, trading off precision +// and special effects. SDF values outside the range 0..255 are clamped to 0..255. +// +// Example: +// scale = stbtt_ScaleForPixelHeight(22) +// padding = 5 +// onedge_value = 180 +// pixel_dist_scale = 180/5.0 = 36.0 +// +// This will create an SDF bitmap in which the character is about 22 pixels +// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled +// shape, sample the SDF at each pixel and fill the pixel if the SDF value +// is greater than or equal to 180/255. (You'll actually want to antialias, +// which is beyond the scope of this example.) Additionally, you can compute +// offset outlines (e.g. to stroke the character border inside & outside, +// or only outside). For example, to fill outside the character up to 3 SDF +// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above +// choice of variables maps a range from 5 pixels outside the shape to +// 2 pixels inside the shape to 0..255; this is intended primarily for apply +// outside effects only (the interior range is needed to allow proper +// antialiasing of the font at *smaller* sizes) +// +// The function computes the SDF analytically at each SDF pixel, not by e.g. +// building a higher-res bitmap and approximating it. In theory the quality +// should be as high as possible for an SDF of this size & representation, but +// unclear if this is true in practice (perhaps building a higher-res bitmap +// and computing from that can allow drop-out prevention). +// +// The algorithm has not been optimized at all, so expect it to be slow +// if computing lots of characters or very large sizes. + + + +////////////////////////////////////////////////////////////////////////////// +// +// Finding the right font... +// +// You should really just solve this offline, keep your own tables +// of what font is what, and don't try to get it out of the .ttf file. +// That's because getting it out of the .ttf file is really hard, because +// the names in the file can appear in many possible encodings, in many +// possible languages, and e.g. if you need a case-insensitive comparison, +// the details of that depend on the encoding & language in a complex way +// (actually underspecified in truetype, but also gigantic). +// +// But you can use the provided functions in two possible ways: +// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on +// unicode-encoded names to try to find the font you want; +// you can run this before calling stbtt_InitFont() +// +// stbtt_GetFontNameString() lets you get any of the various strings +// from the file yourself and do your own comparisons on them. +// You have to have called stbtt_InitFont() first. + + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +// returns the offset (not index) of the font that matches, or -1 if none +// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". +// if you use any other flag, use a font name like "Arial"; this checks +// the 'macStyle' header field; i don't know if fonts set this consistently +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +// returns 1/0 whether the first string interpreted as utf8 is identical to +// the second string interpreted as big-endian utf16... useful for strings from next func + +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +// returns the string (which may be big-endian double byte, e.g. for unicode) +// and puts the length in bytes in *length. +// +// some of the values for the IDs are below; for more see the truetype spec: +// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html +// http://www.microsoft.com/typography/otspec/name.htm + +enum { // platformID + STBTT_PLATFORM_ID_UNICODE =0, + STBTT_PLATFORM_ID_MAC =1, + STBTT_PLATFORM_ID_ISO =2, + STBTT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_UNICODE + STBTT_UNICODE_EID_UNICODE_1_0 =0, + STBTT_UNICODE_EID_UNICODE_1_1 =1, + STBTT_UNICODE_EID_ISO_10646 =2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT + STBTT_MS_EID_SYMBOL =0, + STBTT_MS_EID_UNICODE_BMP =1, + STBTT_MS_EID_SHIFTJIS =2, + STBTT_MS_EID_UNICODE_FULL =10 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes + STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, + STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, + STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, + STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 +}; + +enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... + // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs + STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, + STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, + STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, + STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, + STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, + STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D +}; + +enum { // languageID for STBTT_PLATFORM_ID_MAC + STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, + STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, + STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, + STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , + STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , + STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, + STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 +}; + +#ifdef __cplusplus +} +#endif + +#endif // PLUTOVG_STB_TRUETYPE_H + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// IMPLEMENTATION +//// +//// + +#ifdef STB_TRUETYPE_IMPLEMENTATION + +#ifndef STBTT_MAX_OVERSAMPLE +#define STBTT_MAX_OVERSAMPLE 8 +#endif + +#if STBTT_MAX_OVERSAMPLE > 255 +#error "STBTT_MAX_OVERSAMPLE cannot be > 255" +#endif + +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; + +#ifndef STBTT_RASTERIZER_VERSION +#define STBTT_RASTERIZER_VERSION 2 +#endif + +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + +////////////////////////////////////////////////////////////////////////// +// +// stbtt__buf helpers to parse data from file +// + +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; +} + +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; +} + +static void stbtt__buf_seek(stbtt__buf *b, int o) +{ + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; +} + +static void stbtt__buf_skip(stbtt__buf *b, int o) +{ + stbtt__buf_seek(b, b->cursor + o); +} + +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) +{ + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; +} + +static stbtt__buf stbtt__new_buf(const void *p, size_t size) +{ + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8*) p; + r.size = (int) size; + r.cursor = 0; + return r; +} + +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) + +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) +{ + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; + r.data = b->data + o; + r.size = s; + return r; +} + +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) +{ + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); +} + +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) +{ + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) return b0 - 139; + else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) return stbtt__buf_get16(b); + else if (b0 == 29) return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; +} + +static void stbtt__cff_skip_operand(stbtt__buf *b) { + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) +{ + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) op = stbtt__buf_get8(b) | 0x100; + if (op == key) return stbtt__buf_range(b, start, end-start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) +{ + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) +{ + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) +{ + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i*offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +} + +////////////////////////////////////////////////////////////////////////// +// +// accessors to parse data from file +// + +// on platforms that don't allow misaligned reads, if we want to allow +// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE + +#define ttBYTE(p) (* (stbtt_uint8 *) (p)) +#define ttCHAR(p) (* (stbtt_int8 *) (p)) +#define ttFixed(p) ttLONG(p) + +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } + +#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) + +static int stbtt__isfont(stbtt_uint8 *font) +{ + // check the version number + if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF + if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts + return 0; +} + +// @OPTIMIZE: binary search +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) +{ + stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i=0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16*i; + if (stbtt_tag(data+loc+0, tag)) + return ttULONG(data+loc+8); + } + return 0; +} + +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) +{ + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection+8); + if (index >= n) + return -1; + return ttULONG(font_collection+12+index*4); + } + } + return -1; +} + +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) +{ + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + return ttLONG(font_collection+8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) +{ + stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1]+subrsoff); + return stbtt__cff_get_index(&cff); +} + +// since most people won't use this, find this table the first time it's needed +static int stbtt__get_svg(stbtt_fontinfo *info) +{ + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) +{ + stbtt_uint32 cmap, t; + stbtt_int32 i,numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data+t+4); + else + info->numGlyphs = 0xffff; + + info->svg = -1; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch(ttUSHORT(data+encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data+encoding_record+2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + // Mac/iOS has these + // all the encodingIDs are unicode, so we don't bother to check it + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data+info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) +{ + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes-6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges + stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); + stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) + search += rangeShift*2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange*2); + if (unicode_codepoint > end) + search += searchRange*2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start, last; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + last = ttUSHORT(data + endCount + 2*item); + if (unicode_codepoint < start || unicode_codepoint > last) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + + return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data+index_map+12); + stbtt_int32 low,high; + low = 0; high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); + stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); + if ((stbtt_uint32) unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32) unicode_codepoint > end_char) + low = mid+1; + else { + stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); + if (format == 12) + return start_glyph + unicode_codepoint-start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; +} + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) +{ + return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +} + +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) +{ + v->type = type; + v->x = (stbtt_int16) x; + v->y = (stbtt_int16) y; + v->cx = (stbtt_int16) cx; + v->cy = (stbtt_int16) cy; +} + +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) +{ + int g1,g2; + + STBTT_assert(!info->cff.size); + + if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); + } + + return g1==g2 ? -1 : g1; // if length is 0, return -1 +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); + +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; + + if (x0) *x0 = ttSHORT(info->data + g + 2); + if (y0) *y0 = ttSHORT(info->data + g + 4); + if (x1) *x1 = ttSHORT(info->data + g + 6); + if (y1) *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) +{ + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, + stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) +{ + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices=0; + int num_vertices=0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags=0,flagcount; + stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; + stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); + + m = n + 2*numberOfContours; // a loose bound on how many vertices we might need + vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated + + // first load flags + + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off+i].type = flags; + } + + // now load x coordinates + x=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? + } else { + if (!(flags & 16)) { + x = x + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].x = (stbtt_int16) x; + } + + // now load y coordinates + y=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? + } else { + if (!(flags & 32)) { + y = y + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].y = (stbtt_int16) y; + } + + // now convert them to our format + num_vertices=0; + sx = sy = cx = cy = scx = scy = 0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + x = (stbtt_int16) vertices[off+i].x; + y = (stbtt_int16) vertices[off+i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find a point on the curve + // where we can start, and we need to save some state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + // next point is also a curve point, so interpolate an on-point curve + sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; + sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32) vertices[off+i+1].x; + sy = (stbtt_int32) vertices[off+i+1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours+j*2); + ++j; + } else { + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + } else if (numberOfContours < 0) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1,0,0,1,0,0}, m, n; + + flags = ttSHORT(comp); comp+=2; + gidx = ttSHORT(comp); comp+=2; + + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); comp+=2; + mtx[5] = ttSHORT(comp); comp+=2; + } else { + mtx[4] = ttCHAR(comp); comp+=1; + mtx[5] = ttCHAR(comp); comp+=1; + } + } + else { + // @TODO handle matching point + STBTT_assert(0); + } + if (flags & (1<<3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } + + // Find transformation scales. + m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex* v = &comp_verts[i]; + stbtt_vertex_type x,y; + x=v->x; y=v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + x=v->cx; y=v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); + if (!tmp) { + if (vertices) STBTT_free(vertices, info->userdata); + if (comp_verts) STBTT_free(comp_verts, info->userdata); + return 0; + } + if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); + STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); + if (vertices) STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; + } + // More components ? + more = flags & (1<<5); + } + } else { + // numberOfCounters == 0, do nothing + } + + *pvertices = vertices; + return num_vertices; +} + +typedef struct +{ + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; +} stbtt__csctx; + +#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) +{ + if (x > c->max_x || !c->started) c->max_x = x; + if (y > c->max_y || !c->started) c->max_y = y; + if (x < c->min_x || !c->started) c->min_x = x; + if (y < c->min_y || !c->started) c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) +{ + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) +{ + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) +{ + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) +{ + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) +{ + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) +{ + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); +} + +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) +{ + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; + +#define STBTT__CSERR(s) (0) + + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; + + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: // rlineto + if (sp < 2) return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; + + case 0x1F: // hvcurveto + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); + i += 4; + } + break; + + case 0x08: // rrcurveto + if (sp < 6) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x18: // rcurveline + if (sp < 8) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + case 0x19: // rlinecurve + if (sp < 8) return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { f = s[i]; i++; } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); + f = 0.0; + } + break; + + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // FALLTHROUGH + case 0x1D: // callgsubr + if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); + v = (int) s[--sp]; + if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; + + case 0x0B: // return + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + //fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1+dx2+dx3+dx4+dx5; + dy = dy1+dy2+dy3+dy4+dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + default: + return STBTT__CSERR("unimplemented"); + } + } break; + + default: + if (b0 != 255 && b0 != 28 && b0 < 32) + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) sp = 0; + } + return STBTT__CSERR("no endchar"); + +#undef STBTT__CSERR +} + +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) *x0 = r ? c.min_x : 0; + if (y0) *y0 = r ? c.min_y : 0; + if (x1) *x1 = r ? c.max_x : 0; + if (y1) *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) +{ + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); + } else { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); + } +} + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) +{ + stbtt_uint8 *data = info->data + info->kern; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + return ttUSHORT(data+10); +} + +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) +{ + stbtt_uint8 *data = info->data + info->kern; + int k, length; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + length = ttUSHORT(data+10); + if (table_length < length) + length = table_length; + + for (k = 0; k < length; k++) + { + table[k].glyph1 = ttUSHORT(data+18+(k*6)); + table[k].glyph2 = ttUSHORT(data+20+(k*6)); + table[k].advance = ttSHORT(data+22+(k*6)); + } + + return length; +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + l = 0; + r = ttUSHORT(data+10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data+18+(m*6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data+22+(m*6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +{ + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch (coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; + } + } + break; + } + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } + } + break; + } + + default: return -1; // unsupported + } + + return -1; +} + +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) +{ + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch (classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + break; + } + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + break; + } + + default: + return -1; // Unsupported definition type, return an error. + } + + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; +} + +// Define to STBTT_assert(x) if you want to break on unimplemented formats. +#define STBTT_GPOS_TODO_assert(x) + +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i, sti; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i= pairSetCount) return 0; + + needle=glyph2; + r=pairValueCount-1; + l=0; + + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } else + return 0; + break; + } + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + stbtt_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; + } + + default: + return 0; // Unsupported position format + } + } + } + + return 0; +} + +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) +{ + int xAdvance = 0; + + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + + return xAdvance; +} + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) +{ + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +} + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) +{ + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +} + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) +{ + if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); + if (descent) *descent = ttSHORT(info->data+info->hhea + 6); + if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +} + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) +{ + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); + if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); + if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); + return 1; +} + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) +{ + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); +} + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) +{ + int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); + return (float) height / fheight; +} + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) +{ + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; +} + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) +{ + STBTT_free(v, info->userdata); +} + +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) +{ + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); + + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; + + for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; +} + +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) +{ + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; + + if (info->svg == 0) + return 0; + + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } +} + +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) +{ + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +} + +////////////////////////////////////////////////////////////////////////////// +// +// antialiasing software rasterizer +// + +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + // e.g. space character + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels get touched)? + if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); + if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); + if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); + } +} + +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Rasterizer + +typedef struct stbtt__hheap_chunk +{ + struct stbtt__hheap_chunk *next; +} stbtt__hheap_chunk; + +typedef struct stbtt__hheap +{ + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; +} stbtt__hheap; + +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) +{ + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = * (void **) p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; + } +} + +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) +{ + *(void **) p = hh->first_free; + hh->first_free = p; +} + +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) +{ + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } +} + +typedef struct stbtt__edge { + float x0,y0, x1,y1; + int invert; +} stbtt__edge; + + +typedef struct stbtt__active_edge +{ + struct stbtt__active_edge *next; + #if STBTT_RASTERIZER_VERSION==1 + int x,dx; + float ey; + int direction; + #elif STBTT_RASTERIZER_VERSION==2 + float fx,fdx,fdy; + float direction; + float sy; + float ey; + #else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" + #endif +} stbtt__active_edge; + +#if STBTT_RASTERIZER_VERSION == 1 +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX-1) + +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) return z; + + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + + z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; + + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; +} +#elif STBTT_RASTERIZER_VERSION == 2 +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + //STBTT_assert(e->y0 <= start_point); + if (!z) return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#if STBTT_RASTERIZER_VERSION == 1 +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) +{ + // non-zero winding fill + int x0=0, w=0; + + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->direction; + } else { + int x1 = e->x; w += e->direction; + // if we went to zero, we need to draw + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8) max_weight; + } + } + } + } + + e = e->next; + } +} + +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; + + if (result->w > 512) + scanline = (unsigned char *) STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; + + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; + + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s=0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for(;;) { + int changed=0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; + + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); + + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} + +#elif STBTT_RASTERIZER_VERSION == 2 + +// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 +// (i.e. it has already been clipped to those) +static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) +{ + if (y0 == y1) return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) return; + if (y1 < e->sy) return; + if (y0 < e->sy) { + x0 += (x1-x0) * (e->sy - y0) / (y1-y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1-x0) * (e->ey - y1) / (y1-y0); + y1 = e->ey; + } + + if (x0 == x) + STBTT_assert(x1 <= x+1); + else if (x0 == x+1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x+1) + STBTT_assert(x1 >= x+1); + else + STBTT_assert(x1 >= x && x1 <= x+1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1-y0); + else if (x0 >= x+1 && x1 >= x+1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); + scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position + } +} + +static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) +{ + STBTT_assert(top_width >= 0); + STBTT_assert(bottom_width >= 0); + return (top_width + bottom_width) / 2.0f * height; +} + +static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) +{ + return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); +} + +static float stbtt__sized_triangle_area(float height, float width) +{ + return height * width / 2; +} + +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) +{ + float y_bottom = y_top+1; + + while (e) { + // brute force every pixel + + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); + + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); + stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0,sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; + } else { + x_top = x0; + sy0 = y_top; + } + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; + } else { + x_bottom = xb; + sy1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int) x_top == (int) x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int) x_top; + height = (sy1 - sy0) * e->direction; + STBTT_assert(x >= 0 && x < len); + scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); + scanline_fill[x] += height; // everything right of this pixel is filled + } else { + int x,x1,x2; + float y_crossing, y_final, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + } + STBTT_assert(dy >= 0); + STBTT_assert(dx >= 0); + + x1 = (int) x_top; + x2 = (int) x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = y_top + dy * (x1+1 - x0); + + // compute intersection with y axis at x2 + y_final = y_top + dy * (x2 - x0); + + // x1 x_top x2 x_bottom + // y_top +------|-----+------------+------------+--------|---+------------+ + // | | | | | | + // | | | | | | + // sy0 | Txxxxx|............|............|............|............| + // y_crossing | *xxxxx.......|............|............|............| + // | | xxxxx..|............|............|............| + // | | /- xx*xxxx........|............|............| + // | | dy < | xxxxxx..|............|............| + // y_final | | \- | xx*xxx.........|............| + // sy1 | | | | xxxxxB...|............| + // | | | | | | + // | | | | | | + // y_bottom +------------+------------+------------+------------+------------+ + // + // goal is to measure the area covered by '.' in each pixel + + // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 + // @TODO: maybe test against sy1 rather than y_bottom? + if (y_crossing > y_bottom) + y_crossing = y_bottom; + + sign = e->direction; + + // area of the rectangle covered from sy0..y_crossing + area = sign * (y_crossing-sy0); + + // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) + scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); + + // check if final y_crossing is blown up; no test case for this + if (y_final > y_bottom) { + y_final = y_bottom; + dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom + } + + // in second pixel, area covered by line segment found in first pixel + // is always a rectangle 1 wide * the height of that line segment; this + // is exactly what the variable 'area' stores. it also gets a contribution + // from the line segment within it. the THIRD pixel will get the first + // pixel's rectangle contribution, the second pixel's rectangle contribution, + // and its own contribution. the 'own contribution' is the same in every pixel except + // the leftmost and rightmost, a trapezoid that slides down in each pixel. + // the second pixel's contribution to the third pixel will be the + // rectangle 1 wide times the height change in the second pixel, which is dy. + + step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, + // which multiplied by 1-pixel-width is how much pixel area changes for each step in x + // so the area advances by 'step' every time + + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; // area of trapezoid is 1*step/2 + area += step; + } + STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down + STBTT_assert(sy1 > y_final-0.01f); + + // area covered in the last pixel is the rectangle from all the pixels to the left, + // plus the trapezoid filled by the line segment in this pixel all the way to the right edge + scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); + + // the rest of the line is filled based on the total height of the line segment in this pixel + scanline_fill[x2] += sign * (sy1-sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + // note though that this does happen some of the time because + // x_top and x_bottom can be extrapolated at the top & bottom of + // the shape and actually lie outside the bounding box + int x; + for (x=0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any intersection + // with left or right edges can be handled by splitting into two (or three) + // regions. intersections with top & bottom do not necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & right edges, + // then used some simple logic to produce up to three segments in sorted order + // from top-to-bottom. however, this had a problem: if an x edge was epsilon + // across the x border, then the corresponding y position might not be distinct + // from the other y segment, and it might ignored as an empty segment. to avoid + // that, we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x1 && x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); + } + } + } + } + e = e->next; + } +} + +// directly AA rasterize edges w/o supersampling +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0, i; + float scanline_data[129], *scanline, *scanline2; + + STBTT__NOTUSED(vsubsample); + + if (result->w > 64) + scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); + else + scanline = scanline_data; + + scanline2 = scanline + result->w; + + y = off_y; + e[n].y0 = (float) (off_y + result->h) + 1; + + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; + + STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); + + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list + } + } + + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds + // insert at front + z->next = active; + active = z; + } + } + ++e; + } + + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i=0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float) STBTT_fabs(k)*255 + 0.5f; + m = (int) k; + if (m > 255) m = 255; + result->pixels[j*result->stride + i] = (unsigned char) m; + } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + + ++y; + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) + +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) +{ + int i,j; + for (i=1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j-1]; + int c = STBTT__COMPARE(a,b); + if (!c) break; + p[j] = p[j-1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) +{ + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01,c12,c,m,i,j; + + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0],&p[m]); + c12 = STBTT__COMPARE(&p[m],&p[n-1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0],&p[n-1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i=1; + j=n-1; + for(;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;;++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!STBTT__COMPARE(&p[0], &p[j])) break; + } + /* make sure we haven't crossed */ + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n-i)) { + stbtt__sort_edges_quicksort(p,j); + p = p+i; + n = n-i; + } else { + stbtt__sort_edges_quicksort(p+i, n-i); + n = j; + } + } +} + +static void stbtt__sort_edges(stbtt__edge *p, int n) +{ + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); +} + +typedef struct +{ + float x,y; +} stbtt__point; + +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) +{ + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n,i,j,k,m; +#if STBTT_RASTERIZER_VERSION == 1 + int vsubsample = result->h < 8 ? 15 : 5; +#elif STBTT_RASTERIZER_VERSION == 2 + int vsubsample = 1; +#else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel + if (e == 0) return; + n = 0; + + m=0; + for (i=0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i]-1; + for (k=0; k < wcount[i]; j=k++) { + int a=k,b=j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a=j,b=k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } + + // now sort the edges by their highest point (should snap to integer, and then by x) + //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); + + // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + + STBTT_free(e, userdata); +} + +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) +{ + if (!points) return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; +} + +// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) +{ + // midpoint + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + // versus directly drawn line + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA + stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x2,y2); + *num_points = *num_points+1; + } + return 1; +} + +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) +{ + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1-x0; + float dy0 = y1-y0; + float dx1 = x2-x1; + float dy1 = y2-y1; + float dx2 = x3-x2; + float dy2 = y3-y2; + float dx = x3-x0; + float dy = y3-y0; + float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); + float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); + float flatness_squared = longlen*longlen-shortlen*shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0+x1)/2; + float y01 = (y0+y1)/2; + float x12 = (x1+x2)/2; + float y12 = (y1+y2)/2; + float x23 = (x2+x3)/2; + float y23 = (y2+y3)/2; + + float xa = (x01+x12)/2; + float ya = (y01+y12)/2; + float xb = (x12+x23)/2; + float yb = (y12+y23)/2; + + float mx = (xa+xb)/2; + float my = (ya+yb)/2; + + stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x3,y3); + *num_points = *num_points+1; + } +} + +// returns number of contours +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) +{ + stbtt__point *points=0; + int num_points=0; + + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i,n=0,start=0, pass; + + // count how many "moves" there are to get the contour count + for (i=0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; + + *num_contours = n; + if (n == 0) return 0; + + *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + // make two passes through the points so we don't need to realloc + for (pass=0; pass < 2; ++pass) { + float x=0,y=0; + if (pass == 1) { + points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); + if (points == NULL) goto error; + } + num_points = 0; + n= -1; + for (i=0; i < num_verts; ++i) { + switch (vertices[i].type) { + case STBTT_vmove: + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x,y); + break; + case STBTT_vline: + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vcurve: + stbtt__tesselate_curve(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + } + } + (*contour_lengths)[n] = num_points - start; + } + + return points; +error: + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; +} + +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) +{ + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } +} + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + int ix0,iy0,ix1,iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error + + if (width ) *width = gbm.w; + if (height) *height = gbm.h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; + + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) +{ + int ix0,iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; + + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + + STBTT_free(vertices, info->userdata); +} + +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) +{ + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +} + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-CRAPPY packing to keep source code small + +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) +{ + float scale; + int x,y,bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + x=y=1; + bottom_y = 1; + + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + + for (i=0; i < num_chars; ++i) { + int advance, lsb, x0,y0,x1,y1,gw,gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); + gw = x1-x0; + gh = y1-y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x+gw < pw); + STBTT_assert(y+gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); + chardata[i].x0 = (stbtt_int16) x; + chardata[i].y0 = (stbtt_int16) y; + chardata[i].x1 = (stbtt_int16) (x + gw); + chardata[i].y1 = (stbtt_int16) (y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float) x0; + chardata[i].yoff = (float) y0; + x = x + gw + 1; + if (y+gh+1 > bottom_y) + bottom_y = y+gh+1; + } + return bottom_y; +} + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) +{ + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); + + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// rectangle packing replacement routines if you don't have stb_rect_pack.h +// + +#ifndef STB_RECT_PACK_VERSION + +typedef int stbrp_coord; + +//////////////////////////////////////////////////////////////////////////////////// +// // +// // +// COMPILER WARNING ?!?!? // +// // +// // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// // +//////////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int width,height; + int x,y,bottom_y; +} stbrp_context; + +typedef struct +{ + unsigned char x; +} stbrp_node; + +struct stbrp_rect +{ + stbrp_coord x,y; + int id,w,h,was_packed; +}; + +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) +{ + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) +{ + int i; + for (i=0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for ( ; i < num_rects; ++i) + rects[i].was_packed = 0; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If +// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) +{ + stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) STBTT_free(context, alloc_context); + if (nodes != NULL) STBTT_free(nodes , alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; + + stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + + if (pixels) + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + + return 1; +} + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) +{ + STBTT_free(spc->nodes , spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) +{ + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) +{ + spc->skip_missing = skip; +} + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char) (total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < h; ++i) { + STBTT_assert(pixels[i*stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + + pixels += 1; + } +} + +static float stbtt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k; + int missing_glyph_added = 0; + + k=0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char) spc->h_oversample; + ranges[i].v_oversample = (unsigned char) spc->v_oversample; + for (j=0; j < ranges[i].num_chars; ++j) { + int x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + if (glyph == 0) + missing_glyph_added = 1; + } + ++k; + } + } + + return k; +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, + output, + out_w - (prefilter_x - 1), + out_h - (prefilter_y - 1), + out_stride, + scale_x, + scale_y, + shift_x, + shift_y, + glyph); + + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k, missing_glyph = -1, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h,recip_v,sub_x,sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j=0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord) spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + &x0,&y0,&x1,&y1); + stbtt_MakeGlyphBitmapSubpixel(info, + spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w - spc->h_oversample+1, + r->h - spc->v_oversample+1, + spc->stride_in_bytes, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + + bc->x0 = (stbtt_int16) r->x; + bc->y0 = (stbtt_int16) r->y; + bc->x1 = (stbtt_int16) (r->x + r->w); + bc->y1 = (stbtt_int16) (r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; + } else { + return_value = 0; // if any fail, report failure + } + + ++k; + } + } + + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; +} + +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) +{ + stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); +} + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) +{ + stbtt_fontinfo info; + int i,j,n, return_value = 1; + //stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; + + // flag all characters as NOT packed + for (i=0; i < num_ranges; ++i) + for (j=0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = + ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i=0; i < num_ranges; ++i) + n += ranges[i].num_chars; + + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; + + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + + stbtt_PackFontRangesPackRects(spc, rects, n); + + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + + STBTT_free(rects, spc->user_allocator_context); + return return_value; +} + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) +{ + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +} + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) +{ + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float) i_ascent * scale; + *descent = (float) i_descent * scale; + *lineGap = (float) i_lineGap * scale; +} + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) +{ + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; + + if (align_to_integer) { + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// sdf computation +// + +#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) + +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) +{ + float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; + float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; + float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; + float roperp = orig[1]*ray[0] - orig[0]*ray[1]; + + float a = q0perp - 2*q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; + + float s0 = 0., s1 = 0.; + int num_s = 0; + + if (a != 0.0) { + float discr = b*b - a*c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float) STBTT_sqrt(discr); + s0 = (b+d) * rcpna; + s1 = (b-d) * rcpna; + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) s0 = s1; + ++num_s; + } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0]*rayn_x + q0[1]*rayn_y; + float q1d = q1[0]*rayn_x + q1[1]*rayn_y; + float q2d = q2[0]*rayn_x + q2[1]*rayn_y; + float rod = orig[0]*rayn_x + orig[1]*rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; + hits[0][1] = a*s0+b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; + hits[1][1] = a*s1+b; + return 2; + } else { + return 1; + } + } +} + +static int equal(float *a, float *b) +{ + return (a[0] == b[0] && a[1] == b[1]); +} + +static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) +{ + int i; + float orig[2], ray[2] = { 1, 0 }; + float y_frac; + int winding = 0; + + // make sure y never passes through a vertex of the shape + y_frac = (float) STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; + + orig[0] = x; + orig[1] = y; + + // test a ray from (-infinity,y) to (x,y) + for (i=0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; + int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; + int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; + int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; + int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); + int by = STBTT_max(y0,STBTT_max(y1,y2)); + if (y > ay && y < by && x > ax) { + float q0[2],q1[2],q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0,q1) || equal(q1,q2)) { + x0 = (int)verts[i-1].x; + y0 = (int)verts[i-1].y; + x1 = (int)verts[i ].x; + y1 = (int)verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } + } + } + } + return winding; +} + +static float stbtt__cuberoot( float x ) +{ + if (x<0) + return -(float) STBTT_pow(-x,1.0f/3.0f); + else + return (float) STBTT_pow( x,1.0f/3.0f); +} + +// x^3 + a*x^2 + b*x + c = 0 +static int stbtt__solve_cubic(float a, float b, float c, float* r) +{ + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; + float p3 = p*p*p; + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); + float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); + + //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? + //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); + //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } +} + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + float scale_x = scale, scale_y = scale; + int ix0,iy0,ix1,iy1; + int w,h; + unsigned char *data; + + if (scale == 0) return NULL; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; + + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; + + w = (ix1 - ix0); + h = (iy1 - iy0); + + if (width ) *width = w; + if (height) *height = h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + // invert for y-downwards bitmaps + scale_y = -scale_y; + + { + int x,y,i,j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *) STBTT_malloc(w * h, info->userdata); + precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); + + for (i=0,j=num_verts-1; i < num_verts; j=i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; + float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); + precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; + float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; + float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float len2 = bx*bx + by*by; + if (len2 != 0.0f) + precompute[i] = 1.0f / (bx*bx + by*by); + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } + + for (y=iy0; y < iy1; ++y) { + for (x=ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float) x + 0.5f; + float sy = (float) y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); + + int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path + + for (i=0; i < num_verts; ++i) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + + if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + // coarse culling against bbox + //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) + dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1-x0, dy = y1-y0; + float px = x0-sx, py = y0-sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy + // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px*dx + py*dy) / (dx*dx + dy*dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; + } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; + float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; + float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); + float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); + float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); + float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); + // coarse culling against bbox to avoid computing cubic unnecessarily + if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { + int num=0; + float ax = x1-x0, ay = y1-y0; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3] = {0.f,0.f,0.f}; + float px,py,t,it,dist2; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula + float a = 3*(ax*bx + ay*by); + float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); + float c = mx*ax+my*ay; + if (a == 0.0) { // if a is 0, it's linear + if (b != 0.0) { + res[num++] = -c/b; + } + } else { + float discriminant = b*b - 4*a*c; + if (discriminant < 0) + num = 0; + else { + float root = (float) STBTT_sqrt(discriminant); + res[0] = (-b - root)/(2*a); + res[1] = (-b + root)/(2*a); + num = 2; // don't bother distinguishing 1-solution case, as code below will still work + } + } + } else { + float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point + float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; + float d = (mx*ax+my*ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; + } + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; +} + +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// font name matching -- recommended not to use this +// + +// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{ + stbtt_int32 i=0; + + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0]*256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) return -1; + if (s1[i++] != ch) return -1; + } else if (ch < 0x800) { + if (i+1 >= len1) return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2]*256 + s2[3]; + if (i+3 >= len1) return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; + s2 += 2; // plus another 2 below + len2 -= 2; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i+2 >= len1) return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; + } + s2 += 2; + len2 -= 2; + } + return i; +} + +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +{ + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +} + +// returns results in whatever encoding you request... but note that 2-byte encodings +// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) +{ + stbtt_int32 i,count,stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return NULL; + + count = ttUSHORT(fc+nm+2); + stringOffset = nm + ttUSHORT(fc+nm+4); + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) + && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { + *length = ttUSHORT(fc+loc+8); + return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); + } + } + return NULL; +} + +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) +{ + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc+nm+2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); + + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc+loc+6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc+loc+8); + stbtt_int32 off = ttUSHORT(fc+loc+10); + + // check if there's a prefix match + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & language + if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { + slen = ttUSHORT(fc+loc+12+8); + off = ttUSHORT(fc+loc+12+10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) + return 1; + } + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } + } + + // @TODO handle other encodings + } + } + return 0; +} + +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) +{ + stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); + stbtt_uint32 nm,hd; + if (!stbtt__isfont(fc+offset)) return 0; + + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; + } + + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return 0; + + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } + + return 0; +} + +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) +{ + stbtt_int32 i; + for (i=0;;++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) return off; + if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) + return off; + } +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, + float pixel_height, unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, stbtt_bakedchar *chardata) +{ + return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +} + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) +{ + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +} + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) +{ + return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +} + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) +{ + return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +} + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) +{ + return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +} + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +{ + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif // STB_TRUETYPE_IMPLEMENTATION + + +// FULL VERSION HISTORY +// +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) allow user-defined fabs() replacement +// fix memory leak if fontsize=0.0 +// fix warning from duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// allow PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) +// also more precise AA rasterizer, except if shapes overlap +// remove need for STBTT_sort +// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC +// 1.04 (2015-04-15) typo in example +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes +// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ +// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// non-oversampled; STBTT_POINT_SIZE for packed case only +// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling +// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) +// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID +// 0.8b (2014-07-07) fix a warning +// 0.8 (2014-05-25) fix a few more warnings +// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back +// 0.6c (2012-07-24) improve documentation +// 0.6b (2012-07-20) fix a few more warnings +// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, +// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty +// 0.5 (2011-12-09) bugfixes: +// subpixel glyph renderer computed wrong bounding box +// first vertex of shape can be off-curve (FreeSans) +// 0.4b (2011-12-03) fixed an error in the font baking example +// 0.4 (2011-12-01) kerning, subpixel rendering (tor) +// bugfixes for: +// codepoint-to-glyph conversion using table fmt=12 +// codepoint-to-glyph conversion using table fmt=4 +// stbtt_GetBakedQuad with non-square texture (Zer) +// updated Hello World! sample to use kerning and subpixel +// fixed some warnings +// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) +// userdata, malloc-from-userdata, non-zero fill (stb) +// 0.2 (2009-03-11) Fix unsigned/signed char warnings +// 0.1 (2009-03-09) First public release +// + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-surface.c b/vendor/lunasvg/3rdparty/plutovg/plutovg-surface.c new file mode 100644 index 0000000000..79263cec4d --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-surface.c @@ -0,0 +1,300 @@ +#include "plutovg-private.h" +#include "plutovg-utils.h" + +#define STB_IMAGE_WRITE_STATIC +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "plutovg-stb-image-write.h" + +#define STB_IMAGE_STATIC +#define STB_IMAGE_IMPLEMENTATION +#include "plutovg-stb-image.h" + +static plutovg_surface_t* plutovg_surface_create_uninitialized(int width, int height) +{ + if(width > STBI_MAX_DIMENSIONS || height > STBI_MAX_DIMENSIONS) + return NULL; + const size_t size = width * height * 4; + plutovg_surface_t* surface = malloc(size + sizeof(plutovg_surface_t)); + if(surface == NULL) + return NULL; + surface->ref_count = 1; + surface->width = width; + surface->height = height; + surface->stride = width * 4; + surface->data = (uint8_t*)(surface + 1); + return surface; +} + +plutovg_surface_t* plutovg_surface_create(int width, int height) +{ + plutovg_surface_t* surface = plutovg_surface_create_uninitialized(width, height); + if(surface) + memset(surface->data, 0, surface->height * surface->stride); + return surface; +} + +plutovg_surface_t* plutovg_surface_create_for_data(unsigned char* data, int width, int height, int stride) +{ + plutovg_surface_t* surface = malloc(sizeof(plutovg_surface_t)); + surface->ref_count = 1; + surface->width = width; + surface->height = height; + surface->stride = stride; + surface->data = data; + return surface; +} + +static plutovg_surface_t* plutovg_surface_load_from_image(stbi_uc* image, int width, int height) +{ + plutovg_surface_t* surface = plutovg_surface_create_uninitialized(width, height); + if(surface) + plutovg_convert_rgba_to_argb(surface->data, image, surface->width, surface->height, surface->stride); + stbi_image_free(image); + return surface; +} + +plutovg_surface_t* plutovg_surface_load_from_image_file(const char* filename) +{ + int width, height, channels; + stbi_uc* image = stbi_load(filename, &width, &height, &channels, STBI_rgb_alpha); + if(image == NULL) + return NULL; + return plutovg_surface_load_from_image(image, width, height); +} + +plutovg_surface_t* plutovg_surface_load_from_image_data(const void* data, int length) +{ + int width, height, channels; + stbi_uc* image = stbi_load_from_memory(data, length, &width, &height, &channels, STBI_rgb_alpha); + if(image == NULL) + return NULL; + return plutovg_surface_load_from_image(image, width, height); +} + +static const uint8_t base64_table[128] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, + 0x3C, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +plutovg_surface_t* plutovg_surface_load_from_image_base64(const char* data, int length) +{ + plutovg_surface_t* surface = NULL; + uint8_t* output_data = NULL; + size_t output_length = 0; + + size_t equals_sign_count = 0; + size_t sidx = 0; + size_t didx = 0; + + if(length == -1) + length = strlen(data); + output_data = malloc(length); + if(output_data == NULL) + return NULL; + for(int i = 0; i < length; ++i) { + uint8_t cc = data[i]; + if(cc == '=') { + ++equals_sign_count; + } else if(cc == '+' || cc == '/' || PLUTOVG_IS_ALNUM(cc)) { + if(equals_sign_count > 0) + goto cleanup; + output_data[output_length++] = base64_table[cc]; + } else if(!PLUTOVG_IS_WS(cc)) { + goto cleanup; + } + } + + if(output_length == 0 || equals_sign_count > 2 || (output_length % 4) == 1) + goto cleanup; + output_length -= (output_length + 3) / 4; + if(output_length == 0) { + goto cleanup; + } + + if(output_length > 1) { + while(didx < output_length - 2) { + output_data[didx + 0] = (((output_data[sidx + 0] << 2) & 255) | ((output_data[sidx + 1] >> 4) & 003)); + output_data[didx + 1] = (((output_data[sidx + 1] << 4) & 255) | ((output_data[sidx + 2] >> 2) & 017)); + output_data[didx + 2] = (((output_data[sidx + 2] << 6) & 255) | ((output_data[sidx + 3] >> 0) & 077)); + sidx += 4; + didx += 3; + } + } + + if(didx < output_length) + output_data[didx] = (((output_data[sidx + 0] << 2) & 255) | ((output_data[sidx + 1] >> 4) & 003)); + if(++didx < output_length) { + output_data[didx] = (((output_data[sidx + 1] << 4) & 255) | ((output_data[sidx + 2] >> 2) & 017)); + } + + surface = plutovg_surface_load_from_image_data(output_data, output_length); +cleanup: + free(output_data); + return surface; +} + +plutovg_surface_t* plutovg_surface_reference(plutovg_surface_t* surface) +{ + if(surface == NULL) + return NULL; + ++surface->ref_count; + return surface; +} + +void plutovg_surface_destroy(plutovg_surface_t* surface) +{ + if(surface == NULL) + return; + if(--surface->ref_count == 0) { + free(surface); + } +} + +int plutovg_surface_get_reference_count(const plutovg_surface_t* surface) +{ + if(surface) + return surface->ref_count; + return 0; +} + +unsigned char* plutovg_surface_get_data(const plutovg_surface_t* surface) +{ + return surface->data; +} + +int plutovg_surface_get_width(const plutovg_surface_t* surface) +{ + return surface->width; +} + +int plutovg_surface_get_height(const plutovg_surface_t* surface) +{ + return surface->height; +} + +int plutovg_surface_get_stride(const plutovg_surface_t* surface) +{ + return surface->stride; +} + +void plutovg_surface_clear(plutovg_surface_t* surface, const plutovg_color_t* color) +{ + uint32_t pixel = plutovg_premultiply_argb(plutovg_color_to_argb32(color)); + for(int y = 0; y < surface->height; y++) { + uint32_t* pixels = (uint32_t*)(surface->data + surface->stride * y); + plutovg_memfill32(pixels, surface->width, pixel); + } +} + +static void plutovg_surface_write_begin(const plutovg_surface_t* surface) +{ + plutovg_convert_argb_to_rgba(surface->data, surface->data, surface->width, surface->height, surface->stride); +} + +static void plutovg_surface_write_end(const plutovg_surface_t* surface) +{ + plutovg_convert_rgba_to_argb(surface->data, surface->data, surface->width, surface->height, surface->stride); +} + +bool plutovg_surface_write_to_png(const plutovg_surface_t* surface, const char* filename) +{ + plutovg_surface_write_begin(surface); + int success = stbi_write_png(filename, surface->width, surface->height, 4, surface->data, surface->stride); + plutovg_surface_write_end(surface); + return success; +} + +bool plutovg_surface_write_to_jpg(const plutovg_surface_t* surface, const char* filename, int quality) +{ + plutovg_surface_write_begin(surface); + int success = stbi_write_jpg(filename, surface->width, surface->height, 4, surface->data, quality); + plutovg_surface_write_end(surface); + return success; +} + +bool plutovg_surface_write_to_png_stream(const plutovg_surface_t* surface, plutovg_write_func_t write_func, void* closure) +{ + plutovg_surface_write_begin(surface); + int success = stbi_write_png_to_func(write_func, closure, surface->width, surface->height, 4, surface->data, surface->stride); + plutovg_surface_write_end(surface); + return success; +} + +bool plutovg_surface_write_to_jpg_stream(const plutovg_surface_t* surface, plutovg_write_func_t write_func, void* closure, int quality) +{ + plutovg_surface_write_begin(surface); + int success = stbi_write_jpg_to_func(write_func, closure, surface->width, surface->height, 4, surface->data, quality); + plutovg_surface_write_end(surface); + return success; +} + +void plutovg_convert_argb_to_rgba(unsigned char* dst, const unsigned char* src, int width, int height, int stride) +{ + for(int y = 0; y < height; y++) { + const uint32_t* src_row = (const uint32_t*)(src + stride * y); + unsigned char* dst_row = dst + stride * y; + for(int x = 0; x < width; x++) { + uint32_t pixel = src_row[x]; + uint32_t a = (pixel >> 24) & 0xFF; + if(a == 0) { + *dst_row++ = 0; + *dst_row++ = 0; + *dst_row++ = 0; + *dst_row++ = 0; + } else { + uint32_t r = (pixel >> 16) & 0xFF; + uint32_t g = (pixel >> 8) & 0xFF; + uint32_t b = (pixel >> 0) & 0xFF; + if(a != 255) { + r = (r * 255) / a; + g = (g * 255) / a; + b = (b * 255) / a; + } + + *dst_row++ = r; + *dst_row++ = g; + *dst_row++ = b; + *dst_row++ = a; + } + } + } +} + +void plutovg_convert_rgba_to_argb(unsigned char* dst, const unsigned char* src, int width, int height, int stride) +{ + for(int y = 0; y < height; y++) { + const unsigned char* src_row = src + stride * y; + uint32_t* dst_row = (uint32_t*)(dst + stride * y); + for(int x = 0; x < width; x++) { + uint32_t a = src_row[4 * x + 3]; + if(a == 0) { + dst_row[x] = 0x00000000; + } else { + uint32_t r = src_row[4 * x + 0]; + uint32_t g = src_row[4 * x + 1]; + uint32_t b = src_row[4 * x + 2]; + if(a != 255) { + r = (r * a) / 255; + g = (g * a) / 255; + b = (b * a) / 255; + } + + dst_row[x] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + } +} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg-utils.h b/vendor/lunasvg/3rdparty/plutovg/plutovg-utils.h new file mode 100644 index 0000000000..585d8fb1a3 --- /dev/null +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg-utils.h @@ -0,0 +1,211 @@ +#ifndef PLUTOVG_UTILS_H +#define PLUTOVG_UTILS_H + +#include +#include +#include +#include +#include +#include +#include + +#define PLUTOVG_IS_NUM(c) ((c) >= '0' && (c) <= '9') +#define PLUTOVG_IS_ALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) +#define PLUTOVG_IS_ALNUM(c) (PLUTOVG_IS_ALPHA(c) || PLUTOVG_IS_NUM(c)) +#define PLUTOVG_IS_WS(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r') + +#define plutovg_min(a, b) ((a) < (b) ? (a) : (b)) +#define plutovg_max(a, b) ((a) > (b) ? (a) : (b)) +#define plutovg_clamp(v, lo, hi) ((v) < (lo) ? (lo) : (hi) < (v) ? (hi) : (v)) + +#define plutovg_alpha(c) (((c) >> 24) & 0xff) +#define plutovg_red(c) (((c) >> 16) & 0xff) +#define plutovg_green(c) (((c) >> 8) & 0xff) +#define plutovg_blue(c) (((c) >> 0) & 0xff) + +#define plutovg_array_init(array) \ + do { \ + (array).data = NULL; \ + (array).size = 0; \ + (array).capacity = 0; \ + } while(0) + +#define plutovg_array_ensure(array, count) \ + do { \ + if((array).size + (count) > (array).capacity) { \ + int capacity = (array).size + (count); \ + int newcapacity = (array).capacity == 0 ? 8 : (array).capacity; \ + while(newcapacity < capacity) { newcapacity *= 2; } \ + (array).data = realloc((array).data, newcapacity * sizeof((array).data[0])); \ + (array).capacity = newcapacity; \ + } \ + } while(0) + +#define plutovg_array_append_data(array, newdata, count) \ + do { \ + if(newdata && count > 0) { \ + plutovg_array_ensure(array, count); \ + memcpy((array).data + (array).size, newdata, (count) * sizeof((newdata)[0])); \ + (array).size += count; \ + } \ + } while(0) + +#define plutovg_array_append(array, other) plutovg_array_append_data(array, (other).data, (other).size) +#define plutovg_array_clear(array) ((array).size = 0) +#define plutovg_array_destroy(array) free((array).data) + +static inline uint32_t plutovg_premultiply_argb(uint32_t color) +{ + uint32_t a = plutovg_alpha(color); + uint32_t r = plutovg_red(color); + uint32_t g = plutovg_green(color); + uint32_t b = plutovg_blue(color); + if(a != 255) { + r = (r * a) / 255; + g = (g * a) / 255; + b = (b * a) / 255; + } + + return (a << 24) | (r << 16) | (g << 8) | (b); +} + +static inline bool plutovg_parse_number(const char** begin, const char* end, float* number) +{ + const char* it = *begin; + float integer = 0; + float fraction = 0; + float exponent = 0; + int sign = 1; + int expsign = 1; + + if(it < end && *it == '+') { + ++it; + } else if(it < end && *it == '-') { + ++it; + sign = -1; + } + + if(it >= end || (*it != '.' && !PLUTOVG_IS_NUM(*it))) + return false; + if(PLUTOVG_IS_NUM(*it)) { + do { + integer = 10.f * integer + (*it++ - '0'); + } while(it < end && PLUTOVG_IS_NUM(*it)); + } + + if(it < end && *it == '.') { + ++it; + if(it >= end || !PLUTOVG_IS_NUM(*it)) + return false; + float divisor = 1.f; + do { + fraction = 10.f * fraction + (*it++ - '0'); + divisor *= 10.f; + } while(it < end && PLUTOVG_IS_NUM(*it)); + fraction /= divisor; + } + + if(it < end && (*it == 'e' || *it == 'E')) { + ++it; + if(it < end && *it == '+') { + ++it; + } else if(it < end && *it == '-') { + ++it; + expsign = -1; + } + + if(it >= end || !PLUTOVG_IS_NUM(*it)) + return false; + do { + exponent = 10 * exponent + (*it++ - '0'); + } while(it < end && PLUTOVG_IS_NUM(*it)); + } + + *begin = it; + *number = sign * (integer + fraction); + if(exponent) + *number *= powf(10.f, expsign * exponent); + return *number >= -FLT_MAX && *number <= FLT_MAX; +} + +static inline bool plutovg_skip_delim(const char** begin, const char* end, const char delim) +{ + const char* it = *begin; + if(it < end && *it == delim) { + *begin = it + 1; + return true; + } + + return false; +} + +static inline bool plutovg_skip_string(const char** begin, const char* end, const char* data) +{ + const char* it = *begin; + while(it < end && *data && *it == *data) { + ++data; + ++it; + } + + if(*data == '\0') { + *begin = it; + return true; + } + + return false; +} + +static inline bool plutovg_skip_ws(const char** begin, const char* end) +{ + const char* it = *begin; + while(it < end && PLUTOVG_IS_WS(*it)) + ++it; + *begin = it; + return it < end; +} + +static inline bool plutovg_skip_ws_and_delim(const char** begin, const char* end, char delim) +{ + const char* it = *begin; + if(plutovg_skip_ws(&it, end)) { + if(!plutovg_skip_delim(&it, end, delim)) + return false; + plutovg_skip_ws(&it, end); + } else { + return false; + } + + *begin = it; + return it < end; +} + +static inline bool plutovg_skip_ws_and_comma(const char** begin, const char* end) +{ + return plutovg_skip_ws_and_delim(begin, end, ','); +} + +static inline bool plutovg_skip_ws_or_delim(const char** begin, const char* end, char delim, bool* has_delim) +{ + const char* it = *begin; + if(has_delim) + *has_delim = false; + if(plutovg_skip_ws(&it, end)) { + if(plutovg_skip_delim(&it, end, delim)) { + if(has_delim) + *has_delim = true; + plutovg_skip_ws(&it, end); + } + } + + if(it == *begin) + return false; + *begin = it; + return it < end; +} + +static inline bool plutovg_skip_ws_or_comma(const char** begin, const char* end, bool* has_comma) +{ + return plutovg_skip_ws_or_delim(begin, end, ',', has_comma); +} + +#endif // PLUTOVG_UTILS_H diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg.c b/vendor/lunasvg/3rdparty/plutovg/plutovg.c deleted file mode 100644 index 3b357bcbf0..0000000000 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg.c +++ /dev/null @@ -1,495 +0,0 @@ -#include "plutovg-private.h" - -plutovg_surface_t* plutovg_surface_create(int width, int height) -{ - plutovg_surface_t* surface = malloc(sizeof(plutovg_surface_t)); - surface->ref = 1; - surface->owndata = 1; - surface->data = calloc(1, (size_t)(width * height * 4)); - surface->width = width; - surface->height = height; - surface->stride = width * 4; - return surface; -} - -plutovg_surface_t* plutovg_surface_create_for_data(unsigned char* data, int width, int height, int stride) -{ - plutovg_surface_t* surface = malloc(sizeof(plutovg_surface_t)); - surface->ref = 1; - surface->owndata = 0; - surface->data = data; - surface->width = width; - surface->height = height; - surface->stride = stride; - return surface; -} - -plutovg_surface_t* plutovg_surface_reference(plutovg_surface_t* surface) -{ - ++surface->ref; - return surface; -} - -void plutovg_surface_destroy(plutovg_surface_t* surface) -{ - if(surface==NULL) - return; - - if(--surface->ref==0) - { - if(surface->owndata) - free(surface->data); - free(surface); - } -} - -int plutovg_surface_get_reference_count(const plutovg_surface_t* surface) -{ - return surface->ref; -} - -unsigned char* plutovg_surface_get_data(const plutovg_surface_t* surface) -{ - return surface->data; -} - -int plutovg_surface_get_width(const plutovg_surface_t* surface) -{ - return surface->width; -} - -int plutovg_surface_get_height(const plutovg_surface_t* surface) -{ - return surface->height; -} - -int plutovg_surface_get_stride(const plutovg_surface_t* surface) -{ - return surface->stride; -} - -plutovg_state_t* plutovg_state_create(void) -{ - plutovg_state_t* state = malloc(sizeof(plutovg_state_t)); - state->clippath = NULL; - plutovg_paint_init(&state->paint); - plutovg_matrix_init_identity(&state->matrix); - state->winding = plutovg_fill_rule_non_zero; - state->stroke.width = 1.0; - state->stroke.miterlimit = 4.0; - state->stroke.cap = plutovg_line_cap_butt; - state->stroke.join = plutovg_line_join_miter; - state->stroke.dash = NULL; - state->op = plutovg_operator_src_over; - state->opacity = 1.0; - state->next = NULL; - return state; -} - -plutovg_state_t* plutovg_state_clone(const plutovg_state_t* state) -{ - plutovg_state_t* newstate = plutovg_state_create(); - newstate->clippath = plutovg_rle_clone(state->clippath); - plutovg_paint_copy(&newstate->paint, &state->paint); - newstate->matrix = state->matrix; - newstate->winding = state->winding; - newstate->stroke.width = state->stroke.width; - newstate->stroke.miterlimit = state->stroke.miterlimit; - newstate->stroke.cap = state->stroke.cap; - newstate->stroke.join = state->stroke.join; - newstate->stroke.dash = plutovg_dash_clone(state->stroke.dash); - newstate->op = state->op; - newstate->opacity = state->opacity; - newstate->next = NULL; - return newstate; -} - -void plutovg_state_destroy(plutovg_state_t* state) -{ - plutovg_rle_destroy(state->clippath); - plutovg_paint_destroy(&state->paint); - plutovg_dash_destroy(state->stroke.dash); - free(state); -} - -plutovg_t* plutovg_create(plutovg_surface_t* surface) -{ - plutovg_t* pluto = malloc(sizeof(plutovg_t)); - pluto->ref = 1; - pluto->surface = plutovg_surface_reference(surface); - pluto->state = plutovg_state_create(); - pluto->path = plutovg_path_create(); - pluto->rle = plutovg_rle_create(); - pluto->clippath = NULL; - pluto->clip.x = 0.0; - pluto->clip.y = 0.0; - pluto->clip.w = surface->width; - pluto->clip.h = surface->height; - pluto->outline_data = NULL; - pluto->outline_size = 0; - return pluto; -} - -plutovg_t* plutovg_reference(plutovg_t* pluto) -{ - ++pluto->ref; - return pluto; -} - -void plutovg_destroy(plutovg_t* pluto) -{ - if(pluto==NULL) - return; - - if(--pluto->ref==0) - { - while(pluto->state) - { - plutovg_state_t* state = pluto->state; - pluto->state = state->next; - plutovg_state_destroy(state); - } - - plutovg_surface_destroy(pluto->surface); - plutovg_path_destroy(pluto->path); - plutovg_rle_destroy(pluto->rle); - plutovg_rle_destroy(pluto->clippath); - free(pluto->outline_data); - free(pluto); - } -} - -int plutovg_get_reference_count(const plutovg_t* pluto) -{ - return pluto->ref; -} - -void plutovg_save(plutovg_t* pluto) -{ - plutovg_state_t* newstate = plutovg_state_clone(pluto->state); - newstate->next = pluto->state; - pluto->state = newstate; -} - -void plutovg_restore(plutovg_t* pluto) -{ - plutovg_state_t* oldstate = pluto->state; - pluto->state = oldstate->next; - plutovg_state_destroy(oldstate); -} - -plutovg_color_t* plutovg_set_rgb(plutovg_t* pluto, double r, double g, double b) -{ - return plutovg_set_rgba(pluto, r, g, b, 1.0); -} - -plutovg_color_t* plutovg_set_rgba(plutovg_t* pluto, double r, double g, double b, double a) -{ - plutovg_paint_t* paint = &pluto->state->paint; - paint->type = plutovg_paint_type_color; - plutovg_color_init_rgba(&paint->color, r, g, b, a); - return &paint->color; -} - -plutovg_color_t* plutovg_set_color(plutovg_t* pluto, const plutovg_color_t* color) -{ - return plutovg_set_rgba(pluto, color->r, color->g, color->b, color->a); -} - -plutovg_gradient_t* plutovg_set_linear_gradient(plutovg_t* pluto, double x1, double y1, double x2, double y2) -{ - plutovg_paint_t* paint = &pluto->state->paint; - paint->type = plutovg_paint_type_gradient; - plutovg_gradient_init_linear(&paint->gradient, x1, y1, x2, y2); - return &paint->gradient; -} - -plutovg_gradient_t* plutovg_set_radial_gradient(plutovg_t* pluto, double cx, double cy, double cr, double fx, double fy, double fr) -{ - plutovg_paint_t* paint = &pluto->state->paint; - paint->type = plutovg_paint_type_gradient; - plutovg_gradient_init_radial(&paint->gradient, cx, cy, cr, fx, fy, fr); - return &paint->gradient; -} - -plutovg_texture_t* plutovg_set_texture_surface(plutovg_t* pluto, plutovg_surface_t* surface, double x, double y) -{ - plutovg_texture_t* texture = plutovg_set_texture(pluto, surface, plutovg_texture_type_plain); - plutovg_matrix_init_translate(&texture->matrix, x, y); - return texture; -} - -plutovg_texture_t* plutovg_set_texture(plutovg_t* pluto, plutovg_surface_t* surface, plutovg_texture_type_t type) -{ - plutovg_paint_t* paint = &pluto->state->paint; - paint->type = plutovg_paint_type_texture; - plutovg_texture_init(&paint->texture, surface, type); - return &paint->texture; -} - -void plutovg_set_operator(plutovg_t* pluto, plutovg_operator_t op) -{ - pluto->state->op = op; -} - -void plutovg_set_opacity(plutovg_t* pluto, double opacity) -{ - pluto->state->opacity = opacity; -} - -void plutovg_set_fill_rule(plutovg_t* pluto, plutovg_fill_rule_t fill_rule) -{ - pluto->state->winding = fill_rule; -} - -plutovg_operator_t plutovg_get_operator(const plutovg_t* pluto) -{ - return pluto->state->op; -} - -double plutovg_get_opacity(const plutovg_t* pluto) -{ - return pluto->state->opacity; -} - -plutovg_fill_rule_t plutovg_get_fill_rule(const plutovg_t* pluto) -{ - return pluto->state->winding; -} - -void plutovg_set_line_width(plutovg_t* pluto, double width) -{ - pluto->state->stroke.width = width; -} - -void plutovg_set_line_cap(plutovg_t* pluto, plutovg_line_cap_t cap) -{ - pluto->state->stroke.cap = cap; -} - -void plutovg_set_line_join(plutovg_t* pluto, plutovg_line_join_t join) -{ - pluto->state->stroke.join = join; -} - -void plutovg_set_miter_limit(plutovg_t* pluto, double limit) -{ - pluto->state->stroke.miterlimit = limit; -} - -void plutovg_set_dash(plutovg_t* pluto, double offset, const double* data, int size) -{ - plutovg_dash_destroy(pluto->state->stroke.dash); - pluto->state->stroke.dash = plutovg_dash_create(offset, data, size); -} - -double plutovg_get_line_width(const plutovg_t* pluto) -{ - return pluto->state->stroke.width; -} - -plutovg_line_cap_t plutovg_get_line_cap(const plutovg_t* pluto) -{ - return pluto->state->stroke.cap; -} - -plutovg_line_join_t plutovg_get_line_join(const plutovg_t* pluto) -{ - return pluto->state->stroke.join; -} - -double plutovg_get_miter_limit(const plutovg_t* pluto) -{ - return pluto->state->stroke.miterlimit; -} - -void plutovg_translate(plutovg_t* pluto, double x, double y) -{ - plutovg_matrix_translate(&pluto->state->matrix, x, y); -} - -void plutovg_scale(plutovg_t* pluto, double x, double y) -{ - plutovg_matrix_scale(&pluto->state->matrix, x, y); -} - -void plutovg_rotate(plutovg_t* pluto, double radians, double x, double y) -{ - plutovg_matrix_rotate(&pluto->state->matrix, radians, x, y); -} - -void plutovg_transform(plutovg_t* pluto, const plutovg_matrix_t* matrix) -{ - plutovg_matrix_multiply(&pluto->state->matrix, matrix, &pluto->state->matrix); -} - -void plutovg_set_matrix(plutovg_t* pluto, const plutovg_matrix_t* matrix) -{ - pluto->state->matrix = *matrix; -} - -void plutovg_identity_matrix(plutovg_t* pluto) -{ - plutovg_matrix_init_identity(&pluto->state->matrix); -} - -void plutovg_get_matrix(const plutovg_t* pluto, plutovg_matrix_t* matrix) -{ - *matrix = pluto->state->matrix; -} - -void plutovg_move_to(plutovg_t* pluto, double x, double y) -{ - plutovg_path_move_to(pluto->path, x, y); -} - -void plutovg_line_to(plutovg_t* pluto, double x, double y) -{ - plutovg_path_line_to(pluto->path, x, y); -} - -void plutovg_quad_to(plutovg_t* pluto, double x1, double y1, double x2, double y2) -{ - plutovg_path_quad_to(pluto->path, x1, y1, x2, y2); -} - -void plutovg_cubic_to(plutovg_t* pluto, double x1, double y1, double x2, double y2, double x3, double y3) -{ - plutovg_path_cubic_to(pluto->path, x1, y1, x2, y2, x3, y3); -} - -void plutovg_rel_move_to(plutovg_t* pluto, double x, double y) -{ - plutovg_path_rel_move_to(pluto->path, x, y); -} - -void plutovg_rel_line_to(plutovg_t* pluto, double x, double y) -{ - plutovg_path_rel_line_to(pluto->path, x, y); -} - -void plutovg_rel_quad_to(plutovg_t* pluto, double x1, double y1, double x2, double y2) -{ - plutovg_path_rel_quad_to(pluto->path, x1, y1, x2, y2); -} - -void plutovg_rel_cubic_to(plutovg_t* pluto, double x1, double y1, double x2, double y2, double x3, double y3) -{ - plutovg_path_rel_cubic_to(pluto->path, x1, y1, x2, y2, x3, y3); -} - -void plutovg_rect(plutovg_t* pluto, double x, double y, double w, double h) -{ - plutovg_path_add_rect(pluto->path, x, y, w, h); -} - -void plutovg_round_rect(plutovg_t* pluto, double x, double y, double w, double h, double rx, double ry) -{ - plutovg_path_add_round_rect(pluto->path, x, y, w, h, rx, ry); -} - -void plutovg_ellipse(plutovg_t* pluto, double cx, double cy, double rx, double ry) -{ - plutovg_path_add_ellipse(pluto->path, cx, cy, rx, ry); -} - -void plutovg_circle(plutovg_t* pluto, double cx, double cy, double r) -{ - plutovg_ellipse(pluto, cx, cy, r, r); -} - -void plutovg_add_path(plutovg_t* pluto, const plutovg_path_t* path) -{ - plutovg_path_add_path(pluto->path, path, NULL); -} - -void plutovg_new_path(plutovg_t* pluto) -{ - plutovg_path_clear(pluto->path); -} - -void plutovg_close_path(plutovg_t* pluto) -{ - plutovg_path_close(pluto->path); -} - -plutovg_path_t* plutovg_get_path(const plutovg_t* pluto) -{ - return pluto->path; -} - -void plutovg_fill(plutovg_t* pluto) -{ - plutovg_fill_preserve(pluto); - plutovg_new_path(pluto); -} - -void plutovg_stroke(plutovg_t* pluto) -{ - plutovg_stroke_preserve(pluto); - plutovg_new_path(pluto); -} - -void plutovg_clip(plutovg_t* pluto) -{ - plutovg_clip_preserve(pluto); - plutovg_new_path(pluto); -} - -void plutovg_paint(plutovg_t* pluto) -{ - plutovg_state_t* state = pluto->state; - if(state->clippath==NULL && pluto->clippath==NULL) - { - plutovg_path_t* path = plutovg_path_create(); - plutovg_path_add_rect(path, pluto->clip.x, pluto->clip.y, pluto->clip.w, pluto->clip.h); - plutovg_matrix_t matrix; - plutovg_matrix_init_identity(&matrix); - pluto->clippath = plutovg_rle_create(); - plutovg_rle_rasterize(pluto, pluto->clippath, path, &matrix, &pluto->clip, NULL, plutovg_fill_rule_non_zero); - plutovg_path_destroy(path); - } - - plutovg_rle_t* rle = state->clippath ? state->clippath : pluto->clippath; - plutovg_blend(pluto, rle); -} - -void plutovg_fill_preserve(plutovg_t* pluto) -{ - plutovg_state_t* state = pluto->state; - plutovg_rle_clear(pluto->rle); - plutovg_rle_rasterize(pluto, pluto->rle, pluto->path, &state->matrix, &pluto->clip, NULL, state->winding); - plutovg_rle_clip_path(pluto->rle, state->clippath); - plutovg_blend(pluto, pluto->rle); -} - -void plutovg_stroke_preserve(plutovg_t* pluto) -{ - plutovg_state_t* state = pluto->state; - plutovg_rle_clear(pluto->rle); - plutovg_rle_rasterize(pluto, pluto->rle, pluto->path, &state->matrix, &pluto->clip, &state->stroke, plutovg_fill_rule_non_zero); - plutovg_rle_clip_path(pluto->rle, state->clippath); - plutovg_blend(pluto, pluto->rle); -} - -void plutovg_clip_preserve(plutovg_t* pluto) -{ - plutovg_state_t* state = pluto->state; - if(state->clippath) - { - plutovg_rle_clear(pluto->rle); - plutovg_rle_rasterize(pluto, pluto->rle, pluto->path, &state->matrix, &pluto->clip, NULL, state->winding); - plutovg_rle_clip_path(state->clippath, pluto->rle); - } - else - { - state->clippath = plutovg_rle_create(); - plutovg_rle_rasterize(pluto, state->clippath, pluto->path, &state->matrix, &pluto->clip, NULL, state->winding); - } -} - -void plutovg_reset_clip(plutovg_t* pluto) -{ - plutovg_rle_destroy(pluto->state->clippath); - pluto->state->clippath = NULL; -} diff --git a/vendor/lunasvg/3rdparty/plutovg/plutovg.h b/vendor/lunasvg/3rdparty/plutovg/plutovg.h index e9da860e7d..07f6ff6773 100644 --- a/vendor/lunasvg/3rdparty/plutovg/plutovg.h +++ b/vendor/lunasvg/3rdparty/plutovg/plutovg.h @@ -1,257 +1,2316 @@ +/* + * Copyright (c) 2020-2025 Samuel Ugochukwu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + #ifndef PLUTOVG_H #define PLUTOVG_H +#include + #ifdef __cplusplus extern "C" { #endif -typedef struct plutovg_surface plutovg_surface_t; +#if !defined(PLUTOVG_BUILD_STATIC) && (defined(_WIN32) || defined(__CYGWIN__)) +#define PLUTOVG_EXPORT __declspec(dllexport) +#define PLUTOVG_IMPORT __declspec(dllimport) +#elif defined(__GNUC__) && (__GNUC__ >= 4) +#define PLUTOVG_EXPORT __attribute__((__visibility__("default"))) +#define PLUTOVG_IMPORT +#else +#define PLUTOVG_EXPORT +#define PLUTOVG_IMPORT +#endif -plutovg_surface_t* plutovg_surface_create(int width, int height); -plutovg_surface_t* plutovg_surface_create_for_data(unsigned char* data, int width, int height, int stride); -plutovg_surface_t* plutovg_surface_reference(plutovg_surface_t* surface); -void plutovg_surface_destroy(plutovg_surface_t* surface); -int plutovg_surface_get_reference_count(const plutovg_surface_t* surface); -unsigned char* plutovg_surface_get_data(const plutovg_surface_t* surface); -int plutovg_surface_get_width(const plutovg_surface_t* surface); -int plutovg_surface_get_height(const plutovg_surface_t* surface); -int plutovg_surface_get_stride(const plutovg_surface_t* surface); +#ifdef PLUTOVG_BUILD +#define PLUTOVG_API PLUTOVG_EXPORT +#else +#define PLUTOVG_API PLUTOVG_IMPORT +#endif -typedef struct { - double x; - double y; +#define PLUTOVG_VERSION_MAJOR 0 +#define PLUTOVG_VERSION_MINOR 0 +#define PLUTOVG_VERSION_MICRO 13 + +#define PLUTOVG_VERSION_ENCODE(major, minor, micro) (((major) * 10000) + ((minor) * 100) + ((micro) * 1)) +#define PLUTOVG_VERSION PLUTOVG_VERSION_ENCODE(PLUTOVG_VERSION_MAJOR, PLUTOVG_VERSION_MINOR, PLUTOVG_VERSION_MICRO) + +#define PLUTOVG_VERSION_XSTRINGIZE(major, minor, micro) #major"."#minor"."#micro +#define PLUTOVG_VERSION_STRINGIZE(major, minor, micro) PLUTOVG_VERSION_XSTRINGIZE(major, minor, micro) +#define PLUTOVG_VERSION_STRING PLUTOVG_VERSION_STRINGIZE(PLUTOVG_VERSION_MAJOR, PLUTOVG_VERSION_MINOR, PLUTOVG_VERSION_MICRO) + +/** + * @brief Gets the version of the plutovg library. + * @return An integer representing the version of the plutovg library. + */ +PLUTOVG_API int plutovg_version(void); + +/** + * @brief Gets the version of the plutovg library as a string. + * @return A string representing the version of the plutovg library. + */ +PLUTOVG_API const char* plutovg_version_string(void); + +/** + * @brief A function pointer type for a cleanup callback. + * @param closure A pointer to the resource to be cleaned up. + */ +typedef void (*plutovg_destroy_func_t)(void* closure); + +/** + * @brief A function pointer type for a write callback. + * @param closure A pointer to user-defined data or context. + * @param data A pointer to the data to be written. + * @param size The size of the data in bytes. + */ +typedef void (*plutovg_write_func_t)(void* closure, void* data, int size); + +#define PLUTOVG_PI 3.14159265358979323846f +#define PLUTOVG_TWO_PI 6.28318530717958647693f +#define PLUTOVG_HALF_PI 1.57079632679489661923f +#define PLUTOVG_SQRT2 1.41421356237309504880f +#define PLUTOVG_KAPPA 0.55228474983079339840f + +#define PLUTOVG_DEG2RAD(x) ((x) * (PLUTOVG_PI / 180.0f)) +#define PLUTOVG_RAD2DEG(x) ((x) * (180.0f / PLUTOVG_PI)) + +/** + * @brief A structure representing a point in 2D space. + */ +typedef struct plutovg_point { + float x; ///< The x-coordinate of the point. + float y; ///< The y-coordinate of the point. } plutovg_point_t; -typedef struct { - double x; - double y; - double w; - double h; +#define PLUTOVG_MAKE_POINT(x, y) ((plutovg_point_t){x, y}) + +/** + * @brief A structure representing a rectangle in 2D space. + */ +typedef struct plutovg_rect { + float x; ///< The x-coordinate of the top-left corner of the rectangle. + float y; ///< The y-coordinate of the top-left corner of the rectangle. + float w; ///< The width of the rectangle. + float h; ///< The height of the rectangle. } plutovg_rect_t; -void plutovg_rect_init(plutovg_rect_t* rect, double x, double y, double w, double h); -void plutovg_rect_init_zero(plutovg_rect_t* rect); +#define PLUTOVG_MAKE_RECT(x, y, w, h) ((plutovg_rect_t){x, y, w, h}) -typedef struct { - double m00; double m10; - double m01; double m11; - double m02; double m12; +/** + * @brief A structure representing a 2D transformation matrix. + */ +typedef struct plutovg_matrix { + float a; ///< The horizontal scaling factor. + float b; ///< The vertical shearing factor. + float c; ///< The horizontal shearing factor. + float d; ///< The vertical scaling factor. + float e; ///< The horizontal translation offset. + float f; ///< The vertical translation offset. } plutovg_matrix_t; -void plutovg_matrix_init(plutovg_matrix_t* matrix, double m00, double m10, double m01, double m11, double m02, double m12); -void plutovg_matrix_init_identity(plutovg_matrix_t* matrix); -void plutovg_matrix_init_translate(plutovg_matrix_t* matrix, double x, double y); -void plutovg_matrix_init_scale(plutovg_matrix_t* matrix, double x, double y); -void plutovg_matrix_init_shear(plutovg_matrix_t* matrix, double x, double y); -void plutovg_matrix_init_rotate(plutovg_matrix_t* matrix, double radians, double x, double y); -void plutovg_matrix_translate(plutovg_matrix_t* matrix, double x, double y); -void plutovg_matrix_scale(plutovg_matrix_t* matrix, double x, double y); -void plutovg_matrix_shear(plutovg_matrix_t* matrix, double x, double y); -void plutovg_matrix_rotate(plutovg_matrix_t* matrix, double radians, double x, double y); -void plutovg_matrix_multiply(plutovg_matrix_t* matrix, const plutovg_matrix_t* a, const plutovg_matrix_t* b); -int plutovg_matrix_invert(plutovg_matrix_t* matrix); -void plutovg_matrix_map(const plutovg_matrix_t* matrix, double x, double y, double* _x, double* _y); -void plutovg_matrix_map_point(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst); -void plutovg_matrix_map_rect(const plutovg_matrix_t* matrix, const plutovg_rect_t* src, plutovg_rect_t* dst); +#define PLUTOVG_MAKE_MATRIX(a, b, c, d, e, f) ((plutovg_matrix_t){a, b, c, d, e, f}) + +#define PLUTOVG_MAKE_SCALE(x, y) PLUTOVG_MAKE_MATRIX(x, 0, 0, y, 0, 0) +#define PLUTOVG_MAKE_TRANSLATE(x, y) PLUTOVG_MAKE_MATRIX(1, 0, 0, 1, x, y) +#define PLUTOVG_IDENTITY_MATRIX PLUTOVG_MAKE_MATRIX(1, 0, 0, 1, 0, 0) + +/** + * @brief Initializes a 2D transformation matrix. + * @param matrix A pointer to the `plutovg_matrix_t` object to be initialized. + * @param a The horizontal scaling factor. + * @param b The vertical shearing factor. + * @param c The horizontal shearing factor. + * @param d The vertical scaling factor. + * @param e The horizontal translation offset. + * @param f The vertical translation offset. + */ +PLUTOVG_API void plutovg_matrix_init(plutovg_matrix_t* matrix, float a, float b, float c, float d, float e, float f); + +/** + * @brief Initializes a 2D transformation matrix to the identity matrix. + * @param matrix A pointer to the `plutovg_matrix_t` object to be initialized. + */ +PLUTOVG_API void plutovg_matrix_init_identity(plutovg_matrix_t* matrix); + +/** + * @brief Initializes a 2D transformation matrix for translation. + * @param matrix A pointer to the `plutovg_matrix_t` object to be initialized. + * @param tx The translation offset in the x-direction. + * @param ty The translation offset in the y-direction. + */ +PLUTOVG_API void plutovg_matrix_init_translate(plutovg_matrix_t* matrix, float tx, float ty); + +/** + * @brief Initializes a 2D transformation matrix for scaling. + * @param matrix A pointer to the `plutovg_matrix_t` object to be initialized. + * @param sx The scaling factor in the x-direction. + * @param sy The scaling factor in the y-direction. + */ +PLUTOVG_API void plutovg_matrix_init_scale(plutovg_matrix_t* matrix, float sx, float sy); + +/** + * @brief Initializes a 2D transformation matrix for rotation. + * @param matrix A pointer to the `plutovg_matrix_t` object to be initialized. + * @param angle The rotation angle in radians. + */ +PLUTOVG_API void plutovg_matrix_init_rotate(plutovg_matrix_t* matrix, float angle); + +/** + * @brief Initializes a 2D transformation matrix for shearing. + * @param matrix A pointer to the `plutovg_matrix_t` object to be initialized. + * @param shx The shearing factor in the x-direction. + * @param shy The shearing factor in the y-direction. + */ +PLUTOVG_API void plutovg_matrix_init_shear(plutovg_matrix_t* matrix, float shx, float shy); + +/** + * @brief Adds a translation with offsets `tx` and `ty` to the matrix. + * @param matrix A pointer to the `plutovg_matrix_t` object to be modified. + * @param tx The translation offset in the x-direction. + * @param ty The translation offset in the y-direction. + */ +PLUTOVG_API void plutovg_matrix_translate(plutovg_matrix_t* matrix, float tx, float ty); + +/** + * @brief Scales the matrix by factors `sx` and `sy` + * @param matrix A pointer to the `plutovg_matrix_t` object to be modified. + * @param sx The scaling factor in the x-direction. + * @param sy The scaling factor in the y-direction. + */ +PLUTOVG_API void plutovg_matrix_scale(plutovg_matrix_t* matrix, float sx, float sy); + +/** + * @brief Rotates the matrix by the specified angle (in radians). + * @param matrix A pointer to the `plutovg_matrix_t` object to be modified. + * @param angle The rotation angle in radians. + */ +PLUTOVG_API void plutovg_matrix_rotate(plutovg_matrix_t* matrix, float angle); + +/** + * @brief Shears the matrix by factors `shx` and `shy`. + * @param matrix A pointer to the `plutovg_matrix_t` object to be modified. + * @param shx The shearing factor in the x-direction. + * @param shy The shearing factor in the y-direction. + */ +PLUTOVG_API void plutovg_matrix_shear(plutovg_matrix_t* matrix, float shx, float shy); +/** + * @brief Multiplies `left` and `right` matrices and stores the result in `matrix`. + * @note `matrix` can be identical to either `left` or `right`. + * @param matrix A pointer to the `plutovg_matrix_t` object to store the result. + * @param left A pointer to the first `plutovg_matrix_t` matrix. + * @param right A pointer to the second `plutovg_matrix_t` matrix. + */ +PLUTOVG_API void plutovg_matrix_multiply(plutovg_matrix_t* matrix, const plutovg_matrix_t* left, const plutovg_matrix_t* right); + +/** + * @brief Calculates the inverse of `matrix` and stores it in `inverse`. + * + * If `inverse` is `NULL`, the function only checks if the matrix is invertible. + * + * @note `matrix` and `inverse` can be identical. + * @param matrix A pointer to the `plutovg_matrix_t` object to invert. + * @param inverse A pointer to the `plutovg_matrix_t` object to store the result, or `NULL`. + * @return `true` if the matrix is invertible; `false` otherwise. + */ +PLUTOVG_API bool plutovg_matrix_invert(const plutovg_matrix_t* matrix, plutovg_matrix_t* inverse); + +/** + * @brief Transforms the point `(x, y)` using `matrix` and stores the result in `(xx, yy)`. + * @param matrix A pointer to a `plutovg_matrix_t` object. + * @param x The x-coordinate of the point to transform. + * @param y The y-coordinate of the point to transform. + * @param xx A pointer to store the transformed x-coordinate. + * @param yy A pointer to store the transformed y-coordinate. + */ +PLUTOVG_API void plutovg_matrix_map(const plutovg_matrix_t* matrix, float x, float y, float* xx, float* yy); + +/** + * @brief Transforms the `src` point using `matrix` and stores the result in `dst`. + * @note `src` and `dst` can be identical. + * @param matrix A pointer to a `plutovg_matrix_t` object. + * @param src A pointer to the `plutovg_point_t` object to transform. + * @param dst A pointer to the `plutovg_point_t` to store the transformed point. + */ +PLUTOVG_API void plutovg_matrix_map_point(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst); + +/** + * @brief Transforms an array of `src` points using `matrix` and stores the results in `dst`. + * @note `src` and `dst` can be identical. + * @param matrix A pointer to a `plutovg_matrix_t` object. + * @param src A pointer to the array of `plutovg_point_t` objects to transform. + * @param dst A pointer to the array of `plutovg_point_t` to store the transformed points. + * @param count The number of points to transform. + */ +PLUTOVG_API void plutovg_matrix_map_points(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst, int count); + +/** + * @brief Transforms the `src` rectangle using `matrix` and stores the result in `dst`. + * @note `src` and `dst` can be identical. + * @param matrix A pointer to a `plutovg_matrix_t` object. + * @param src A pointer to the `plutovg_rect_t` object to transform. + * @param dst A pointer to the `plutovg_rect_t` to store the transformed rectangle. + */ +PLUTOVG_API void plutovg_matrix_map_rect(const plutovg_matrix_t* matrix, const plutovg_rect_t* src, plutovg_rect_t* dst); + +/** + * @brief Parses an SVG transform string into a matrix. + * + * @param matrix A pointer to a `plutovg_matrix_t` object to store the result. + * @param data Input SVG transform string. + * @param length Length of the string, or `-1` if null-terminated. + * + * @return `true` on success, `false` on failure. + */ +PLUTOVG_API bool plutovg_matrix_parse(plutovg_matrix_t* matrix, const char* data, int length); + +/** + * @brief Represents a 2D path for drawing operations. + */ typedef struct plutovg_path plutovg_path_t; -typedef enum { - plutovg_path_element_move_to, - plutovg_path_element_line_to, - plutovg_path_element_cubic_to, - plutovg_path_element_close +/** + * @brief Enumeration defining path commands. + */ +typedef enum plutovg_path_command { + PLUTOVG_PATH_COMMAND_MOVE_TO, ///< Moves the current point to a new position. + PLUTOVG_PATH_COMMAND_LINE_TO, ///< Draws a straight line to a new point. + PLUTOVG_PATH_COMMAND_CUBIC_TO, ///< Draws a cubic Bézier curve to a new point. + PLUTOVG_PATH_COMMAND_CLOSE ///< Closes the current path by drawing a line to the starting point. +} plutovg_path_command_t; + +/** + * @brief Union representing a path element. + * + * A path element can be a command with a length or a coordinate point. + * Each command type in the path element array is followed by a specific number of points: + * - `PLUTOVG_PATH_COMMAND_MOVE_TO`: 1 point + * - `PLUTOVG_PATH_COMMAND_LINE_TO`: 1 point + * - `PLUTOVG_PATH_COMMAND_CUBIC_TO`: 3 points + * - `PLUTOVG_PATH_COMMAND_CLOSE`: 1 point + * + * @example + * const plutovg_path_element_t* elements; + * int count = plutovg_path_get_elements(path, &elements); + * for(int i = 0; i < count; i += elements[i].header.length) { + * plutovg_path_command_t command = elements[i].header.command; + * switch(command) { + * case PLUTOVG_PATH_COMMAND_MOVE_TO: + * printf("MoveTo: %g %g\n", elements[i + 1].point.x, elements[i + 1].point.y); + * break; + * case PLUTOVG_PATH_COMMAND_LINE_TO: + * printf("LineTo: %g %g\n", elements[i + 1].point.x, elements[i + 1].point.y); + * break; + * case PLUTOVG_PATH_COMMAND_CUBIC_TO: + * printf("CubicTo: %g %g %g %g %g %g\n", + * elements[i + 1].point.x, elements[i + 1].point.y, + * elements[i + 2].point.x, elements[i + 2].point.y, + * elements[i + 3].point.x, elements[i + 3].point.y); + * break; + * case PLUTOVG_PATH_COMMAND_CLOSE: + * printf("Close: %g %g\n", elements[i + 1].point.x, elements[i + 1].point.y); + * break; + * } + * } + */ +typedef union plutovg_path_element { + struct { + plutovg_path_command_t command; ///< The path command. + int length; ///< Number of elements including the header. + } header; ///< Header for path commands. + plutovg_point_t point; ///< A coordinate point in the path. } plutovg_path_element_t; -plutovg_path_t* plutovg_path_create(void); -plutovg_path_t* plutovg_path_reference(plutovg_path_t* path); -void plutovg_path_destroy(plutovg_path_t* path); -int plutovg_path_get_reference_count(const plutovg_path_t* path); -void plutovg_path_move_to(plutovg_path_t* path, double x, double y); -void plutovg_path_line_to(plutovg_path_t* path, double x, double y); -void plutovg_path_quad_to(plutovg_path_t* path, double x1, double y1, double x2, double y2); -void plutovg_path_cubic_to(plutovg_path_t* path, double x1, double y1, double x2, double y2, double x3, double y3); -void plutovg_path_close(plutovg_path_t* path); -void plutovg_path_rel_move_to(plutovg_path_t* path, double x, double y); -void plutovg_path_rel_line_to(plutovg_path_t* path, double x, double y); -void plutovg_path_rel_quad_to(plutovg_path_t* path, double x1, double y1, double x2, double y2); -void plutovg_path_rel_cubic_to(plutovg_path_t* path, double x1, double y1, double x2, double y2, double x3, double y3); -void plutovg_path_add_rect(plutovg_path_t* path, double x, double y, double w, double h); -void plutovg_path_add_round_rect(plutovg_path_t* path, double x, double y, double w, double h, double rx, double ry); -void plutovg_path_add_ellipse(plutovg_path_t* path, double cx, double cy, double rx, double ry); -void plutovg_path_add_circle(plutovg_path_t* path, double cx, double cy, double r); -void plutovg_path_add_path(plutovg_path_t* path, const plutovg_path_t* source, const plutovg_matrix_t* matrix); -void plutovg_path_transform(plutovg_path_t* path, const plutovg_matrix_t* matrix); -void plutovg_path_get_current_point(const plutovg_path_t* path, double* x, double* y); -int plutovg_path_get_element_count(const plutovg_path_t* path); -plutovg_path_element_t* plutovg_path_get_elements(const plutovg_path_t* path); -int plutovg_path_get_point_count(const plutovg_path_t* path); -plutovg_point_t* plutovg_path_get_points(const plutovg_path_t* path); -void plutovg_path_clear(plutovg_path_t* path); -int plutovg_path_empty(const plutovg_path_t* path); -plutovg_path_t* plutovg_path_clone(const plutovg_path_t* path); -plutovg_path_t* plutovg_path_clone_flat(const plutovg_path_t* path); +/** + * @brief Iterator for traversing path elements in a path. + */ +typedef struct plutovg_path_iterator { + const plutovg_path_element_t* elements; ///< Pointer to the array of path elements. + int size; ///< Total number of elements in the array. + int index; ///< Current position in the array. +} plutovg_path_iterator_t; -typedef struct { - double r; - double g; - double b; - double a; +/** + * @brief Initializes a path iterator for a given path. + * + * @param it The path iterator to initialize. + * @param path The path to iterate over. + */ +PLUTOVG_API void plutovg_path_iterator_init(plutovg_path_iterator_t* it, const plutovg_path_t* path); + +/** + * @brief Checks if there are more elements to iterate over. + * + * @param it The path iterator. + * @return `true` if there are more elements; otherwise, `false`. + */ +PLUTOVG_API bool plutovg_path_iterator_has_next(const plutovg_path_iterator_t* it); + +/** + * @brief Retrieves the current command and its associated points, then advances the iterator. + * + * @param it The path iterator. + * @param points An array to store the points for the current command. + * @return The path command for the current element. + */ +PLUTOVG_API plutovg_path_command_t plutovg_path_iterator_next(plutovg_path_iterator_t* it, plutovg_point_t points[3]); + +/** + * @brief Creates a new path object. + * + * @return A pointer to the newly created path object. + */ +PLUTOVG_API plutovg_path_t* plutovg_path_create(void); + +/** + * @brief Increases the reference count of a path object. + * + * @param path A pointer to a `plutovg_path_t` object. + * @return A pointer to the same `plutovg_path_t` object. + */ +PLUTOVG_API plutovg_path_t* plutovg_path_reference(plutovg_path_t* path); + +/** + * @brief Decreases the reference count of a path object. + * + * This function decrements the reference count of the given path object. If + * the reference count reaches zero, the path object is destroyed and its + * resources are freed. + * + * @param path A pointer to the `plutovg_path_t` object. + */ +PLUTOVG_API void plutovg_path_destroy(plutovg_path_t* path); + +/** + * @brief Retrieves the reference count of a path object. + * + * @param path A pointer to a `plutovg_path_t` object. + * @return The current reference count of the path object. + */ +PLUTOVG_API int plutovg_path_get_reference_count(const plutovg_path_t* path); + +/** + * @brief Retrieves the elements of a path. + * + * Provides access to the array of path elements. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param elements A pointer to a pointer that will be set to the array of path elements. + * @return The number of elements in the path. + */ +PLUTOVG_API int plutovg_path_get_elements(const plutovg_path_t* path, const plutovg_path_element_t** elements); + +/** + * @brief Moves the current point to a new position. + * + * This function moves the current point to the specified coordinates without + * drawing a line. This is equivalent to the `M` command in SVG path syntax. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param x The x-coordinate of the new position. + * @param y The y-coordinate of the new position. + */ +PLUTOVG_API void plutovg_path_move_to(plutovg_path_t* path, float x, float y); + +/** + * @brief Adds a straight line segment to the path. + * + * This function adds a straight line segment from the current point to the + * specified coordinates. This is equivalent to the `L` command in SVG path syntax. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param x The x-coordinate of the end point of the line segment. + * @param y The y-coordinate of the end point of the line segment. + */ +PLUTOVG_API void plutovg_path_line_to(plutovg_path_t* path, float x, float y); + +/** + * @brief Adds a quadratic Bézier curve to the path. + * + * This function adds a quadratic Bézier curve segment from the current point + * to the specified end point, using the given control point. This is equivalent + * to the `Q` command in SVG path syntax. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param x1 The x-coordinate of the control point. + * @param y1 The y-coordinate of the control point. + * @param x2 The x-coordinate of the end point of the curve. + * @param y2 The y-coordinate of the end point of the curve. + */ +PLUTOVG_API void plutovg_path_quad_to(plutovg_path_t* path, float x1, float y1, float x2, float y2); + +/** + * @brief Adds a cubic Bézier curve to the path. + * + * This function adds a cubic Bézier curve segment from the current point + * to the specified end point, using the given two control points. This is + * equivalent to the `C` command in SVG path syntax. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param x1 The x-coordinate of the first control point. + * @param y1 The y-coordinate of the first control point. + * @param x2 The x-coordinate of the second control point. + * @param y2 The y-coordinate of the second control point. + * @param x3 The x-coordinate of the end point of the curve. + * @param y3 The y-coordinate of the end point of the curve. + */ +PLUTOVG_API void plutovg_path_cubic_to(plutovg_path_t* path, float x1, float y1, float x2, float y2, float x3, float y3); + +/** + * @brief Adds an elliptical arc to the path. + * + * This function adds an elliptical arc segment from the current point to the + * specified end point. The arc is defined by the radii, rotation angle, and + * flags for large arc and sweep. This is equivalent to the `A` command in SVG + * path syntax. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param rx The x-radius of the ellipse. + * @param ry The y-radius of the ellipse. + * @param angle The rotation angle of the ellipse in radians. + * @param large_arc_flag If true, draw the large arc; otherwise, draw the small arc. + * @param sweep_flag If true, draw the arc in the positive-angle direction; otherwise, in the negative-angle direction. + * @param x The x-coordinate of the end point of the arc. + * @param y The y-coordinate of the end point of the arc. + */ +PLUTOVG_API void plutovg_path_arc_to(plutovg_path_t* path, float rx, float ry, float angle, bool large_arc_flag, bool sweep_flag, float x, float y); + +/** + * @brief Closes the current sub-path. + * + * This function closes the current sub-path by drawing a straight line back to + * the start point of the sub-path. This is equivalent to the `Z` command in SVG + * path syntax. + * + * @param path A pointer to a `plutovg_path_t` object. + */ +PLUTOVG_API void plutovg_path_close(plutovg_path_t* path); + +/** + * @brief Retrieves the current point of the path. + * + * Gets the current point's coordinates in the path. This point is the last + * position used or the point where the path was last moved to. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param x The x-coordinate of the current point. + * @param y The y-coordinate of the current point. + */ +PLUTOVG_API void plutovg_path_get_current_point(const plutovg_path_t* path, float* x, float* y); + +/** + * @brief Reserves space for path elements. + * + * Reserves space for a specified number of elements in the path. This helps optimize + * memory allocation for future path operations. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param count The number of path elements to reserve space for. + */ +PLUTOVG_API void plutovg_path_reserve(plutovg_path_t* path, int count); + +/** + * @brief Resets the path. + * + * Clears all path data, effectively resetting the `plutovg_path_t` object to its initial state. + * + * @param path A pointer to a `plutovg_path_t` object. + */ +PLUTOVG_API void plutovg_path_reset(plutovg_path_t* path); + +/** + * @brief Adds a rectangle to the path. + * + * Adds a rectangle defined by the top-left corner (x, y) and dimensions (w, h) to the path. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param x The x-coordinate of the rectangle's top-left corner. + * @param y The y-coordinate of the rectangle's top-left corner. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + */ +PLUTOVG_API void plutovg_path_add_rect(plutovg_path_t* path, float x, float y, float w, float h); + +/** + * @brief Adds a rounded rectangle to the path. + * + * Adds a rounded rectangle defined by the top-left corner (x, y), dimensions (w, h), + * and corner radii (rx, ry) to the path. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param x The x-coordinate of the rectangle's top-left corner. + * @param y The y-coordinate of the rectangle's top-left corner. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + * @param rx The x-radius of the rectangle's corners. + * @param ry The y-radius of the rectangle's corners. + */ +PLUTOVG_API void plutovg_path_add_round_rect(plutovg_path_t* path, float x, float y, float w, float h, float rx, float ry); + +/** + * @brief Adds an ellipse to the path. + * + * Adds an ellipse defined by the center (cx, cy) and radii (rx, ry) to the path. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param cx The x-coordinate of the ellipse's center. + * @param cy The y-coordinate of the ellipse's center. + * @param rx The x-radius of the ellipse. + * @param ry The y-radius of the ellipse. + */ +PLUTOVG_API void plutovg_path_add_ellipse(plutovg_path_t* path, float cx, float cy, float rx, float ry); + +/** + * @brief Adds a circle to the path. + * + * Adds a circle defined by its center (cx, cy) and radius (r) to the path. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param cx The x-coordinate of the circle's center. + * @param cy The y-coordinate of the circle's center. + * @param r The radius of the circle. + */ +PLUTOVG_API void plutovg_path_add_circle(plutovg_path_t* path, float cx, float cy, float r); + +/** + * @brief Adds an arc to the path. + * + * Adds an arc defined by the center (cx, cy), radius (r), start angle (a0), end angle (a1), + * and direction (ccw) to the path. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param cx The x-coordinate of the arc's center. + * @param cy The y-coordinate of the arc's center. + * @param r The radius of the arc. + * @param a0 The start angle of the arc in radians. + * @param a1 The end angle of the arc in radians. + * @param ccw If true, the arc is drawn counter-clockwise; if false, clockwise. + */ +PLUTOVG_API void plutovg_path_add_arc(plutovg_path_t* path, float cx, float cy, float r, float a0, float a1, bool ccw); + +/** + * @brief Adds a sub-path to the path. + * + * Adds all elements from another path (`source`) to the current path, optionally + * applying a transformation matrix. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param source A pointer to the `plutovg_path_t` object to copy elements from. + * @param matrix A pointer to a `plutovg_matrix_t` object, or `NULL` to apply no transformation. + */ +PLUTOVG_API void plutovg_path_add_path(plutovg_path_t* path, const plutovg_path_t* source, const plutovg_matrix_t* matrix); + +/** + * @brief Applies a transformation matrix to the path. + * + * Transforms the entire path using the provided transformation matrix. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param matrix A pointer to a `plutovg_matrix_t` object. + */ +PLUTOVG_API void plutovg_path_transform(plutovg_path_t* path, const plutovg_matrix_t* matrix); + +/** + * @brief Callback function type for traversing a path. + * + * This function type defines a callback used to traverse path elements. + * + * @param closure A pointer to user-defined data passed to the callback. + * @param command The current path command. + * @param points An array of points associated with the command. + * @param npoints The number of points in the array. + */ +typedef void (*plutovg_path_traverse_func_t)(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints); + +/** + * @brief Traverses the path and calls the callback for each element. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param traverse_func The callback function to be called for each element of the path. + * @param closure User-defined data passed to the callback. + */ +PLUTOVG_API void plutovg_path_traverse(const plutovg_path_t* path, plutovg_path_traverse_func_t traverse_func, void* closure); + +/** + * @brief Traverses the path with Bézier curves flattened to line segments. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param traverse_func The callback function to be called for each element of the path. + * @param closure User-defined data passed to the callback. + */ +PLUTOVG_API void plutovg_path_traverse_flatten(const plutovg_path_t* path, plutovg_path_traverse_func_t traverse_func, void* closure); + +/** + * @brief Traverses the path with a dashed pattern and calls the callback for each segment. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param offset The starting offset into the dash pattern. + * @param dashes An array of dash lengths. + * @param ndashes The number of elements in the `dashes` array. + * @param traverse_func The callback function to be called for each element of the path. + * @param closure User-defined data passed to the callback. + */ +PLUTOVG_API void plutovg_path_traverse_dashed(const plutovg_path_t* path, float offset, const float* dashes, int ndashes, plutovg_path_traverse_func_t traverse_func, void* closure); + +/** + * @brief Creates a copy of the path. + * + * @param path A pointer to the `plutovg_path_t` object to clone. + * @return A pointer to the newly created path clone. + */ +PLUTOVG_API plutovg_path_t* plutovg_path_clone(const plutovg_path_t* path); + +/** + * @brief Creates a copy of the path with Bézier curves flattened to line segments. + * + * @param path A pointer to the `plutovg_path_t` object to clone. + * @return A pointer to the newly created path clone with flattened curves. + */ +PLUTOVG_API plutovg_path_t* plutovg_path_clone_flatten(const plutovg_path_t* path); + +/** + * @brief Creates a copy of the path with a dashed pattern applied. + * + * @param path A pointer to the `plutovg_path_t` object to clone. + * @param offset The starting offset into the dash pattern. + * @param dashes An array of dash lengths. + * @param ndashes The number of elements in the `dashes` array. + * @return A pointer to the newly created path clone with dashed pattern. + */ +PLUTOVG_API plutovg_path_t* plutovg_path_clone_dashed(const plutovg_path_t* path, float offset, const float* dashes, int ndashes); + +/** + * @brief Computes the bounding box and total length of the path. + * + * @param path A pointer to a `plutovg_path_t` object. + * @param extents A pointer to a `plutovg_rect_t` object to store the bounding box. + * @param tight If `true`, computes a precise bounding box; otherwise, aligns to control points. + * @return The total length of the path. + */ +PLUTOVG_API float plutovg_path_extents(const plutovg_path_t* path, plutovg_rect_t* extents, bool tight); + +/** + * @brief Calculates the total length of the path. + * + * @param path A pointer to a `plutovg_path_t` object. + * @return The total length of the path. + */ +PLUTOVG_API float plutovg_path_length(const plutovg_path_t* path); + +/** + * @brief Parses SVG path data into a `plutovg_path_t` object. + * + * @param path A pointer to the `plutovg_path_t` object to populate. + * @param data The SVG path data string. + * @param length The length of `data`, or `-1` for null-terminated data. + * @return `true` if successful; `false` otherwise. + */ +PLUTOVG_API bool plutovg_path_parse(plutovg_path_t* path, const char* data, int length); + +/** + * @brief Text encodings used for converting text data to code points. + */ +typedef enum plutovg_text_encoding { + PLUTOVG_TEXT_ENCODING_UTF8, ///< UTF-8 encoding + PLUTOVG_TEXT_ENCODING_UTF16, ///< UTF-16 encoding + PLUTOVG_TEXT_ENCODING_UTF32, ///< UTF-32 encoding + PLUTOVG_TEXT_ENCODING_LATIN1 ///< Latin-1 encoding +} plutovg_text_encoding_t; + +/** + * @brief Iterator for traversing code points in text data. + */ +typedef struct plutovg_text_iterator { + const void* text; ///< Pointer to the text data. + int length; ///< Length of the text data. + plutovg_text_encoding_t encoding; ///< Encoding format of the text data. + int index; ///< Current position in the text data. +} plutovg_text_iterator_t; + +/** + * @brief Represents a Unicode code point. + */ +typedef unsigned int plutovg_codepoint_t; + +/** + * @brief Initializes a text iterator. + * + * @param it Pointer to the text iterator. + * @param text Pointer to the text data. + * @param length Length of the text data, or -1 if the data is null-terminated. + * @param encoding Encoding of the text data. + */ +PLUTOVG_API void plutovg_text_iterator_init(plutovg_text_iterator_t* it, const void* text, int length, plutovg_text_encoding_t encoding); + +/** + * @brief Checks if there are more code points to iterate. + * + * @param it Pointer to the text iterator. + * @return `true` if more code points are available; otherwise, `false`. + */ +PLUTOVG_API bool plutovg_text_iterator_has_next(const plutovg_text_iterator_t* it); + +/** + * @brief Retrieves the next code point and advances the iterator. + * + * @param it Pointer to the text iterator. + * @return The next code point. + */ +PLUTOVG_API plutovg_codepoint_t plutovg_text_iterator_next(plutovg_text_iterator_t* it); + +/** + * @brief Represents a font face. + */ +typedef struct plutovg_font_face plutovg_font_face_t; + +/** + * @brief Loads a font face from a file. + * + * @param filename Path to the font file. + * @param ttcindex Index of the font face within a TrueType Collection (TTC). + * @return A pointer to the loaded `plutovg_font_face_t` object, or `NULL` on failure. + */ +PLUTOVG_API plutovg_font_face_t* plutovg_font_face_load_from_file(const char* filename, int ttcindex); + +/** + * @brief Loads a font face from memory. + * + * @param data Pointer to the font data. + * @param length Length of the font data. + * @param ttcindex Index of the font face within a TrueType Collection (TTC). + * @param destroy_func Function to free the font data when no longer needed. + * @param closure User-defined data passed to `destroy_func`. + * @return A pointer to the loaded `plutovg_font_face_t` object, or `NULL` on failure. + */ +PLUTOVG_API plutovg_font_face_t* plutovg_font_face_load_from_data(const void* data, unsigned int length, int ttcindex, plutovg_destroy_func_t destroy_func, void* closure); + +/** + * @brief Increments the reference count of a font face. + * + * @param face A pointer to a `plutovg_font_face_t` object. + * @return A pointer to the same `plutovg_font_face_t` object with an incremented reference count. + */ +PLUTOVG_API plutovg_font_face_t* plutovg_font_face_reference(plutovg_font_face_t* face); + +/** + * @brief Decrements the reference count and potentially destroys the font face. + * + * @param face A pointer to a `plutovg_font_face_t` object. + */ +PLUTOVG_API void plutovg_font_face_destroy(plutovg_font_face_t* face); + +/** + * @brief Retrieves the current reference count of a font face. + * + * @param face A pointer to a `plutovg_font_face_t` object. + * @return The reference count of the font face. + */ +PLUTOVG_API int plutovg_font_face_get_reference_count(const plutovg_font_face_t* face); + +/** + * @brief Retrieves metrics for a font face at a specified size. + * + * @param face A pointer to a `plutovg_font_face_t` object. + * @param size The font size in pixels. + * @param ascent Pointer to store the ascent metric. + * @param descent Pointer to store the descent metric. + * @param line_gap Pointer to store the line gap metric. + * @param extents Pointer to a `plutovg_rect_t` object to store the font bounding box. + */ +PLUTOVG_API void plutovg_font_face_get_metrics(const plutovg_font_face_t* face, float size, float* ascent, float* descent, float* line_gap, plutovg_rect_t* extents); + +/** + * @brief Retrieves metrics for a specified glyph at a given size. + * + * @param face A pointer to a `plutovg_font_face_t` object. + * @param size The font size in pixels. + * @param codepoint The Unicode code point of the glyph. + * @param advance_width Pointer to store the advance width of the glyph. + * @param left_side_bearing Pointer to store the left side bearing of the glyph. + * @param extents Pointer to a `plutovg_rect_t` object to store the glyph bounding box. + */ +PLUTOVG_API void plutovg_font_face_get_glyph_metrics(plutovg_font_face_t* face, float size, plutovg_codepoint_t codepoint, float* advance_width, float* left_side_bearing, plutovg_rect_t* extents); + +/** + * @brief Retrieves the path of a glyph and its advance width. + * + * @param face A pointer to a `plutovg_font_face_t` object. + * @param size The font size in pixels. + * @param x The x-coordinate for positioning the glyph. + * @param y The y-coordinate for positioning the glyph. + * @param codepoint The Unicode code point of the glyph. + * @param path Pointer to a `plutovg_path_t` object to store the glyph path. + * @return The advance width of the glyph. + */ +PLUTOVG_API float plutovg_font_face_get_glyph_path(plutovg_font_face_t* face, float size, float x, float y, plutovg_codepoint_t codepoint, plutovg_path_t* path); + +/** + * @brief Traverses the path of a glyph and calls a callback for each path element. + * + * @param face A pointer to a `plutovg_font_face_t` object. + * @param size The font size in pixels. + * @param x The x-coordinate for positioning the glyph. + * @param y The y-coordinate for positioning the glyph. + * @param codepoint The Unicode code point of the glyph. + * @param traverse_func The callback function to be called for each path element. + * @param closure User-defined data passed to the callback function. + * @return The advance width of the glyph. + */ +PLUTOVG_API float plutovg_font_face_traverse_glyph_path(plutovg_font_face_t* face, float size, float x, float y, plutovg_codepoint_t codepoint, plutovg_path_traverse_func_t traverse_func, void* closure); + +/** + * @brief Computes the bounding box of a text string and its advance width. + * + * @param face A pointer to a `plutovg_font_face_t` object. + * @param size The font size in pixels. + * @param text Pointer to the text data. + * @param length Length of the text data, or -1 if null-terminated. + * @param encoding Encoding of the text data. + * @param extents Pointer to a `plutovg_rect_t` object to store the bounding box of the text. + * @return The total advance width of the text. + */ +PLUTOVG_API float plutovg_font_face_text_extents(plutovg_font_face_t* face, float size, const void* text, int length, plutovg_text_encoding_t encoding, plutovg_rect_t* extents); + +/** + * @brief Represents a color with red, green, blue, and alpha components. + */ +typedef struct plutovg_color { + float r; ///< Red component (0 to 1). + float g; ///< Green component (0 to 1). + float b; ///< Blue component (0 to 1). + float a; ///< Alpha (opacity) component (0 to 1). } plutovg_color_t; -void plutovg_color_init_rgb(plutovg_color_t* color, double r, double g, double b); -void plutovg_color_init_rgba(plutovg_color_t* color, double r, double g, double b, double a); +#define PLUTOVG_MAKE_COLOR(r, g, b, a) ((plutovg_color_t){r, g, b, a}) -typedef enum { - plutovg_spread_method_pad, - plutovg_spread_method_reflect, - plutovg_spread_method_repeat -} plutovg_spread_method_t; +#define PLUTOVG_BLACK_COLOR PLUTOVG_MAKE_COLOR(0, 0, 0, 1) +#define PLUTOVG_WHITE_COLOR PLUTOVG_MAKE_COLOR(1, 1, 1, 1) +#define PLUTOVG_RED_COLOR PLUTOVG_MAKE_COLOR(1, 0, 0, 1) +#define PLUTOVG_GREEN_COLOR PLUTOVG_MAKE_COLOR(0, 1, 0, 1) +#define PLUTOVG_BLUE_COLOR PLUTOVG_MAKE_COLOR(0, 0, 1, 1) +#define PLUTOVG_YELLOW_COLOR PLUTOVG_MAKE_COLOR(1, 1, 0, 1) +#define PLUTOVG_CYAN_COLOR PLUTOVG_MAKE_COLOR(0, 1, 1, 1) +#define PLUTOVG_MAGENTA_COLOR PLUTOVG_MAKE_COLOR(1, 0, 1, 1) + +/** + * @brief Initializes a color using RGB components in the 0-1 range. + * + * @param color A pointer to a `plutovg_color_t` object. + * @param r Red component (0 to 1). + * @param g Green component (0 to 1). + * @param b Blue component (0 to 1). + */ +PLUTOVG_API void plutovg_color_init_rgb(plutovg_color_t* color, float r, float g, float b); + +/** + * @brief Initializes a color using RGBA components in the 0-1 range. + * + * @param color A pointer to a `plutovg_color_t` object. + * @param r Red component (0 to 1). + * @param g Green component (0 to 1). + * @param b Blue component (0 to 1). + * @param a Alpha component (0 to 1). + */ +PLUTOVG_API void plutovg_color_init_rgba(plutovg_color_t* color, float r, float g, float b, float a); + +/** + * @brief Initializes a color using RGB components in the 0-255 range. + * + * @param color A pointer to a `plutovg_color_t` object. + * @param r Red component (0 to 255). + * @param g Green component (0 to 255). + * @param b Blue component (0 to 255). + */ +PLUTOVG_API void plutovg_color_init_rgb8(plutovg_color_t* color, int r, int g, int b); + +/** + * @brief Initializes a color using RGBA components in the 0-255 range. + * + * @param color A pointer to a `plutovg_color_t` object. + * @param r Red component (0 to 255). + * @param g Green component (0 to 255). + * @param b Blue component (0 to 255). + * @param a Alpha component (0 to 255). + */ +PLUTOVG_API void plutovg_color_init_rgba8(plutovg_color_t* color, int r, int g, int b, int a); + +/** + * @brief Initializes a color from a 32-bit unsigned RGBA value. + * + * @param color A pointer to a `plutovg_color_t` object. + * @param value 32-bit unsigned RGBA value. + */ +PLUTOVG_API void plutovg_color_init_rgba32(plutovg_color_t* color, unsigned int value); + +/** + * @brief Initializes a color from a 32-bit unsigned ARGB value. + * + * @param color A pointer to a `plutovg_color_t` object. + * @param value 32-bit unsigned ARGB value. + */ +PLUTOVG_API void plutovg_color_init_argb32(plutovg_color_t* color, unsigned int value); + +/** + * @brief Initializes a color with the specified HSL color values. + * + * @param color A pointer to a `plutovg_color_t` object. + * @param h Hue component in degrees (0 to 360). + * @param s Saturation component (0 to 1). + * @param l Lightness component (0 to 1). + */ +PLUTOVG_API void plutovg_color_init_hsl(plutovg_color_t* color, float h, float s, float l); + +/** + * @brief Initializes a color with the specified HSLA color values. + * + * @param color A pointer to a `plutovg_color_t` object. + * @param h Hue component in degrees (0 to 360). + * @param s Saturation component (0 to 1). + * @param l Lightness component (0 to 1). + * @param a Alpha component (0 to 1). + */ +PLUTOVG_API void plutovg_color_init_hsla(plutovg_color_t* color, float h, float s, float l, float a); + +/** + * @brief Converts a color to a 32-bit unsigned RGBA value. + * + * @param color A pointer to a `plutovg_color_t` object. + * + * @return 32-bit unsigned RGBA value. + */ +PLUTOVG_API unsigned int plutovg_color_to_rgba32(const plutovg_color_t* color); + +/** + * @brief Converts a color to a 32-bit unsigned ARGB value. + * + * @param color A pointer to a `plutovg_color_t` object. + * + * @return 32-bit unsigned ARGB value. + */ +PLUTOVG_API unsigned int plutovg_color_to_argb32(const plutovg_color_t* color); + +/** + * @brief Parses a color from a string using CSS color syntax. + * + * @param color A pointer to a `plutovg_color_t` object to store the parsed color. + * @param data A pointer to the input string containing the color data. + * @param length The length of the input string in bytes, or `-1` if the string is null-terminated. + * + * @return The number of characters consumed on success (including leading/trailing spaces), or 0 on failure. + */ +PLUTOVG_API int plutovg_color_parse(plutovg_color_t* color, const char* data, int length); + +/** + * @brief Represents an image surface for drawing operations. + * + * Stores pixel data in a 32-bit premultiplied ARGB format (0xAARRGGBB), + * where red, green, and blue channels are multiplied by the alpha channel + * and divided by 255. + */ +typedef struct plutovg_surface plutovg_surface_t; + +/** + * @brief Creates a new image surface with the specified dimensions. + * + * @param width The width of the surface in pixels. + * @param height The height of the surface in pixels. + * @return A pointer to the newly created `plutovg_surface_t` object. + */ +PLUTOVG_API plutovg_surface_t* plutovg_surface_create(int width, int height); + +/** + * @brief Creates an image surface using existing pixel data. + * + * @param data Pointer to the pixel data. + * @param width The width of the surface in pixels. + * @param height The height of the surface in pixels. + * @param stride The number of bytes per row in the pixel data. + * @return A pointer to the newly created `plutovg_surface_t` object. + */ +PLUTOVG_API plutovg_surface_t* plutovg_surface_create_for_data(unsigned char* data, int width, int height, int stride); + +/** + * @brief Loads an image surface from a file. + * + * @param filename Path to the image file. + * @return Pointer to the surface, or `NULL` on failure. + */ +PLUTOVG_API plutovg_surface_t* plutovg_surface_load_from_image_file(const char* filename); + +/** + * @brief Loads an image surface from raw image data. + * + * @param data Pointer to the image data. + * @param length Length of the data in bytes. + * @return Pointer to the surface, or `NULL` on failure. + */ +PLUTOVG_API plutovg_surface_t* plutovg_surface_load_from_image_data(const void* data, int length); + +/** + * @brief Loads an image surface from base64-encoded data. + * + * @param data Pointer to the base64-encoded image data. + * @param length Length of the data in bytes, or `-1` if null-terminated. + * @return Pointer to the surface, or `NULL` on failure. + */ +PLUTOVG_API plutovg_surface_t* plutovg_surface_load_from_image_base64(const char* data, int length); + +/** + * @brief Increments the reference count for a surface. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @return Pointer to the `plutovg_surface_t` object. + */ +PLUTOVG_API plutovg_surface_t* plutovg_surface_reference(plutovg_surface_t* surface); + +/** + * @brief Decrements the reference count and destroys the surface if the count reaches zero. + * + * @param surface Pointer to the `plutovg_surface_t` object . + */ +PLUTOVG_API void plutovg_surface_destroy(plutovg_surface_t* surface); + +/** + * @brief Gets the current reference count of a surface. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @return The reference count of the surface. + */ +PLUTOVG_API int plutovg_surface_get_reference_count(const plutovg_surface_t* surface); + +/** + * @brief Gets the pixel data of the surface. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @return Pointer to the pixel data. + */ +PLUTOVG_API unsigned char* plutovg_surface_get_data(const plutovg_surface_t* surface); + +/** + * @brief Gets the width of the surface. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @return Width of the surface in pixels. + */ +PLUTOVG_API int plutovg_surface_get_width(const plutovg_surface_t* surface); + +/** + * @brief Gets the height of the surface. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @return Height of the surface in pixels. + */ +PLUTOVG_API int plutovg_surface_get_height(const plutovg_surface_t* surface); -typedef struct plutovg_gradient plutovg_gradient_t; +/** + * @brief Gets the stride of the surface. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @return Number of bytes per row. + */ +PLUTOVG_API int plutovg_surface_get_stride(const plutovg_surface_t* surface); +/** + * @brief plutovg_surface_clear + * @param surface + * @param color + */ +PLUTOVG_API void plutovg_surface_clear(plutovg_surface_t* surface, const plutovg_color_t* color); + +/** + * @brief Writes the surface to a PNG file. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @param filename Path to the output PNG file. + * @return `true` if successful, `false` otherwise. + */ +PLUTOVG_API bool plutovg_surface_write_to_png(const plutovg_surface_t* surface, const char* filename); + +/** + * @brief Writes the surface to a JPEG file. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @param filename Path to the output JPEG file. + * @param quality JPEG quality (0 to 100). + * @return `true` if successful, `false` otherwise. + */ +PLUTOVG_API bool plutovg_surface_write_to_jpg(const plutovg_surface_t* surface, const char* filename, int quality); + +/** + * @brief Writes the surface to a PNG stream. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @param write_func Callback function for writing data. + * @param closure User-defined data passed to the callback. + * @return `true` if successful, `false` otherwise. + */ +PLUTOVG_API bool plutovg_surface_write_to_png_stream(const plutovg_surface_t* surface, plutovg_write_func_t write_func, void* closure); + +/** + * @brief Writes the surface to a JPEG stream. + * + * @param surface Pointer to the `plutovg_surface_t` object. + * @param write_func Callback function for writing data. + * @param closure User-defined data passed to the callback. + * @param quality JPEG quality (0 to 100). + * @return `true` if successful, `false` otherwise. + */ +PLUTOVG_API bool plutovg_surface_write_to_jpg_stream(const plutovg_surface_t* surface, plutovg_write_func_t write_func, void* closure, int quality); + +/** + * @brief Converts pixel data from premultiplied ARGB to RGBA format. + * + * Transforms pixel data from native-endian 32-bit ARGB premultiplied format + * to a non-premultiplied RGBA byte sequence. + * + * @param dst Pointer to the destination buffer (can overlap with `src`). + * @param src Pointer to the source buffer in ARGB premultiplied format. + * @param width Image width in pixels. + * @param height Image height in pixels. + * @param stride Number of bytes per image row in the buffers. + */ +PLUTOVG_API void plutovg_convert_argb_to_rgba(unsigned char* dst, const unsigned char* src, int width, int height, int stride); + +/** + * @brief Converts pixel data from RGBA to premultiplied ARGB format. + * + * Transforms pixel data from a non-premultiplied RGBA byte sequence + * to a native-endian 32-bit ARGB premultiplied format. + * + * @param dst Pointer to the destination buffer (can overlap with `src`). + * @param src Pointer to the source buffer in RGBA format. + * @param width Image width in pixels. + * @param height Image height in pixels. + * @param stride Number of bytes per image row in the buffers. + */ +PLUTOVG_API void plutovg_convert_rgba_to_argb(unsigned char* dst, const unsigned char* src, int width, int height, int stride); + +/** + * @brief Defines the type of texture, either plain or tiled. + */ typedef enum { - plutovg_gradient_type_linear, - plutovg_gradient_type_radial -} plutovg_gradient_type_t; + PLUTOVG_TEXTURE_TYPE_PLAIN, ///< Plain texture. + PLUTOVG_TEXTURE_TYPE_TILED ///< Tiled texture. +} plutovg_texture_type_t; +/** + * @brief Defines the spread method for gradients. + */ +typedef enum { + PLUTOVG_SPREAD_METHOD_PAD, ///< Pad the gradient's edges. + PLUTOVG_SPREAD_METHOD_REFLECT, ///< Reflect the gradient beyond its bounds. + PLUTOVG_SPREAD_METHOD_REPEAT ///< Repeat the gradient pattern. +} plutovg_spread_method_t; + +/** + * @brief Represents a gradient stop. + */ typedef struct { - double offset; - plutovg_color_t color; + float offset; ///< The offset of the gradient stop, as a value between 0 and 1. + plutovg_color_t color; ///< The color of the gradient stop. } plutovg_gradient_stop_t; -void plutovg_gradient_init_linear(plutovg_gradient_t* gradient, double x1, double y1, double x2, double y2); -void plutovg_gradient_init_radial(plutovg_gradient_t* gradient, double cx, double cy, double cr, double fx, double fy, double fr); -void plutovg_gradient_set_type(plutovg_gradient_t* gradient, plutovg_gradient_type_t type); -plutovg_gradient_type_t plutovg_gradient_get_type(const plutovg_gradient_t* gradient); -void plutovg_gradient_set_spread(plutovg_gradient_t* gradient, plutovg_spread_method_t spread); -plutovg_spread_method_t plutovg_gradient_get_spread(const plutovg_gradient_t* gradient); -void plutovg_gradient_set_matrix(plutovg_gradient_t* gradient, const plutovg_matrix_t* matrix); -void plutovg_gradient_get_matrix(const plutovg_gradient_t* gradient, plutovg_matrix_t* matrix); -void plutovg_gradient_add_stop_rgb(plutovg_gradient_t* gradient, double offset, double r, double g, double b); -void plutovg_gradient_add_stop_rgba(plutovg_gradient_t* gradient, double offset, double r, double g, double b, double a); -void plutovg_gradient_add_stop(plutovg_gradient_t* gradient, const plutovg_gradient_stop_t* stop); -void plutovg_gradient_clear_stops(plutovg_gradient_t* gradient); -int plutovg_gradient_get_stop_count(const plutovg_gradient_t* gradient); -plutovg_gradient_stop_t* plutovg_gradient_get_stops(const plutovg_gradient_t* gradient); -void plutovg_gradient_get_values_linear(const plutovg_gradient_t* gradient, double* x1, double* y1, double* x2, double* y2); -void plutovg_gradient_get_values_radial(const plutovg_gradient_t* gradient, double* cx, double* cy, double* cr, double* fx, double* fy, double* fr); -void plutovg_gradient_set_values_linear(plutovg_gradient_t* gradient, double x1, double y1, double x2, double y2); -void plutovg_gradient_set_values_radial(plutovg_gradient_t* gradient, double cx, double cy, double cr, double fx, double fy, double fr); -void plutovg_gradient_set_opacity(plutovg_gradient_t* paint, double opacity); -double plutovg_gradient_get_opacity(const plutovg_gradient_t* paint); - -typedef struct plutovg_texture plutovg_texture_t; +/** + * @brief Represents a paint object used for drawing operations. + */ +typedef struct plutovg_paint plutovg_paint_t; + +/** + * @brief Creates a solid RGB paint. + * + * @param r The red component (0 to 1). + * @param g The green component (0 to 1). + * @param b The blue component (0 to 1). + * @return A pointer to the created `plutovg_paint_t` object. + */ +PLUTOVG_API plutovg_paint_t* plutovg_paint_create_rgb(float r, float g, float b); + +/** + * @brief Creates a solid RGBA paint. + * + * @param r The red component (0 to 1). + * @param g The green component (0 to 1). + * @param b The blue component (0 to 1). + * @param a The alpha component (0 to 1). + * @return A pointer to the created `plutovg_paint_t` object. + */ +PLUTOVG_API plutovg_paint_t* plutovg_paint_create_rgba(float r, float g, float b, float a); + +/** + * @brief Creates a solid color paint. + * + * @param color A pointer to the `plutovg_color_t` object. + * @return A pointer to the created `plutovg_paint_t` object. + */ +PLUTOVG_API plutovg_paint_t* plutovg_paint_create_color(const plutovg_color_t* color); + +/** + * @brief Creates a linear gradient paint. + * + * @param x1 The x coordinate of the gradient start. + * @param y1 The y coordinate of the gradient start. + * @param x2 The x coordinate of the gradient end. + * @param y2 The y coordinate of the gradient end. + * @param spread The gradient spread method. + * @param stops Array of gradient stops. + * @param nstops Number of gradient stops. + * @param matrix Optional transformation matrix. + * @return A pointer to the created `plutovg_paint_t` object. + */ +PLUTOVG_API plutovg_paint_t* plutovg_paint_create_linear_gradient(float x1, float y1, float x2, float y2, + plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix); +/** + * @brief Creates a radial gradient paint. + * + * @param cx The x coordinate of the gradient center. + * @param cy The y coordinate of the gradient center. + * @param cr The radius of the gradient. + * @param fx The x coordinate of the focal point. + * @param fy The y coordinate of the focal point. + * @param fr The radius of the focal point. + * @param spread The gradient spread method. + * @param stops Array of gradient stops. + * @param nstops Number of gradient stops. + * @param matrix Optional transformation matrix. + * @return A pointer to the created `plutovg_paint_t` object. + */ +PLUTOVG_API plutovg_paint_t* plutovg_paint_create_radial_gradient(float cx, float cy, float cr, float fx, float fy, float fr, + plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix); + +/** + * @brief Creates a texture paint from a surface. + * + * @param surface The texture surface. + * @param type The texture type (plain or tiled). + * @param opacity The opacity of the texture (0 to 1). + * @param matrix Optional transformation matrix. + * @return A pointer to the created `plutovg_paint_t` object. + */ +PLUTOVG_API plutovg_paint_t* plutovg_paint_create_texture(plutovg_surface_t* surface, plutovg_texture_type_t type, float opacity, const plutovg_matrix_t* matrix); + +/** + * @brief Increments the reference count of a paint object. + * + * @param paint A pointer to the `plutovg_paint_t` object. + * @return A pointer to the referenced `plutovg_paint_t` object. + */ +PLUTOVG_API plutovg_paint_t* plutovg_paint_reference(plutovg_paint_t* paint); + +/** + * @brief Decrements the reference count and destroys the paint if the count reaches zero. + * + * @param paint A pointer to the `plutovg_paint_t` object. + */ +PLUTOVG_API void plutovg_paint_destroy(plutovg_paint_t* paint); + +/** + * @brief Retrieves the reference count of a paint object. + * + * @param paint A pointer to the `plutovg_paint_t` object. + * @return The reference count of the `plutovg_paint_t` object. + */ +PLUTOVG_API int plutovg_paint_get_reference_count(const plutovg_paint_t* paint); + +/** + * @brief Defines fill rule types for filling paths. + */ typedef enum { - plutovg_texture_type_plain, - plutovg_texture_type_tiled -} plutovg_texture_type_t; + PLUTOVG_FILL_RULE_NON_ZERO, ///< Non-zero winding fill rule. + PLUTOVG_FILL_RULE_EVEN_ODD ///< Even-odd fill rule. +} plutovg_fill_rule_t; -void plutovg_texture_init(plutovg_texture_t* texture, plutovg_surface_t* surface, plutovg_texture_type_t type); -void plutovg_texture_set_type(plutovg_texture_t* texture, plutovg_texture_type_t type); -plutovg_texture_type_t plutovg_texture_get_type(const plutovg_texture_t* texture); -void plutovg_texture_set_matrix(plutovg_texture_t* texture, const plutovg_matrix_t* matrix); -void plutovg_texture_get_matrix(const plutovg_texture_t* texture, plutovg_matrix_t* matrix); -void plutovg_texture_set_surface(plutovg_texture_t* texture, plutovg_surface_t* surface); -plutovg_surface_t* plutovg_texture_get_surface(const plutovg_texture_t* texture); -void plutovg_texture_set_opacity(plutovg_texture_t* texture, double opacity); -double plutovg_texture_get_opacity(const plutovg_texture_t* texture); +/** + * @brief Defines compositing operations. + */ +typedef enum { + PLUTOVG_OPERATOR_CLEAR, ///< Clears the destination (resulting in a fully transparent image). + PLUTOVG_OPERATOR_SRC, ///< Source replaces destination. + PLUTOVG_OPERATOR_DST, ///< Destination is kept, source is ignored. + PLUTOVG_OPERATOR_SRC_OVER, ///< Source is composited over destination. + PLUTOVG_OPERATOR_DST_OVER, ///< Destination is composited over source. + PLUTOVG_OPERATOR_SRC_IN, ///< Source within destination (only the overlapping part of source is shown). + PLUTOVG_OPERATOR_DST_IN, ///< Destination within source. + PLUTOVG_OPERATOR_SRC_OUT, ///< Source outside destination (non-overlapping part of source is shown). + PLUTOVG_OPERATOR_DST_OUT, ///< Destination outside source. + PLUTOVG_OPERATOR_SRC_ATOP, ///< Source atop destination (source shown over destination but only in the destination's bounds). + PLUTOVG_OPERATOR_DST_ATOP, ///< Destination atop source (destination shown over source but only in the source's bounds). + PLUTOVG_OPERATOR_XOR ///< Source and destination are combined, but their overlapping regions are cleared. +} plutovg_operator_t; +/** + * @brief Defines the shape used at the ends of open subpaths. + */ typedef enum { - plutovg_line_cap_butt, - plutovg_line_cap_round, - plutovg_line_cap_square + PLUTOVG_LINE_CAP_BUTT, ///< Flat edge at the end of the stroke. + PLUTOVG_LINE_CAP_ROUND, ///< Rounded ends at the end of the stroke. + PLUTOVG_LINE_CAP_SQUARE ///< Square ends at the end of the stroke. } plutovg_line_cap_t; +/** + * @brief Defines the shape used at the corners of paths. + */ typedef enum { - plutovg_line_join_miter, - plutovg_line_join_round, - plutovg_line_join_bevel + PLUTOVG_LINE_JOIN_MITER, ///< Miter join with sharp corners. + PLUTOVG_LINE_JOIN_ROUND, ///< Rounded join. + PLUTOVG_LINE_JOIN_BEVEL ///< Beveled join with a flattened corner. } plutovg_line_join_t; -typedef enum { - plutovg_fill_rule_non_zero, - plutovg_fill_rule_even_odd -} plutovg_fill_rule_t; +/** + * @brief Represents a drawing context. + */ +typedef struct plutovg_canvas plutovg_canvas_t; -typedef enum { - plutovg_operator_src, - plutovg_operator_src_over, - plutovg_operator_dst_in, - plutovg_operator_dst_out -} plutovg_operator_t; +/** + * @brief Creates a drawing context on a surface. + * + * @param surface A pointer to a `plutovg_surface_t` object. + * @return A pointer to the newly created `plutovg_canvas_t` object. + */ +PLUTOVG_API plutovg_canvas_t* plutovg_canvas_create(plutovg_surface_t* surface); + +/** + * @brief Increases the reference count of the canvas. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The same pointer to the `plutovg_canvas_t` object. + */ +PLUTOVG_API plutovg_canvas_t* plutovg_canvas_reference(plutovg_canvas_t* canvas); + +/** + * @brief Decreases the reference count and destroys the canvas when it reaches zero. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_destroy(plutovg_canvas_t* canvas); + +/** + * @brief Retrieves the reference count of the canvas. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current reference count. + */ +PLUTOVG_API int plutovg_canvas_get_reference_count(const plutovg_canvas_t* canvas); + +/** + * @brief Gets the surface associated with the canvas. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return A pointer to the `plutovg_surface_t` object. + */ +PLUTOVG_API plutovg_surface_t* plutovg_canvas_get_surface(const plutovg_canvas_t* canvas); + +/** + * @brief Saves the current state of the canvas. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_save(plutovg_canvas_t* canvas); + +/** + * @brief Restores the canvas to the most recently saved state. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_restore(plutovg_canvas_t* canvas); + +/** + * @brief Sets the current paint to a solid color. + * + * If not set, the default paint is opaque black color. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param r The red component (0 to 1). + * @param g The green component (0 to 1). + * @param b The blue component (0 to 1). + */ +PLUTOVG_API void plutovg_canvas_set_rgb(plutovg_canvas_t* canvas, float r, float g, float b); + +/** + * @brief Sets the current paint to a solid color. + * + * If not set, the default paint is opaque black color. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param r The red component (0 to 1). + * @param g The green component (0 to 1). + * @param b The blue component (0 to 1). + * @param a The alpha component (0 to 1). + */ +PLUTOVG_API void plutovg_canvas_set_rgba(plutovg_canvas_t* canvas, float r, float g, float b, float a); + +/** + * @brief Sets the current paint to a solid color. + * + * If not set, the default paint is opaque black color. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param color A pointer to a `plutovg_color_t` object. + */ +PLUTOVG_API void plutovg_canvas_set_color(plutovg_canvas_t* canvas, const plutovg_color_t* color); + +/** + * @brief Sets the current paint to a linear gradient. + * + * If not set, the default paint is opaque black color. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x1 The x coordinate of the start point. + * @param y1 The y coordinate of the start point. + * @param x2 The x coordinate of the end point. + * @param y2 The y coordinate of the end point. + * @param spread The gradient spread method. + * @param stops Array of gradient stops. + * @param nstops Number of gradient stops. + * @param matrix Optional transformation matrix. + */ +PLUTOVG_API void plutovg_canvas_set_linear_gradient(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2, + plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix); + +/** + * @brief Sets the current paint to a radial gradient. + * + * If not set, the default paint is opaque black color. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param cx The x coordinate of the center. + * @param cy The y coordinate of the center. + * @param cr The radius of the gradient. + * @param fx The x coordinate of the focal point. + * @param fy The y coordinate of the focal point. + * @param fr The radius of the focal point. + * @param spread The gradient spread method. + * @param stops Array of gradient stops. + * @param nstops Number of gradient stops. + * @param matrix Optional transformation matrix. + */ +PLUTOVG_API void plutovg_canvas_set_radial_gradient(plutovg_canvas_t* canvas, float cx, float cy, float cr, float fx, float fy, float fr, + plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix); + +/** + * @brief Sets the current paint to a texture. + * + * If not set, the default paint is opaque black color. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param surface The texture surface. + * @param type The texture type (plain or tiled). + * @param opacity The opacity of the texture (0 to 1). + * @param matrix Optional transformation matrix. + */ +PLUTOVG_API void plutovg_canvas_set_texture(plutovg_canvas_t* canvas, plutovg_surface_t* surface, plutovg_texture_type_t type, float opacity, const plutovg_matrix_t* matrix); + +/** + * @brief Sets the current paint. + * + * If not set, the default paint is opaque black color. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param paint The paint to be used for subsequent drawing operations. + */ +PLUTOVG_API void plutovg_canvas_set_paint(plutovg_canvas_t* canvas, plutovg_paint_t* paint); + +/** + * @brief Retrieves the current paint. + * + * If not set, the default paint is opaque black color. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param color A pointer to a `plutovg_color_t` object where the current color will be stored. + * @return The current `plutovg_paint_t` used for drawing operations. If no paint is set, `NULL` is returned. + */ +PLUTOVG_API plutovg_paint_t* plutovg_canvas_get_paint(const plutovg_canvas_t* canvas, plutovg_color_t* color); + +/** + * @brief Sets the font face and size for text rendering on the canvas. + * + * If not set, the default font face is `NULL`, and the default face size is 12. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param face A pointer to a `plutovg_font_face_t` object representing the font face to use. + * @param size The size of the font, in pixels. This determines the height of the rendered text. + */ +PLUTOVG_API void plutovg_canvas_set_font(plutovg_canvas_t* canvas, plutovg_font_face_t* face, float size); + +/** + * @brief Sets the font face for text rendering on the canvas. + * + * If not set, the default font face is `NULL`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param face A pointer to a `plutovg_font_face_t` object representing the font face to use. + */ +PLUTOVG_API void plutovg_canvas_set_font_face(plutovg_canvas_t* canvas, plutovg_font_face_t* face); + +/** + * @brief Retrieves the current font face used for text rendering on the canvas. + * + * If not set, the default font face is `NULL`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return A pointer to a `plutovg_font_face_t` object representing the current font face. + */ +PLUTOVG_API plutovg_font_face_t* plutovg_canvas_get_font_face(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the font size for text rendering on the canvas. + * + * If not set, the default font size is 12. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param size The size of the font, in pixels. This value defines the height of the rendered text. + */ +PLUTOVG_API void plutovg_canvas_set_font_size(plutovg_canvas_t* canvas, float size); + +/** + * @brief Retrieves the current font size used for text rendering on the canvas. + * + * If not set, the default font size is 12. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current font size, in pixels. This value represents the height of the rendered text. + */ +PLUTOVG_API float plutovg_canvas_get_font_size(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the fill rule. + * + * If not set, the default fill rule is `PLUTOVG_FILL_RULE_NON_ZERO`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param winding The fill rule. + */ +PLUTOVG_API void plutovg_canvas_set_fill_rule(plutovg_canvas_t* canvas, plutovg_fill_rule_t winding); + +/** + * @brief Retrieves the current fill rule. + * + * If not set, the default fill rule is `PLUTOVG_FILL_RULE_NON_ZERO`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current fill rule. + */ +PLUTOVG_API plutovg_fill_rule_t plutovg_canvas_get_fill_rule(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the compositing operator. + * + * If not set, the default compositing operator is `PLUTOVG_OPERATOR_SRC_OVER`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param op The compositing operator. + */ +PLUTOVG_API void plutovg_canvas_set_operator(plutovg_canvas_t* canvas, plutovg_operator_t op); + +/** + * @brief Retrieves the current compositing operator. + * + * If not set, the default compositing operator is `PLUTOVG_OPERATOR_SRC_OVER`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current compositing operator. + */ +PLUTOVG_API plutovg_operator_t plutovg_canvas_get_operator(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the global opacity. + * + * If not set, the default global opacity is 1. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param opacity The opacity value (0 to 1). + */ +PLUTOVG_API void plutovg_canvas_set_opacity(plutovg_canvas_t* canvas, float opacity); + +/** + * @brief Retrieves the current global opacity. + * + * If not set, the default global opacity is 1. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current opacity value. + */ +PLUTOVG_API float plutovg_canvas_get_opacity(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the line width. + * + * If not set, the default line width is 1. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param line_width The width of the stroke. + */ +PLUTOVG_API void plutovg_canvas_set_line_width(plutovg_canvas_t* canvas, float line_width); + +/** + * @brief Retrieves the current line width. + * + * If not set, the default line width is 1. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current line width. + */ +PLUTOVG_API float plutovg_canvas_get_line_width(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the line cap style. + * + * If not set, the default line cap is `PLUTOVG_LINE_CAP_BUTT`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param line_cap The line cap style. + */ +PLUTOVG_API void plutovg_canvas_set_line_cap(plutovg_canvas_t* canvas, plutovg_line_cap_t line_cap); + +/** + * @brief Retrieves the current line cap style. + * + * If not set, the default line cap is `PLUTOVG_LINE_CAP_BUTT`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current line cap style. + */ +PLUTOVG_API plutovg_line_cap_t plutovg_canvas_get_line_cap(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the line join style. + * + * If not set, the default line join is `PLUTOVG_LINE_JOIN_MITER`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param line_join The line join style. + */ +PLUTOVG_API void plutovg_canvas_set_line_join(plutovg_canvas_t* canvas, plutovg_line_join_t line_join); + +/** + * @brief Retrieves the current line join style. + * + * If not set, the default line join is `PLUTOVG_LINE_JOIN_MITER`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current line join style. + */ +PLUTOVG_API plutovg_line_join_t plutovg_canvas_get_line_join(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the miter limit. + * + * If not set, the default miter limit is 10. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param miter_limit The miter limit value. + */ +PLUTOVG_API void plutovg_canvas_set_miter_limit(plutovg_canvas_t* canvas, float miter_limit); + +/** + * @brief Retrieves the current miter limit. + * + * If not set, the default miter limit is 10. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current miter limit value. + */ +PLUTOVG_API float plutovg_canvas_get_miter_limit(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the dash pattern. + * + * If not set, the default dash offset is 0, and the default dash array is `NULL`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param offset The dash offset. + * @param dashes Array of dash lengths. + * @param ndashes Number of dash lengths. + */ +PLUTOVG_API void plutovg_canvas_set_dash(plutovg_canvas_t* canvas, float offset, const float* dashes, int ndashes); + +/** + * @brief Sets the dash offset. + * + * If not set, the default dash offset is 0. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param offset The dash offset. + */ +PLUTOVG_API void plutovg_canvas_set_dash_offset(plutovg_canvas_t* canvas, float offset); + +/** + * @brief Retrieves the current dash offset. + * + * If not set, the default dash offset is 0. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current dash offset. + */ +PLUTOVG_API float plutovg_canvas_get_dash_offset(const plutovg_canvas_t* canvas); + +/** + * @brief Sets the dash pattern. + * + * If not set, the default dash array is `NULL`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param dashes Array of dash lengths. + * @param ndashes Number of dash lengths. + */ +PLUTOVG_API void plutovg_canvas_set_dash_array(plutovg_canvas_t* canvas, const float* dashes, int ndashes); + +/** + * @brief Retrieves the current dash pattern. + * + * If not set, the default dash array is `NULL`. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param dashes Pointer to store the dash array. + * @return The number of dash lengths. + */ +PLUTOVG_API int plutovg_canvas_get_dash_array(const plutovg_canvas_t* canvas, const float** dashes); + +/** + * @brief Translates the current transformation matrix by offsets `tx` and `ty`. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param tx The translation offset in the x-direction. + * @param ty The translation offset in the y-direction. + */ +PLUTOVG_API void plutovg_canvas_translate(plutovg_canvas_t* canvas, float tx, float ty); + +/** + * @brief Scales the current transformation matrix by factors `sx` and `sy`. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param sx The scaling factor in the x-direction. + * @param sy The scaling factor in the y-direction. + */ +PLUTOVG_API void plutovg_canvas_scale(plutovg_canvas_t* canvas, float sx, float sy); + +/** + * @brief Shears the current transformation matrix by factors `shx` and `shy`. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param shx The shearing factor in the x-direction. + * @param shy The shearing factor in the y-direction. + */ +PLUTOVG_API void plutovg_canvas_shear(plutovg_canvas_t* canvas, float shx, float shy); + +/** + * @brief Rotates the current transformation matrix by the specified angle (in radians). + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param angle The rotation angle in radians. + */ +PLUTOVG_API void plutovg_canvas_rotate(plutovg_canvas_t* canvas, float angle); + +/** + * @brief Multiplies the current transformation matrix with the specified `matrix`. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param matrix A pointer to the `plutovg_matrix_t` object. + */ +PLUTOVG_API void plutovg_canvas_transform(plutovg_canvas_t* canvas, const plutovg_matrix_t* matrix); + +/** + * @brief Resets the current transformation matrix to the identity matrix. + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_reset_matrix(plutovg_canvas_t* canvas); + +/** + * @brief Resets the current transformation matrix to the specified `matrix`. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param matrix A pointer to the `plutovg_matrix_t` object. + */ +PLUTOVG_API void plutovg_canvas_set_matrix(plutovg_canvas_t* canvas, const plutovg_matrix_t* matrix); + +/** + * @brief Stores the current transformation matrix in `matrix`. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param A pointer to the `plutovg_matrix_t` to store the matrix. + */ +PLUTOVG_API void plutovg_canvas_get_matrix(const plutovg_canvas_t* canvas, plutovg_matrix_t* matrix); + +/** + * @brief Transforms the point `(x, y)` using the current transformation matrix and stores the result in `(xx, yy)`. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the point to transform. + * @param y The y-coordinate of the point to transform. + * @param xx A pointer to store the transformed x-coordinate. + * @param yy A pointer to store the transformed y-coordinate. + */ +PLUTOVG_API void plutovg_canvas_map(const plutovg_canvas_t* canvas, float x, float y, float* xx, float* yy); + +/** + * @brief Transforms the `src` point using the current transformation matrix and stores the result in `dst`. + * @note `src` and `dst` can be identical. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param src A pointer to the `plutovg_point_t` point to transform. + * @param dst A pointer to the `plutovg_point_t` to store the transformed point. + */ +PLUTOVG_API void plutovg_canvas_map_point(const plutovg_canvas_t* canvas, const plutovg_point_t* src, plutovg_point_t* dst); + +/** + * @brief Transforms the `src` rectangle using the current transformation matrix and stores the result in `dst`. + * @note `src` and `dst` can be identical. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param src A pointer to the `plutovg_rect_t` rectangle to transform. + * @param dst A pointer to the `plutovg_rect_t` to store the transformed rectangle. + */ +PLUTOVG_API void plutovg_canvas_map_rect(const plutovg_canvas_t* canvas, const plutovg_rect_t* src, plutovg_rect_t* dst); + +/** + * @brief Moves the current point to a new position. + * + * Moves the current point to the specified coordinates without adding a line. + * This operation is added to the current path. Equivalent to the SVG `M` command. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the new position. + * @param y The y-coordinate of the new position. + */ +PLUTOVG_API void plutovg_canvas_move_to(plutovg_canvas_t* canvas, float x, float y); + +/** + * @brief Adds a straight line segment to the current path. + * + * Adds a straight line from the current point to the specified coordinates. + * This segment is added to the current path. Equivalent to the SVG `L` command. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the end point of the line. + * @param y The y-coordinate of the end point of the line. + */ +PLUTOVG_API void plutovg_canvas_line_to(plutovg_canvas_t* canvas, float x, float y); + +/** + * @brief Adds a quadratic Bézier curve to the current path. + * + * Adds a quadratic Bézier curve from the current point to the specified end point, + * using the given control point. This curve is added to the current path. Equivalent to the SVG `Q` command. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x1 The x-coordinate of the control point. + * @param y1 The y-coordinate of the control point. + * @param x2 The x-coordinate of the end point of the curve. + * @param y2 The y-coordinate of the end point of the curve. + */ +PLUTOVG_API void plutovg_canvas_quad_to(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2); + +/** + * @brief Adds a cubic Bézier curve to the current path. + * + * Adds a cubic Bézier curve from the current point to the specified end point, + * using the given control points. This curve is added to the current path. Equivalent to the SVG `C` command. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x1 The x-coordinate of the first control point. + * @param y1 The y-coordinate of the first control point. + * @param x2 The x-coordinate of the second control point. + * @param y2 The y-coordinate of the second control point. + * @param x3 The x-coordinate of the end point of the curve. + * @param y3 The y-coordinate of the end point of the curve. + */ +PLUTOVG_API void plutovg_canvas_cubic_to(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2, float x3, float y3); + +/** + * @brief Adds an elliptical arc to the current path. + * + * Adds an elliptical arc from the current point to the specified end point, + * defined by radii, rotation angle, and flags for arc type and direction. + * This arc segment is added to the current path. Equivalent to the SVG `A` command. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param rx The x-radius of the ellipse. + * @param ry The y-radius of the ellipse. + * @param angle The rotation angle of the ellipse in degrees. + * @param large_arc_flag If true, add the large arc; otherwise, add the small arc. + * @param sweep_flag If true, add the arc in the positive-angle direction; otherwise, in the negative-angle direction. + * @param x The x-coordinate of the end point. + * @param y The y-coordinate of the end point. + */ +PLUTOVG_API void plutovg_canvas_arc_to(plutovg_canvas_t* canvas, float rx, float ry, float angle, bool large_arc_flag, bool sweep_flag, float x, float y); + +/** + * @brief Adds a rectangle to the current path. + * + * Adds a rectangle with the specified position and dimensions to the current path. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the rectangle's origin. + * @param y The y-coordinate of the rectangle's origin. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + */ +PLUTOVG_API void plutovg_canvas_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h); + +/** + * @brief Adds a rounded rectangle to the current path. + * + * Adds a rectangle with rounded corners defined by the specified position, + * dimensions, and corner radii to the current path. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the rectangle's origin. + * @param y The y-coordinate of the rectangle's origin. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + * @param rx The x-radius of the corners. + * @param ry The y-radius of the corners. + */ +PLUTOVG_API void plutovg_canvas_round_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h, float rx, float ry); + +/** + * @brief Adds an ellipse to the current path. + * + * Adds an ellipse centered at the specified coordinates with the given radii to the current path. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param cx The x-coordinate of the ellipse's center. + * @param cy The y-coordinate of the ellipse's center. + * @param rx The x-radius of the ellipse. + * @param ry The y-radius of the ellipse. + */ +PLUTOVG_API void plutovg_canvas_ellipse(plutovg_canvas_t* canvas, float cx, float cy, float rx, float ry); + +/** + * @brief Adds a circle to the current path. + * + * Adds a circle centered at the specified coordinates with the given radius to the current path. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param cx The x-coordinate of the circle's center. + * @param cy The y-coordinate of the circle's center. + * @param r The radius of the circle. + */ +PLUTOVG_API void plutovg_canvas_circle(plutovg_canvas_t* canvas, float cx, float cy, float r); + +/** + * @brief Adds an arc to the current path. + * + * Adds an arc centered at the specified coordinates, with a given radius, + * starting and ending at the specified angles. The direction of the arc is + * determined by `ccw`. This arc segment is added to the current path. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param cx The x-coordinate of the arc's center. + * @param cy The y-coordinate of the arc's center. + * @param r The radius of the arc. + * @param a0 The starting angle of the arc in radians. + * @param a1 The ending angle of the arc in radians. + * @param ccw If true, add the arc counter-clockwise; otherwise, clockwise. + */ +PLUTOVG_API void plutovg_canvas_arc(plutovg_canvas_t* canvas, float cx, float cy, float r, float a0, float a1, bool ccw); + +/** + * @brief Adds a path to the current path. + * + * Appends the elements of the specified path to the current path. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param path A pointer to the `plutovg_path_t` object to be added. + */ +PLUTOVG_API void plutovg_canvas_add_path(plutovg_canvas_t* canvas, const plutovg_path_t* path); + +/** + * @brief Starts a new path on the canvas. + * + * Begins a new path, clearing any existing path data. The new path starts with no commands. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_new_path(plutovg_canvas_t* canvas); + +/** + * @brief Closes the current path. + * + * Closes the current path by adding a straight line back to the starting point. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_close_path(plutovg_canvas_t* canvas); + +/** + * @brief Retrieves the current point of the canvas. + * + * Gets the coordinates of the current point in the canvas, which is the last point + * added or moved to in the current path. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the current point. + * @param y The y-coordinate of the current point. + */ +PLUTOVG_API void plutovg_canvas_get_current_point(const plutovg_canvas_t* canvas, float* x, float* y); + +/** + * @brief Gets the current path from the canvas. + * + * Retrieves the path object representing the sequence of path commands added to the canvas. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @return The current path. + */ +PLUTOVG_API plutovg_path_t* plutovg_canvas_get_path(const plutovg_canvas_t* canvas); + +/** + * @brief Gets the bounding box of the filled region. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param extents The bounding box of the filled region. + */ +PLUTOVG_API void plutovg_canvas_fill_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents); + +/** + * @brief Gets the bounding box of the stroked region. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param extents The bounding box of the stroked region. + */ +PLUTOVG_API void plutovg_canvas_stroke_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents); + +/** + * @brief Gets the bounding box of the clipped region. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param extents The bounding box of the clipped region. + */ +PLUTOVG_API void plutovg_canvas_clip_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents); + +/** + * @brief A drawing operator that fills the current path according to the current fill rule. + * + * The current path will be cleared after this operation. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_fill(plutovg_canvas_t* canvas); + +/** + * @brief A drawing operator that strokes the current path according to the current stroke settings. + * + * The current path will be cleared after this operation. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_stroke(plutovg_canvas_t* canvas); + +/** + * @brief A drawing operator that intersects the current clipping region with the current path according to the current fill rule. + * + * The current path will be cleared after this operation. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_clip(plutovg_canvas_t* canvas); + +/** + * @brief A drawing operator that paints the current clipping region using the current paint. + * + * @note The current path will not be affected by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_paint(plutovg_canvas_t* canvas); + +/** + * @brief A drawing operator that fills the current path according to the current fill rule. + * + * The current path will be preserved after this operation. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_fill_preserve(plutovg_canvas_t* canvas); + +/** + * @brief A drawing operator that strokes the current path according to the current stroke settings. + * + * The current path will be preserved after this operation. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_stroke_preserve(plutovg_canvas_t* canvas); + +/** + * @brief A drawing operator that intersects the current clipping region with the current path according to the current fill rule. + * + * The current path will be preserved after this operation. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + */ +PLUTOVG_API void plutovg_canvas_clip_preserve(plutovg_canvas_t* canvas); + +/** + * @brief Fills a rectangle according to the current fill rule. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the rectangle's origin. + * @param y The y-coordinate of the rectangle's origin. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + */ +PLUTOVG_API void plutovg_canvas_fill_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h); + +/** + * @brief Fills a path according to the current fill rule. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param path The `plutovg_path_t` object. + */ +PLUTOVG_API void plutovg_canvas_fill_path(plutovg_canvas_t* canvas, const plutovg_path_t* path); + +/** + * @brief Strokes a rectangle with the current stroke settings. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the rectangle's origin. + * @param y The y-coordinate of the rectangle's origin. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + */ +PLUTOVG_API void plutovg_canvas_stroke_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h); + +/** + * @brief Strokes a path with the current stroke settings. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param path The `plutovg_path_t` object. + */ +PLUTOVG_API void plutovg_canvas_stroke_path(plutovg_canvas_t* canvas, const plutovg_path_t* path); + +/** + * @brief Intersects the current clipping region with a rectangle according to the current fill rule. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param x The x-coordinate of the rectangle's origin. + * @param y The y-coordinate of the rectangle's origin. + * @param w The width of the rectangle. + * @param h The height of the rectangle. + */ +PLUTOVG_API void plutovg_canvas_clip_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h); + +/** + * @brief Intersects the current clipping region with a path according to the current fill rule. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param path The `plutovg_path_t` object. + */ +PLUTOVG_API void plutovg_canvas_clip_path(plutovg_canvas_t* canvas, const plutovg_path_t* path); + +/** + * @brief Adds a glyph to the current path at the specified origin. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param codepoint The glyph codepoint. + * @param x The x-coordinate of the origin. + * @param y The y-coordinate of the origin. + * @return The advance width of the glyph. + */ +PLUTOVG_API float plutovg_canvas_add_glyph(plutovg_canvas_t* canvas, plutovg_codepoint_t codepoint, float x, float y); + +/** + * @brief Adds text to the current path at the specified origin. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param text The text data. + * @param length The length of the text data, or -1 if null-terminated. + * @param encoding The encoding of the text data. + * @param x The x-coordinate of the origin. + * @param y The y-coordinate of the origin. + * @return The total advance width of the text. + */ +PLUTOVG_API float plutovg_canvas_add_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y); + +/** + * @brief Fills a text at the specified origin. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param text The text data. + * @param length The length of the text data, or -1 if null-terminated. + * @param encoding The encoding of the text data. + * @param x The x-coordinate of the origin. + * @param y The y-coordinate of the origin. + * @return The total advance width of the text. + */ +PLUTOVG_API float plutovg_canvas_fill_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y); + +/** + * @brief Strokes a text at the specified origin. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param text The text data. + * @param length The length of the text data, or -1 if null-terminated. + * @param encoding The encoding of the text data. + * @param x The x-coordinate of the origin. + * @param y The y-coordinate of the origin. + * @return The total advance width of the text. + */ +PLUTOVG_API float plutovg_canvas_stroke_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y); + +/** + * @brief Intersects the current clipping region with text at the specified origin. + * + * @note The current path will be cleared by this operation. + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param text The text data. + * @param length The length of the text data, or -1 if null-terminated. + * @param encoding The encoding of the text data. + * @param x The x-coordinate of the origin. + * @param y The y-coordinate of the origin. + * @return The total advance width of the text. + */ +PLUTOVG_API float plutovg_canvas_clip_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y); + +/** + * @brief Retrieves font metrics for the current font. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param ascent The ascent of the font. + * @param descent The descent of the font. + * @param line_gap The line gap of the font. + * @param extents The bounding box of the font. + */ +PLUTOVG_API void plutovg_canvas_font_metrics(const plutovg_canvas_t* canvas, float* ascent, float* descent, float* line_gap, plutovg_rect_t* extents); + +/** + * @brief Retrieves metrics for a specific glyph. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param codepoint The glyph codepoint. + * @param advance_width The advance width of the glyph. + * @param left_side_bearing The left side bearing of the glyph. + * @param extents The bounding box of the glyph. + */ +PLUTOVG_API void plutovg_canvas_glyph_metrics(plutovg_canvas_t* canvas, plutovg_codepoint_t codepoint, float* advance_width, float* left_side_bearing, plutovg_rect_t* extents); -typedef struct plutovg plutovg_t; - -plutovg_t* plutovg_create(plutovg_surface_t* surface); -plutovg_t* plutovg_reference(plutovg_t* pluto); -void plutovg_destroy(plutovg_t* pluto); -int plutovg_get_reference_count(const plutovg_t* pluto); -void plutovg_save(plutovg_t* pluto); -void plutovg_restore(plutovg_t* pluto); - -plutovg_color_t* plutovg_set_rgb(plutovg_t* pluto, double r, double g, double b); -plutovg_color_t* plutovg_set_rgba(plutovg_t* pluto, double r, double g, double b, double a); -plutovg_color_t* plutovg_set_color(plutovg_t* pluto, const plutovg_color_t* color); - -plutovg_gradient_t* plutovg_set_linear_gradient(plutovg_t* pluto, double x1, double y1, double x2, double y2); -plutovg_gradient_t* plutovg_set_radial_gradient(plutovg_t* pluto, double cx, double cy, double cr, double fx, double fy, double fr); - -plutovg_texture_t* plutovg_set_texture_surface(plutovg_t* pluto, plutovg_surface_t* surface, double x, double y); -plutovg_texture_t* plutovg_set_texture(plutovg_t* pluto, plutovg_surface_t* surface, plutovg_texture_type_t type); - -void plutovg_set_operator(plutovg_t* pluto, plutovg_operator_t op); -void plutovg_set_opacity(plutovg_t* pluto, double opacity); -void plutovg_set_fill_rule(plutovg_t* pluto, plutovg_fill_rule_t fill_rule); -plutovg_operator_t plutovg_get_operator(const plutovg_t* pluto); -double plutovg_get_opacity(const plutovg_t* pluto); -plutovg_fill_rule_t plutovg_get_fill_rule(const plutovg_t* pluto); - -void plutovg_set_line_width(plutovg_t* pluto, double width); -void plutovg_set_line_cap(plutovg_t* pluto, plutovg_line_cap_t cap); -void plutovg_set_line_join(plutovg_t* pluto, plutovg_line_join_t join); -void plutovg_set_miter_limit(plutovg_t* pluto, double limit); -void plutovg_set_dash(plutovg_t* pluto, double offset, const double* data, int size); -double plutovg_get_line_width(const plutovg_t* pluto); -plutovg_line_cap_t plutovg_get_line_cap(const plutovg_t* pluto); -plutovg_line_join_t plutovg_get_line_join(const plutovg_t* pluto); -double plutovg_get_miter_limit(const plutovg_t* pluto); - -void plutovg_translate(plutovg_t* pluto, double x, double y); -void plutovg_scale(plutovg_t* pluto, double x, double y); -void plutovg_rotate(plutovg_t* pluto, double radians, double x, double y); -void plutovg_transform(plutovg_t* pluto, const plutovg_matrix_t* matrix); -void plutovg_set_matrix(plutovg_t* pluto, const plutovg_matrix_t* matrix); -void plutovg_identity_matrix(plutovg_t* pluto); -void plutovg_get_matrix(const plutovg_t* pluto, plutovg_matrix_t* matrix); - -void plutovg_move_to(plutovg_t* pluto, double x, double y); -void plutovg_line_to(plutovg_t* pluto, double x, double y); -void plutovg_quad_to(plutovg_t* pluto, double x1, double y1, double x2, double y2); -void plutovg_cubic_to(plutovg_t* pluto, double x1, double y1, double x2, double y2, double x3, double y3); -void plutovg_rel_move_to(plutovg_t* pluto, double x, double y); -void plutovg_rel_line_to(plutovg_t* pluto, double x, double y); -void plutovg_rel_quad_to(plutovg_t* pluto, double x1, double y1, double x2, double y2); -void plutovg_rel_cubic_to(plutovg_t* pluto, double x1, double y1, double x2, double y2, double x3, double y3); -void plutovg_rect(plutovg_t* pluto, double x, double y, double w, double h); -void plutovg_round_rect(plutovg_t* pluto, double x, double y, double w, double h, double rx, double ry); -void plutovg_ellipse(plutovg_t* pluto, double cx, double cy, double rx, double ry); -void plutovg_circle(plutovg_t* pluto, double cx, double cy, double r); -void plutovg_add_path(plutovg_t* pluto, const plutovg_path_t* path); -void plutovg_new_path(plutovg_t* pluto); -void plutovg_close_path(plutovg_t* pluto); -plutovg_path_t* plutovg_get_path(const plutovg_t* pluto); - -void plutovg_fill(plutovg_t* pluto); -void plutovg_stroke(plutovg_t* pluto); -void plutovg_clip(plutovg_t* pluto); -void plutovg_paint(plutovg_t* pluto); - -void plutovg_fill_preserve(plutovg_t* pluto); -void plutovg_stroke_preserve(plutovg_t* pluto); -void plutovg_clip_preserve(plutovg_t* pluto); -void plutovg_reset_clip(plutovg_t* pluto); +/** + * @brief Retrieves the extents of a text. + * + * @param canvas A pointer to a `plutovg_canvas_t` object. + * @param text The text data. + * @param length The length of the text data, or -1 if null-terminated. + * @param encoding The encoding of the text data. + * @param extents The bounding box of the text. + * @return The total advance width of the text. + */ +PLUTOVG_API float plutovg_canvas_text_extents(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, plutovg_rect_t* extents); #ifdef __cplusplus } diff --git a/vendor/lunasvg/LICENSE b/vendor/lunasvg/LICENSE index ce476ed0dd..0c17a4b39b 100644 --- a/vendor/lunasvg/LICENSE +++ b/vendor/lunasvg/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Nwutobo Samuel Ugochukwu +Copyright (c) 2020-2024 Samuel Ugochukwu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/lunasvg/README.md b/vendor/lunasvg/README.md index 1cff727214..0f941b4b05 100644 --- a/vendor/lunasvg/README.md +++ b/vendor/lunasvg/README.md @@ -1,14 +1,12 @@ -[![Releases](https://img.shields.io/badge/Version-2.3.8-orange.svg)](https://github.com/sammycage/lunasvg/releases) +[![Releases](https://img.shields.io/badge/Version-3.2.0-orange.svg)](https://github.com/sammycage/lunasvg/releases) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/sammycage/lunasvg/blob/master/LICENSE) -[![Build Status](https://github.com/sammycage/lunasvg/actions/workflows/ci.yml/badge.svg)](https://github.com/sammycage/lunasvg/actions) +[![Build Status](https://github.com/sammycage/lunasvg/actions/workflows/main.yml/badge.svg)](https://github.com/sammycage/lunasvg/actions) -> If you like the work lunasvg is doing please consider a small donation : [![Donate](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://www.paypal.me/sammycage) +# LunaSVG -# LunaSVG - SVG rendering library in C++ +LunaSVG is an SVG rendering library in C++, designed to be lightweight and portable, offering efficient rendering and manipulation of Scalable Vector Graphics (SVG) files. -![LunaSVG](https://github.com/sammycage/lunasvg/blob/master/luna.png) - -## Example +## Basic Usage ```cpp #include @@ -18,67 +16,194 @@ using namespace lunasvg; int main() { auto document = Document::loadFromFile("tiger.svg"); + if(document == nullptr) + return -1; auto bitmap = document->renderToBitmap(); + if(bitmap.isNull()) + return -1; + bitmap.writeToPng("tiger.png"); + return 0; +} + +``` + +![tiger.png](https://github.com/user-attachments/assets/b87bbf92-6dd1-4b29-a890-99cfffce66b8) - // do something useful with the bitmap here. +--- +## Dynamic Styling + +```cpp +#include + +using namespace lunasvg; + +static const char kLandspaceContent[] = R"SVG( + + + + + + + + + + + + + + + + + + + + + +)SVG"; + +static const char kSummerStyle[] = R"CSS( +.sky { fill: #4A90E2; } +.sun { fill: #FF7F00; } +.mountain { fill: #2E3A59; } +.cloud { fill: #FFFFFF; opacity: 0.8; } +.ground { fill: #2E8B57; } +)CSS"; + +static const char kWinterStyle[] = R"CSS( +.sky { fill: #87CEEB; } +.sun { fill: #ADD8E6; } +.mountain { fill: #2F4F4F; } +.cloud { fill: #FFFFFF; opacity: 0.8; } +.ground { fill: #FFFAFA; } +)CSS"; + +int main() +{ + auto document = Document::loadFromData(kLandspaceContent); + + document->applyStyleSheet(kSummerStyle); + document->renderToBitmap().writeToPng("summer.png"); + + document->applyStyleSheet(kWinterStyle); + document->renderToBitmap().writeToPng("winter.png"); return 0; } - ``` +| `summer.png` | `winter.png` | +| --- | --- | +| ![summer.png](https://github.com/user-attachments/assets/c7f16780-23f8-4acd-906a-2242f2d0d33b) | ![winter.png](https://github.com/user-attachments/assets/fdd65288-11c7-4e16-bb5a-2bf28de57145) | + ## Features -- Basic Shapes -- Document Structures -- Coordinate Systems, Transformations and Units -- SolidColors -- Gradients -- Patterns -- Masks -- ClipPaths -- Markers -- StyleSheet +LunaSVG supports nearly all graphical features outlined in the SVG 1.1 and SVG 1.2 Tiny specifications. The primary exceptions are animation, filters, and scripts. As LunaSVG is designed for static rendering, animation is unlikely to be supported in the future. However, support for filters may be added. It currently handles a wide variety of elements, including: -## TODO +`` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `