First Commit
This commit is contained in:
4
3rdparty/plutosvg/.github/FUNDING.yml
vendored
Normal file
4
3rdparty/plutosvg/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
buy_me_a_coffee: sammycage
|
||||
custom: ['https://www.paypal.me/sammycage']
|
||||
63
3rdparty/plutosvg/.github/workflows/main.yml
vendored
Normal file
63
3rdparty/plutosvg/.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
name: Build
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build with meson
|
||||
run: |
|
||||
pip install meson
|
||||
pip install ninja
|
||||
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
|
||||
- name: Build with cmake
|
||||
run: |
|
||||
cmake .
|
||||
cmake --build .
|
||||
|
||||
macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build with meson
|
||||
run: |
|
||||
pip install meson
|
||||
pip install ninja
|
||||
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
|
||||
- name: Build with cmake
|
||||
run: |
|
||||
cmake .
|
||||
cmake --build .
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build with meson
|
||||
run: |
|
||||
pip install meson
|
||||
pip install ninja
|
||||
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
|
||||
- name: Build with cmake
|
||||
run: |
|
||||
cmake .
|
||||
cmake --build .
|
||||
2
3rdparty/plutosvg/.gitignore
vendored
Normal file
2
3rdparty/plutosvg/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
*.user
|
||||
3
3rdparty/plutosvg/.gitmodules
vendored
Normal file
3
3rdparty/plutosvg/.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "plutovg"]
|
||||
path = plutovg
|
||||
url = https://github.com/sammycage/plutovg.git
|
||||
105
3rdparty/plutosvg/CMakeLists.txt
vendored
Normal file
105
3rdparty/plutosvg/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
set(PLUTOSVG_VERSION_MAJOR 0)
|
||||
set(PLUTOSVG_VERSION_MINOR 0)
|
||||
set(PLUTOSVG_VERSION_MICRO 6)
|
||||
|
||||
project(plutosvg LANGUAGES C VERSION ${PLUTOSVG_VERSION_MAJOR}.${PLUTOSVG_VERSION_MINOR}.${PLUTOSVG_VERSION_MICRO})
|
||||
|
||||
find_package(plutovg 0.0.4 QUIET)
|
||||
if(NOT plutovg_FOUND)
|
||||
add_subdirectory(plutovg)
|
||||
endif()
|
||||
|
||||
set(plutosvg_sources
|
||||
source/plutosvg.h
|
||||
source/plutosvg-ft.h
|
||||
source/plutosvg.c
|
||||
)
|
||||
|
||||
add_library(plutosvg ${plutosvg_sources})
|
||||
add_library(plutosvg::plutosvg ALIAS plutosvg)
|
||||
|
||||
set_target_properties(plutosvg PROPERTIES
|
||||
SOVERSION ${PLUTOSVG_VERSION_MAJOR}
|
||||
C_VISIBILITY_PRESET hidden
|
||||
C_STANDARD_REQUIRED ON
|
||||
C_STANDARD 99
|
||||
)
|
||||
|
||||
target_include_directories(plutosvg PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source
|
||||
)
|
||||
|
||||
target_include_directories(plutosvg PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/source>
|
||||
$<INSTALL_INTERFACE:include/plutosvg>
|
||||
)
|
||||
|
||||
target_link_libraries(plutosvg PUBLIC plutovg::plutovg)
|
||||
|
||||
find_library(MATH_LIBRARY m)
|
||||
if(MATH_LIBRARY)
|
||||
target_link_libraries(plutosvg PUBLIC ${MATH_LIBRARY})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(plutosvg PRIVATE PLUTOSVG_BUILD)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(plutosvg PUBLIC PLUTOSVG_BUILD_STATIC)
|
||||
endif()
|
||||
|
||||
option(PLUTOSVG_ENABLE_FREETYPE "Enable Freetype integration" OFF)
|
||||
if(PLUTOSVG_ENABLE_FREETYPE)
|
||||
find_package(Freetype 2.12 REQUIRED)
|
||||
target_compile_definitions(plutosvg PUBLIC PLUTOSVG_HAS_FREETYPE)
|
||||
target_include_directories(plutosvg PUBLIC ${FREETYPE_INCLUDE_DIRS})
|
||||
target_link_libraries(plutosvg PUBLIC ${FREETYPE_LIBRARIES})
|
||||
endif()
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/plutosvgConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/plutosvgConfig.cmake"
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/plutosvg
|
||||
)
|
||||
|
||||
write_basic_package_version_file(plutosvgConfigVersion.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/plutosvg.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/plutosvg-ft.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/plutosvg
|
||||
)
|
||||
|
||||
install(TARGETS plutosvg
|
||||
EXPORT plutosvgTargets
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
install(EXPORT plutosvgTargets
|
||||
FILE plutosvgTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/plutosvg
|
||||
NAMESPACE plutosvg::
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/plutosvgConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/plutosvgConfigVersion.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/plutosvg
|
||||
)
|
||||
|
||||
export(EXPORT plutosvgTargets
|
||||
FILE ${CMAKE_CURRENT_BINARY_DIR}/plutosvgTargets.cmake
|
||||
NAMESPACE plutosvg::
|
||||
)
|
||||
|
||||
option(PLUTOSVG_BUILD_EXAMPLES "Build examples" ON)
|
||||
if(PLUTOSVG_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
21
3rdparty/plutosvg/LICENSE
vendored
Normal file
21
3rdparty/plutosvg/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2025 Samuel Ugochukwu <sammycageagle@gmail.com>
|
||||
|
||||
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.
|
||||
87
3rdparty/plutosvg/README.md
vendored
Normal file
87
3rdparty/plutosvg/README.md
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||

|
||||
|
||||
# PlutoSVG
|
||||
|
||||
PlutoSVG is a compact and efficient SVG rendering library written in C. It is specifically designed for parsing and rendering SVG documents embedded in OpenType fonts, providing an optimal balance between speed and minimal memory usage. It is also suitable for rendering scalable icons.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```c
|
||||
#include <plutosvg.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
plutosvg_document_t* document = plutosvg_document_load_from_file("camera.svg", -1, -1);
|
||||
if(document == NULL) {
|
||||
printf("Unable to load: camera.svg\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
plutovg_surface_t* surface = plutosvg_document_render_to_surface(document, NULL, -1, -1, NULL, NULL, NULL);
|
||||
plutovg_surface_write_to_png(surface, "camera.png");
|
||||
plutosvg_document_destroy(document);
|
||||
plutovg_surface_destroy(surface);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Integrating with FreeType
|
||||
|
||||
```c
|
||||
#include <plutosvg-ft.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_MODULE_H
|
||||
|
||||
int main(void)
|
||||
{
|
||||
FT_Library library;
|
||||
|
||||
// Initialize the FreeType library
|
||||
if(FT_Init_FreeType(&library)) {
|
||||
// Handle error
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set PlutoSVG hooks for the SVG module
|
||||
if(FT_Property_Set(library, "ot-svg", "svg-hooks", &plutosvg_ft_hooks)) {
|
||||
// Handle error
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Your code here
|
||||
|
||||
// Clean up
|
||||
FT_Done_FreeType(library);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
Follow the steps below to install PlutoSVG using either [Meson](https://mesonbuild.com/) or [CMake](https://cmake.org/).
|
||||
|
||||
### Using Meson
|
||||
|
||||
```bash
|
||||
git clone https://github.com/sammycage/plutosvg.git
|
||||
cd plutosvg
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
meson install -C build
|
||||
```
|
||||
|
||||
### Using CMake
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/sammycage/plutosvg.git
|
||||
cd plutosvg
|
||||
cmake -B build .
|
||||
cmake --build build
|
||||
cmake --install build
|
||||
```
|
||||
BIN
3rdparty/plutosvg/camera.png
vendored
Normal file
BIN
3rdparty/plutosvg/camera.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
6
3rdparty/plutosvg/cmake/plutosvgConfig.cmake.in
vendored
Normal file
6
3rdparty/plutosvg/cmake/plutosvgConfig.cmake.in
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(plutovg)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/plutosvgTargets.cmake")
|
||||
15
3rdparty/plutosvg/examples/CMakeLists.txt
vendored
Normal file
15
3rdparty/plutosvg/examples/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
FILE(COPY camera.svg DESTINATION "${CMAKE_BINARY_DIR}/examples")
|
||||
|
||||
add_executable(camera2png camera2png.c)
|
||||
target_link_libraries(camera2png plutosvg)
|
||||
|
||||
add_executable(svg2png svg2png.c)
|
||||
target_link_libraries(svg2png plutosvg)
|
||||
|
||||
if(PLUTOSVG_ENABLE_FREETYPE)
|
||||
add_executable(emoji2png emoji2png.c)
|
||||
target_link_libraries(emoji2png plutosvg)
|
||||
endif()
|
||||
340
3rdparty/plutosvg/examples/camera.svg
vendored
Normal file
340
3rdparty/plutosvg/examples/camera.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 130 KiB |
34
3rdparty/plutosvg/examples/camera2png.c
vendored
Normal file
34
3rdparty/plutosvg/examples/camera2png.c
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <plutosvg.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
plutosvg_document_t* document = NULL;
|
||||
plutovg_surface_t* surface = NULL;
|
||||
|
||||
fprintf(stdout, "Loading 'camera.svg'\n");
|
||||
document = plutosvg_document_load_from_file("camera.svg", -1, -1);
|
||||
if(document == NULL) {
|
||||
fprintf(stderr, "Unable to load 'camera.svg'\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Rendering 'camera.svg'\n");
|
||||
surface = plutosvg_document_render_to_surface(document, NULL, -1, -1, NULL, NULL, NULL);
|
||||
if(surface == NULL) {
|
||||
fprintf(stderr, "Unable to render 'camera.svg'\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Writing 'camera.png'\n");
|
||||
if(!plutovg_surface_write_to_png(surface, "camera.png")) {
|
||||
fprintf(stderr, "Unable to write 'camera.png'\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
plutovg_surface_destroy(surface);
|
||||
plutosvg_document_destroy(document);
|
||||
return 0;
|
||||
}
|
||||
56
3rdparty/plutosvg/examples/emoji2png.c
vendored
Normal file
56
3rdparty/plutosvg/examples/emoji2png.c
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <plutosvg.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_MODULE_H
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if(argc != 4) {
|
||||
fprintf(stderr, "Usage: emoji2png font codepoint size\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* filename = argv[1];
|
||||
FT_ULong codepoint = strtoul(argv[2], NULL, 16);
|
||||
FT_ULong size = strtoul(argv[3], NULL, 10);
|
||||
|
||||
FT_Library library = NULL;
|
||||
FT_Face face = NULL;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
|
||||
if((error = FT_Init_FreeType(&library)))
|
||||
goto cleanup;
|
||||
if((error = FT_Property_Set(library, "ot-svg", "svg-hooks", plutosvg_ft_svg_hooks())))
|
||||
goto cleanup;
|
||||
if((error = FT_New_Face(library, filename, 0, &face)))
|
||||
goto cleanup;
|
||||
if((error = FT_Set_Pixel_Sizes(face, 0, size)))
|
||||
goto cleanup;
|
||||
if((error = FT_Load_Char(face, codepoint, FT_LOAD_RENDER | FT_LOAD_COLOR))) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
|
||||
plutovg_surface_t* surface = plutovg_surface_create_for_data(
|
||||
face->glyph->bitmap.buffer, face->glyph->bitmap.width,
|
||||
face->glyph->bitmap.rows, face->glyph->bitmap.pitch
|
||||
);
|
||||
|
||||
char name[64];
|
||||
sprintf(name, "emoji-%lx.png", codepoint);
|
||||
plutovg_surface_write_to_png(surface, name);
|
||||
plutovg_surface_destroy(surface);
|
||||
fprintf(stdout, "Generated Emoji: %s\n", name);
|
||||
} else {
|
||||
fprintf(stderr, "The glyph for codepoint %lx is not in color mode.\n", codepoint);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if(error) fprintf(stderr, "freetype error: %s\n", FT_Error_String(error));
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(library);
|
||||
return error;
|
||||
}
|
||||
8
3rdparty/plutosvg/examples/meson.build
vendored
Normal file
8
3rdparty/plutosvg/examples/meson.build
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fs = import('fs')
|
||||
fs.copyfile('camera.svg')
|
||||
|
||||
executable('camera2png', 'camera2png.c', dependencies: plutosvg_dep)
|
||||
executable('svg2png', 'svg2png.c', dependencies: plutosvg_dep)
|
||||
if freetype_dep.found()
|
||||
executable('emoji2png', 'emoji2png.c', dependencies: [plutosvg_dep, freetype_dep])
|
||||
endif
|
||||
63
3rdparty/plutosvg/examples/svg2png.c
vendored
Normal file
63
3rdparty/plutosvg/examples/svg2png.c
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
#include <plutosvg.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
static double elapsed_time(clock_t start, clock_t end)
|
||||
{
|
||||
return ((double)(end - start)) / CLOCKS_PER_SEC;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if(argc != 3 && argc != 4) {
|
||||
fprintf(stderr, "Usage: svg2png input output [id]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* input = argv[1];
|
||||
const char* output = argv[2];
|
||||
const char* id = NULL;
|
||||
if(argc == 4) {
|
||||
id = argv[3];
|
||||
}
|
||||
|
||||
plutosvg_document_t* document = NULL;
|
||||
plutovg_surface_t* surface = NULL;
|
||||
clock_t start, end;
|
||||
|
||||
start = clock();
|
||||
document = plutosvg_document_load_from_file(input, -1, -1);
|
||||
end = clock();
|
||||
|
||||
if(document == NULL) {
|
||||
fprintf(stderr, "Unable to load '%s'\n", input);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Finished loading '%s' in %.3f seconds\n", input, elapsed_time(start, end));
|
||||
|
||||
start = clock();
|
||||
surface = plutosvg_document_render_to_surface(document, id, -1, -1, NULL, NULL, NULL);
|
||||
end = clock();
|
||||
|
||||
if(surface == NULL) {
|
||||
fprintf(stderr, "Unable to render '%s'\n", input);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Finished rendering '%s' in %.3f seconds\n", input, elapsed_time(start, end));
|
||||
|
||||
start = clock();
|
||||
if(!plutovg_surface_write_to_png(surface, output)) {
|
||||
fprintf(stderr, "Unable to write '%s'\n", output);
|
||||
goto cleanup;
|
||||
}
|
||||
end = clock();
|
||||
|
||||
fprintf(stdout, "Finished writing '%s' in %.3f seconds\n", output, elapsed_time(start, end));
|
||||
cleanup:
|
||||
plutovg_surface_destroy(surface);
|
||||
plutosvg_document_destroy(document);
|
||||
return 0;
|
||||
}
|
||||
72
3rdparty/plutosvg/meson.build
vendored
Normal file
72
3rdparty/plutosvg/meson.build
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
project('plutosvg', 'c',
|
||||
version: '0.0.6',
|
||||
license: 'MIT',
|
||||
meson_version: '>=0.64.0',
|
||||
default_options: ['c_std=c99']
|
||||
)
|
||||
|
||||
plutosvg_deps = []
|
||||
plutosvg_compile_args = []
|
||||
|
||||
plutovg_dep = dependency('plutovg',
|
||||
required: true,
|
||||
version: '>=0.0.4',
|
||||
fallback: ['plutovg', 'plutovg_dep']
|
||||
)
|
||||
|
||||
plutosvg_deps += [plutovg_dep]
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
math_dep = cc.find_library('m', required: false)
|
||||
if math_dep.found()
|
||||
plutosvg_deps += [math_dep]
|
||||
endif
|
||||
|
||||
freetype_dep = dependency('freetype2',
|
||||
required: get_option('freetype'),
|
||||
version: '>=2.12',
|
||||
allow_fallback: false
|
||||
)
|
||||
|
||||
if freetype_dep.found() and cc.has_type('SVG_RendererHooks', dependencies: freetype_dep, prefix: '#include <freetype/otsvg.h>')
|
||||
plutosvg_deps += [freetype_dep]
|
||||
plutosvg_compile_args += ['-DPLUTOSVG_HAS_FREETYPE']
|
||||
else
|
||||
freetype_dep = disabler()
|
||||
endif
|
||||
|
||||
if get_option('default_library') == 'static'
|
||||
plutosvg_compile_args += ['-DPLUTOSVG_BUILD_STATIC']
|
||||
endif
|
||||
|
||||
plutosvg_lib = library('plutosvg', 'source/plutosvg.c',
|
||||
include_directories: include_directories('source'),
|
||||
dependencies: plutosvg_deps,
|
||||
version: meson.project_version(),
|
||||
c_args: ['-DPLUTOSVG_BUILD'] + plutosvg_compile_args,
|
||||
cpp_args: ['-DPLUTOSVG_BUILD'] + plutosvg_compile_args,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
install: true
|
||||
)
|
||||
|
||||
plutosvg_dep = declare_dependency(
|
||||
link_with: plutosvg_lib,
|
||||
dependencies: plutovg_dep,
|
||||
include_directories: include_directories('source'),
|
||||
compile_args: plutosvg_compile_args
|
||||
)
|
||||
|
||||
meson.override_dependency('plutosvg', plutosvg_dep)
|
||||
install_headers('source/plutosvg.h', 'source/plutosvg-ft.h', subdir: 'plutosvg')
|
||||
|
||||
if not get_option('examples').disabled()
|
||||
subdir('examples')
|
||||
endif
|
||||
|
||||
pkgmod = import('pkgconfig')
|
||||
pkgmod.generate(plutosvg_lib,
|
||||
name: 'PlutoSVG',
|
||||
description: 'Tiny SVG rendering library',
|
||||
filebase: 'plutosvg',
|
||||
subdirs: 'plutosvg'
|
||||
)
|
||||
3
3rdparty/plutosvg/meson_options.txt
vendored
Normal file
3
3rdparty/plutosvg/meson_options.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
option('examples', type : 'feature', value : 'auto')
|
||||
option('tests', type : 'feature', value : 'auto')
|
||||
option('freetype', type : 'feature', value : 'auto')
|
||||
4
3rdparty/plutosvg/plutovg/.github/FUNDING.yml
vendored
Normal file
4
3rdparty/plutosvg/plutovg/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
buy_me_a_coffee: sammycage
|
||||
custom: ['https://www.paypal.me/sammycage']
|
||||
57
3rdparty/plutosvg/plutovg/.github/workflows/main.yml
vendored
Normal file
57
3rdparty/plutosvg/plutovg/.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: Build
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Build with meson
|
||||
run: |
|
||||
pip install meson
|
||||
pip install ninja
|
||||
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
|
||||
- name: Build with cmake
|
||||
run: |
|
||||
cmake .
|
||||
cmake --build .
|
||||
|
||||
macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Build with meson
|
||||
run: |
|
||||
pip install meson
|
||||
pip install ninja
|
||||
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
|
||||
- name: Build with cmake
|
||||
run: |
|
||||
cmake .
|
||||
cmake --build .
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Build with meson
|
||||
run: |
|
||||
pip install meson
|
||||
pip install ninja
|
||||
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
|
||||
- name: Build with cmake
|
||||
run: |
|
||||
cmake .
|
||||
cmake --build .
|
||||
2
3rdparty/plutosvg/plutovg/.gitignore
vendored
Normal file
2
3rdparty/plutosvg/plutovg/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
*.user
|
||||
111
3rdparty/plutosvg/plutovg/CMakeLists.txt
vendored
Normal file
111
3rdparty/plutosvg/plutovg/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
set(PLUTOVG_VERSION_MAJOR 0)
|
||||
set(PLUTOVG_VERSION_MINOR 0)
|
||||
set(PLUTOVG_VERSION_MICRO 13)
|
||||
|
||||
project(plutovg LANGUAGES C VERSION ${PLUTOVG_VERSION_MAJOR}.${PLUTOVG_VERSION_MINOR}.${PLUTOVG_VERSION_MICRO})
|
||||
|
||||
set(plutovg_sources
|
||||
source/plutovg-blend.c
|
||||
source/plutovg-canvas.c
|
||||
source/plutovg-font.c
|
||||
source/plutovg-matrix.c
|
||||
source/plutovg-paint.c
|
||||
source/plutovg-path.c
|
||||
source/plutovg-rasterize.c
|
||||
source/plutovg-surface.c
|
||||
source/plutovg-ft-math.c
|
||||
source/plutovg-ft-raster.c
|
||||
source/plutovg-ft-stroker.c
|
||||
)
|
||||
|
||||
set(plutovg_headers
|
||||
include/plutovg.h
|
||||
source/plutovg-private.h
|
||||
source/plutovg-utils.h
|
||||
source/plutovg-ft-math.h
|
||||
source/plutovg-ft-raster.h
|
||||
source/plutovg-ft-stroker.h
|
||||
source/plutovg-ft-types.h
|
||||
source/plutovg-stb-image-write.h
|
||||
source/plutovg-stb-image.h
|
||||
source/plutovg-stb-truetype.h
|
||||
)
|
||||
|
||||
add_library(plutovg ${plutovg_sources} ${plutovg_headers})
|
||||
add_library(plutovg::plutovg ALIAS plutovg)
|
||||
|
||||
set_target_properties(plutovg PROPERTIES
|
||||
SOVERSION ${PLUTOVG_VERSION_MAJOR}
|
||||
C_VISIBILITY_PRESET hidden
|
||||
C_STANDARD_REQUIRED ON
|
||||
C_STANDARD 99
|
||||
)
|
||||
|
||||
target_include_directories(plutovg PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source
|
||||
)
|
||||
|
||||
target_include_directories(plutovg PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include/plutovg>
|
||||
)
|
||||
|
||||
find_library(MATH_LIBRARY m)
|
||||
if(MATH_LIBRARY)
|
||||
target_link_libraries(plutovg PRIVATE ${MATH_LIBRARY})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(plutovg PRIVATE PLUTOVG_BUILD)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(plutovg PUBLIC PLUTOVG_BUILD_STATIC)
|
||||
endif()
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/plutovgConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/plutovgConfig.cmake"
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/plutovg
|
||||
)
|
||||
|
||||
write_basic_package_version_file(plutovgConfigVersion.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/plutovg.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/plutovg
|
||||
)
|
||||
|
||||
install(TARGETS plutovg
|
||||
EXPORT plutovgTargets
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
install(EXPORT plutovgTargets
|
||||
FILE plutovgTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/plutovg
|
||||
NAMESPACE plutovg::
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/plutovgConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/plutovgConfigVersion.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/plutovg
|
||||
)
|
||||
|
||||
export(EXPORT plutovgTargets
|
||||
FILE ${CMAKE_CURRENT_BINARY_DIR}/plutovgTargets.cmake
|
||||
NAMESPACE plutovg::
|
||||
)
|
||||
|
||||
option(PLUTOVG_BUILD_EXAMPLES "Build examples" ON)
|
||||
if(PLUTOVG_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
21
3rdparty/plutosvg/plutovg/LICENSE
vendored
Normal file
21
3rdparty/plutosvg/plutovg/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2025 Samuel Ugochukwu <sammycageagle@gmail.com>
|
||||
|
||||
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.
|
||||
99
3rdparty/plutosvg/plutovg/README.md
vendored
Normal file
99
3rdparty/plutosvg/plutovg/README.md
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
[](https://github.com/sammycage/plutovg/releases)
|
||||
[](https://github.com/sammycage/plutovg/blob/main/LICENSE)
|
||||
[](https://github.com/sammycage/plutovg/actions)
|
||||
[](https://www.codefactor.io/repository/github/sammycage/plutovg)
|
||||
|
||||
# PlutoVG
|
||||
PlutoVG is a standalone 2D vector graphics library in C.
|
||||
|
||||
## Features
|
||||
- Path Filling, Stroking and Dashing
|
||||
- Soild, Gradient and Texture Paints
|
||||
- Fonts and Texts
|
||||
- Clipping and Compositing
|
||||
- Transformations
|
||||
- Images
|
||||
|
||||
## Example
|
||||
```c
|
||||
#include <plutovg.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const int width = 150;
|
||||
const int height = 150;
|
||||
|
||||
const float center_x = width / 2.f;
|
||||
const float center_y = height / 2.f;
|
||||
const float face_radius = 70;
|
||||
const float mouth_radius = 50;
|
||||
const float eye_radius = 10;
|
||||
const float eye_offset_x = 25;
|
||||
const float eye_offset_y = 20;
|
||||
const float eye_x = center_x - eye_offset_x;
|
||||
const float eye_y = center_y - eye_offset_y;
|
||||
|
||||
plutovg_surface_t* surface = plutovg_surface_create(width, height);
|
||||
plutovg_canvas_t* canvas = plutovg_canvas_create(surface);
|
||||
|
||||
plutovg_canvas_save(canvas);
|
||||
plutovg_canvas_arc(canvas, center_x, center_y, face_radius, 0, PLUTOVG_TWO_PI, 0);
|
||||
plutovg_canvas_set_rgb(canvas, 1, 1, 0);
|
||||
plutovg_canvas_fill_preserve(canvas);
|
||||
plutovg_canvas_set_rgb(canvas, 0, 0, 0);
|
||||
plutovg_canvas_set_line_width(canvas, 5);
|
||||
plutovg_canvas_stroke(canvas);
|
||||
plutovg_canvas_restore(canvas);
|
||||
|
||||
plutovg_canvas_save(canvas);
|
||||
plutovg_canvas_arc(canvas, eye_x, eye_y, eye_radius, 0, PLUTOVG_TWO_PI, 0);
|
||||
plutovg_canvas_arc(canvas, center_x + eye_offset_x, eye_y, eye_radius, 0, PLUTOVG_TWO_PI, 0);
|
||||
plutovg_canvas_set_rgb(canvas, 0, 0, 0);
|
||||
plutovg_canvas_fill(canvas);
|
||||
plutovg_canvas_restore(canvas);
|
||||
|
||||
plutovg_canvas_save(canvas);
|
||||
plutovg_canvas_arc(canvas, center_x, center_y, mouth_radius, 0, PLUTOVG_PI, 0);
|
||||
plutovg_canvas_set_rgb(canvas, 0, 0, 0);
|
||||
plutovg_canvas_set_line_width(canvas, 5);
|
||||
plutovg_canvas_stroke(canvas);
|
||||
plutovg_canvas_restore(canvas);
|
||||
|
||||
plutovg_surface_write_to_png(surface, "smiley.png");
|
||||
plutovg_canvas_destroy(canvas);
|
||||
plutovg_surface_destroy(surface);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
output:
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
Follow the steps below to install PlutoVG using either [Meson](https://mesonbuild.com/) or [CMake](https://cmake.org/).
|
||||
|
||||
### Using Meson
|
||||
|
||||
```bash
|
||||
git clone https://github.com/sammycage/plutovg.git
|
||||
cd plutovg
|
||||
meson setup build
|
||||
meson compile -C build
|
||||
meson install -C build
|
||||
```
|
||||
|
||||
### Using CMake
|
||||
|
||||
```bash
|
||||
git clone https://github.com/sammycage/plutovg.git
|
||||
cd plutovg
|
||||
cmake -B build .
|
||||
cmake --build build
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
## Projects using PlutoVG
|
||||
- [LunaSVG](https://github.com/sammycage/lunasvg)
|
||||
- [PlutoSVG](https://github.com/sammycage/plutosvg)
|
||||
3
3rdparty/plutosvg/plutovg/cmake/plutovgConfig.cmake.in
vendored
Normal file
3
3rdparty/plutosvg/plutovg/cmake/plutovgConfig.cmake.in
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/plutovgTargets.cmake")
|
||||
2
3rdparty/plutosvg/plutovg/examples/CMakeLists.txt
vendored
Normal file
2
3rdparty/plutosvg/plutovg/examples/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
add_executable(smiley smiley.c)
|
||||
target_link_libraries(smiley plutovg)
|
||||
1
3rdparty/plutosvg/plutovg/examples/meson.build
vendored
Normal file
1
3rdparty/plutosvg/plutovg/examples/meson.build
vendored
Normal file
@@ -0,0 +1 @@
|
||||
executable('smiley', 'smiley.c', dependencies: plutovg_dep)
|
||||
48
3rdparty/plutosvg/plutovg/examples/smiley.c
vendored
Normal file
48
3rdparty/plutosvg/plutovg/examples/smiley.c
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <plutovg.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const int width = 150;
|
||||
const int height = 150;
|
||||
|
||||
const float center_x = width / 2.f;
|
||||
const float center_y = height / 2.f;
|
||||
const float face_radius = 70;
|
||||
const float mouth_radius = 50;
|
||||
const float eye_radius = 10;
|
||||
const float eye_offset_x = 25;
|
||||
const float eye_offset_y = 20;
|
||||
const float eye_x = center_x - eye_offset_x;
|
||||
const float eye_y = center_y - eye_offset_y;
|
||||
|
||||
plutovg_surface_t* surface = plutovg_surface_create(width, height);
|
||||
plutovg_canvas_t* canvas = plutovg_canvas_create(surface);
|
||||
|
||||
plutovg_canvas_save(canvas);
|
||||
plutovg_canvas_arc(canvas, center_x, center_y, face_radius, 0, PLUTOVG_TWO_PI, 0);
|
||||
plutovg_canvas_set_rgb(canvas, 1, 1, 0);
|
||||
plutovg_canvas_fill_preserve(canvas);
|
||||
plutovg_canvas_set_rgb(canvas, 0, 0, 0);
|
||||
plutovg_canvas_set_line_width(canvas, 5);
|
||||
plutovg_canvas_stroke(canvas);
|
||||
plutovg_canvas_restore(canvas);
|
||||
|
||||
plutovg_canvas_save(canvas);
|
||||
plutovg_canvas_arc(canvas, eye_x, eye_y, eye_radius, 0, PLUTOVG_TWO_PI, 0);
|
||||
plutovg_canvas_arc(canvas, center_x + eye_offset_x, eye_y, eye_radius, 0, PLUTOVG_TWO_PI, 0);
|
||||
plutovg_canvas_set_rgb(canvas, 0, 0, 0);
|
||||
plutovg_canvas_fill(canvas);
|
||||
plutovg_canvas_restore(canvas);
|
||||
|
||||
plutovg_canvas_save(canvas);
|
||||
plutovg_canvas_arc(canvas, center_x, center_y, mouth_radius, 0, PLUTOVG_PI, 0);
|
||||
plutovg_canvas_set_rgb(canvas, 0, 0, 0);
|
||||
plutovg_canvas_set_line_width(canvas, 5);
|
||||
plutovg_canvas_stroke(canvas);
|
||||
plutovg_canvas_restore(canvas);
|
||||
|
||||
plutovg_surface_write_to_png(surface, "smiley.png");
|
||||
plutovg_canvas_destroy(canvas);
|
||||
plutovg_surface_destroy(surface);
|
||||
return 0;
|
||||
}
|
||||
2319
3rdparty/plutosvg/plutovg/include/plutovg.h
vendored
Normal file
2319
3rdparty/plutosvg/plutovg/include/plutovg.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
70
3rdparty/plutosvg/plutovg/meson.build
vendored
Normal file
70
3rdparty/plutosvg/plutovg/meson.build
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
project('plutovg', 'c',
|
||||
version: '0.0.13',
|
||||
license: 'MIT',
|
||||
meson_version: '>=0.59.0',
|
||||
default_options: ['c_std=c99']
|
||||
)
|
||||
|
||||
plutovg_deps = []
|
||||
plutovg_compile_args = []
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
plutovg_c_args = ['-DPLUTOVG_BUILD']
|
||||
plutovg_c_args += cc.get_supported_arguments(
|
||||
'-Wno-sign-compare',
|
||||
'-Wno-unused-function'
|
||||
)
|
||||
|
||||
math_dep = cc.find_library('m', required: false)
|
||||
if math_dep.found()
|
||||
plutovg_deps += [math_dep]
|
||||
endif
|
||||
|
||||
if get_option('default_library') == 'static'
|
||||
plutovg_compile_args += ['-DPLUTOVG_BUILD_STATIC']
|
||||
endif
|
||||
|
||||
plutovg_sources = [
|
||||
'source/plutovg-blend.c',
|
||||
'source/plutovg-canvas.c',
|
||||
'source/plutovg-font.c',
|
||||
'source/plutovg-matrix.c',
|
||||
'source/plutovg-paint.c',
|
||||
'source/plutovg-path.c',
|
||||
'source/plutovg-rasterize.c',
|
||||
'source/plutovg-surface.c',
|
||||
'source/plutovg-ft-math.c',
|
||||
'source/plutovg-ft-raster.c',
|
||||
'source/plutovg-ft-stroker.c'
|
||||
]
|
||||
|
||||
plutovg_lib = library('plutovg', plutovg_sources,
|
||||
include_directories: include_directories('include', 'source'),
|
||||
dependencies: plutovg_deps,
|
||||
version: meson.project_version(),
|
||||
c_args: plutovg_c_args,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
install: true
|
||||
)
|
||||
|
||||
plutovg_dep = declare_dependency(
|
||||
link_with: plutovg_lib,
|
||||
include_directories: include_directories('include'),
|
||||
compile_args: plutovg_compile_args
|
||||
)
|
||||
|
||||
meson.override_dependency('plutovg', plutovg_dep)
|
||||
install_headers('include/plutovg.h', subdir: 'plutovg')
|
||||
|
||||
if not get_option('examples').disabled()
|
||||
subdir('examples')
|
||||
endif
|
||||
|
||||
pkgmod = import('pkgconfig')
|
||||
pkgmod.generate(plutovg_lib,
|
||||
name: 'PlutoVG',
|
||||
description: 'Tiny 2D vector graphics library',
|
||||
filebase: 'plutovg',
|
||||
subdirs: 'plutovg'
|
||||
)
|
||||
2
3rdparty/plutosvg/plutovg/meson_options.txt
vendored
Normal file
2
3rdparty/plutosvg/plutovg/meson_options.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
option('examples', type : 'feature', value : 'auto')
|
||||
option('tests', type : 'feature', value : 'auto')
|
||||
BIN
3rdparty/plutosvg/plutovg/smiley.png
vendored
Normal file
BIN
3rdparty/plutosvg/plutovg/smiley.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
166
3rdparty/plutosvg/plutovg/source/FTL.TXT
vendored
Normal file
166
3rdparty/plutosvg/plutovg/source/FTL.TXT
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
The FreeType Project LICENSE
|
||||
----------------------------
|
||||
|
||||
2006-Jan-27
|
||||
|
||||
Copyright 1996-2002, 2006 by
|
||||
David Turner, Robert Wilhelm, and Werner Lemberg
|
||||
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The FreeType Project is distributed in several archive packages;
|
||||
some of them may contain, in addition to the FreeType font engine,
|
||||
various tools and contributions which rely on, or relate to, the
|
||||
FreeType Project.
|
||||
|
||||
This license applies to all files found in such packages, and
|
||||
which do not fall under their own explicit license. The license
|
||||
affects thus the FreeType font engine, the test programs,
|
||||
documentation and makefiles, at the very least.
|
||||
|
||||
This license was inspired by the BSD, Artistic, and IJG
|
||||
(Independent JPEG Group) licenses, which all encourage inclusion
|
||||
and use of free software in commercial and freeware products
|
||||
alike. As a consequence, its main points are that:
|
||||
|
||||
o We don't promise that this software works. However, we will be
|
||||
interested in any kind of bug reports. (`as is' distribution)
|
||||
|
||||
o You can use this software for whatever you want, in parts or
|
||||
full form, without having to pay us. (`royalty-free' usage)
|
||||
|
||||
o You may not pretend that you wrote this software. If you use
|
||||
it, or only parts of it, in a program, you must acknowledge
|
||||
somewhere in your documentation that you have used the
|
||||
FreeType code. (`credits')
|
||||
|
||||
We specifically permit and encourage the inclusion of this
|
||||
software, with or without modifications, in commercial products.
|
||||
We disclaim all warranties covering The FreeType Project and
|
||||
assume no liability related to The FreeType Project.
|
||||
|
||||
|
||||
Finally, many people asked us for a preferred form for a
|
||||
credit/disclaimer to use in compliance with this license. We thus
|
||||
encourage you to use the following text:
|
||||
|
||||
"""
|
||||
Portions of this software are copyright <20> <year> The FreeType
|
||||
Project (www.freetype.org). All rights reserved.
|
||||
"""
|
||||
|
||||
Please replace <year> with the value from the FreeType version you
|
||||
actually use.
|
||||
|
||||
|
||||
Legal Terms
|
||||
===========
|
||||
|
||||
0. Definitions
|
||||
--------------
|
||||
|
||||
Throughout this license, the terms `package', `FreeType Project',
|
||||
and `FreeType archive' refer to the set of files originally
|
||||
distributed by the authors (David Turner, Robert Wilhelm, and
|
||||
Werner Lemberg) as the `FreeType Project', be they named as alpha,
|
||||
beta or final release.
|
||||
|
||||
`You' refers to the licensee, or person using the project, where
|
||||
`using' is a generic term including compiling the project's source
|
||||
code as well as linking it to form a `program' or `executable'.
|
||||
This program is referred to as `a program using the FreeType
|
||||
engine'.
|
||||
|
||||
This license applies to all files distributed in the original
|
||||
FreeType Project, including all source code, binaries and
|
||||
documentation, unless otherwise stated in the file in its
|
||||
original, unmodified form as distributed in the original archive.
|
||||
If you are unsure whether or not a particular file is covered by
|
||||
this license, you must contact us to verify this.
|
||||
|
||||
The FreeType Project is copyright (C) 1996-2000 by David Turner,
|
||||
Robert Wilhelm, and Werner Lemberg. All rights reserved except as
|
||||
specified below.
|
||||
|
||||
1. No Warranty
|
||||
--------------
|
||||
|
||||
THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO
|
||||
USE, OF THE FREETYPE PROJECT.
|
||||
|
||||
2. Redistribution
|
||||
-----------------
|
||||
|
||||
This license grants a worldwide, royalty-free, perpetual and
|
||||
irrevocable right and license to use, execute, perform, compile,
|
||||
display, copy, create derivative works of, distribute and
|
||||
sublicense the FreeType Project (in both source and object code
|
||||
forms) and derivative works thereof for any purpose; and to
|
||||
authorize others to exercise some or all of the rights granted
|
||||
herein, subject to the following conditions:
|
||||
|
||||
o Redistribution of source code must retain this license file
|
||||
(`FTL.TXT') unaltered; any additions, deletions or changes to
|
||||
the original files must be clearly indicated in accompanying
|
||||
documentation. The copyright notices of the unaltered,
|
||||
original files must be preserved in all copies of source
|
||||
files.
|
||||
|
||||
o Redistribution in binary form must provide a disclaimer that
|
||||
states that the software is based in part of the work of the
|
||||
FreeType Team, in the distribution documentation. We also
|
||||
encourage you to put an URL to the FreeType web page in your
|
||||
documentation, though this isn't mandatory.
|
||||
|
||||
These conditions apply to any software derived from or based on
|
||||
the FreeType Project, not just the unmodified files. If you use
|
||||
our work, you must acknowledge us. However, no fee need be paid
|
||||
to us.
|
||||
|
||||
3. Advertising
|
||||
--------------
|
||||
|
||||
Neither the FreeType authors and contributors nor you shall use
|
||||
the name of the other for commercial, advertising, or promotional
|
||||
purposes without specific prior written permission.
|
||||
|
||||
We suggest, but do not require, that you use one or more of the
|
||||
following phrases to refer to this software in your documentation
|
||||
or advertising materials: `FreeType Project', `FreeType Engine',
|
||||
`FreeType library', or `FreeType Distribution'.
|
||||
|
||||
As you have not signed this license, you are not required to
|
||||
accept it. However, as the FreeType Project is copyrighted
|
||||
material, only this license, or another one contracted with the
|
||||
authors, grants you the right to use, distribute, and modify it.
|
||||
Therefore, by using, distributing, or modifying the FreeType
|
||||
Project, you indicate that you understand and accept all the terms
|
||||
of this license.
|
||||
|
||||
4. Contacts
|
||||
-----------
|
||||
|
||||
There are two mailing lists related to FreeType:
|
||||
|
||||
o freetype@nongnu.org
|
||||
|
||||
Discusses general use and applications of FreeType, as well as
|
||||
future and wanted additions to the library and distribution.
|
||||
If you are looking for support, start in this list if you
|
||||
haven't found anything to help you in the documentation.
|
||||
|
||||
o freetype-devel@nongnu.org
|
||||
|
||||
Discusses bugs, as well as engine internals, design issues,
|
||||
specific licenses, porting, etc.
|
||||
|
||||
Our home page can be found at
|
||||
|
||||
http://www.freetype.org
|
||||
1051
3rdparty/plutosvg/plutovg/source/plutovg-blend.c
vendored
Normal file
1051
3rdparty/plutosvg/plutovg/source/plutovg-blend.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
714
3rdparty/plutosvg/plutovg/source/plutovg-canvas.c
vendored
Normal file
714
3rdparty/plutosvg/plutovg/source/plutovg-canvas.c
vendored
Normal file
@@ -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;
|
||||
}
|
||||
414
3rdparty/plutosvg/plutovg/source/plutovg-font.c
vendored
Normal file
414
3rdparty/plutosvg/plutovg/source/plutovg-font.c
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
#include "plutovg.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
444
3rdparty/plutosvg/plutovg/source/plutovg-ft-math.c
vendored
Normal file
444
3rdparty/plutosvg/plutovg/source/plutovg-ft-math.c
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* fttrigon.c */
|
||||
/* */
|
||||
/* FreeType trigonometric functions (body). */
|
||||
/* */
|
||||
/* Copyright 2001-2005, 2012-2013 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* 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. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#include "plutovg-ft-math.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
static inline int clz(unsigned int x) {
|
||||
unsigned long r = 0;
|
||||
if (_BitScanReverse(&r, x))
|
||||
return 31 - r;
|
||||
return 32;
|
||||
}
|
||||
#define PVG_FT_MSB(x) (31 - clz(x))
|
||||
#elif defined(__GNUC__)
|
||||
#define PVG_FT_MSB(x) (31 - __builtin_clz(x))
|
||||
#else
|
||||
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) (31 - clz(x))
|
||||
#endif
|
||||
|
||||
#define PVG_FT_PAD_FLOOR(x, n) ((x) & ~((n)-1))
|
||||
#define PVG_FT_PAD_ROUND(x, n) PVG_FT_PAD_FLOOR((x) + ((n) / 2), n)
|
||||
#define PVG_FT_PAD_CEIL(x, n) PVG_FT_PAD_FLOOR((x) + ((n)-1), n)
|
||||
|
||||
#define PVG_FT_BEGIN_STMNT do {
|
||||
#define PVG_FT_END_STMNT } while (0)
|
||||
|
||||
/* transfer sign leaving a positive number */
|
||||
#define PVG_FT_MOVE_SIGN(x, s) \
|
||||
PVG_FT_BEGIN_STMNT \
|
||||
if (x < 0) { \
|
||||
x = -x; \
|
||||
s = -s; \
|
||||
} \
|
||||
PVG_FT_END_STMNT
|
||||
|
||||
PVG_FT_Long PVG_FT_MulFix(PVG_FT_Long a, PVG_FT_Long b)
|
||||
{
|
||||
PVG_FT_Int s = 1;
|
||||
PVG_FT_Long c;
|
||||
|
||||
PVG_FT_MOVE_SIGN(a, s);
|
||||
PVG_FT_MOVE_SIGN(b, s);
|
||||
|
||||
c = (PVG_FT_Long)(((PVG_FT_Int64)a * b + 0x8000L) >> 16);
|
||||
|
||||
return (s > 0) ? c : -c;
|
||||
}
|
||||
|
||||
PVG_FT_Long PVG_FT_MulDiv(PVG_FT_Long a, PVG_FT_Long b, PVG_FT_Long c)
|
||||
{
|
||||
PVG_FT_Int s = 1;
|
||||
PVG_FT_Long d;
|
||||
|
||||
PVG_FT_MOVE_SIGN(a, s);
|
||||
PVG_FT_MOVE_SIGN(b, s);
|
||||
PVG_FT_MOVE_SIGN(c, s);
|
||||
|
||||
d = (PVG_FT_Long)(c > 0 ? ((PVG_FT_Int64)a * b + (c >> 1)) / c : 0x7FFFFFFFL);
|
||||
|
||||
return (s > 0) ? d : -d;
|
||||
}
|
||||
|
||||
PVG_FT_Long PVG_FT_DivFix(PVG_FT_Long a, PVG_FT_Long b)
|
||||
{
|
||||
PVG_FT_Int s = 1;
|
||||
PVG_FT_Long q;
|
||||
|
||||
PVG_FT_MOVE_SIGN(a, s);
|
||||
PVG_FT_MOVE_SIGN(b, s);
|
||||
|
||||
q = (PVG_FT_Long)(b > 0 ? (((PVG_FT_UInt64)a << 16) + (b >> 1)) / b
|
||||
: 0x7FFFFFFFL);
|
||||
|
||||
return (s < 0 ? -q : q);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* This is a fixed-point CORDIC implementation of trigonometric */
|
||||
/* functions as well as transformations between Cartesian and polar */
|
||||
/* coordinates. The angles are represented as 16.16 fixed-point values */
|
||||
/* in degrees, i.e., the angular resolution is 2^-16 degrees. Note that */
|
||||
/* only vectors longer than 2^16*180/pi (or at least 22 bits) on a */
|
||||
/* discrete Cartesian grid can have the same or better angular */
|
||||
/* resolution. Therefore, to maintain this precision, some functions */
|
||||
/* require an interim upscaling of the vectors, whereas others operate */
|
||||
/* with 24-bit long vectors directly. */
|
||||
/* */
|
||||
/*************************************************************************/
|
||||
|
||||
/* the Cordic shrink factor 0.858785336480436 * 2^32 */
|
||||
#define PVG_FT_TRIG_SCALE 0xDBD95B16UL
|
||||
|
||||
/* the highest bit in overflow-safe vector components, */
|
||||
/* MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */
|
||||
#define PVG_FT_TRIG_SAFE_MSB 29
|
||||
|
||||
/* this table was generated for PVG_FT_PI = 180L << 16, i.e. degrees */
|
||||
#define PVG_FT_TRIG_MAX_ITERS 23
|
||||
|
||||
static const PVG_FT_Fixed ft_trig_arctan_table[] = {
|
||||
1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, 14668L,
|
||||
7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, 57L,
|
||||
29L, 14L, 7L, 4L, 2L, 1L};
|
||||
|
||||
/* multiply a given value by the CORDIC shrink factor */
|
||||
static PVG_FT_Fixed ft_trig_downscale(PVG_FT_Fixed val)
|
||||
{
|
||||
PVG_FT_Fixed s;
|
||||
PVG_FT_Int64 v;
|
||||
|
||||
s = val;
|
||||
val = PVG_FT_ABS(val);
|
||||
|
||||
v = (val * (PVG_FT_Int64)PVG_FT_TRIG_SCALE) + 0x100000000UL;
|
||||
val = (PVG_FT_Fixed)(v >> 32);
|
||||
|
||||
return (s >= 0) ? val : -val;
|
||||
}
|
||||
|
||||
/* undefined and never called for zero vector */
|
||||
static PVG_FT_Int ft_trig_prenorm(PVG_FT_Vector* vec)
|
||||
{
|
||||
PVG_FT_Pos x, y;
|
||||
PVG_FT_Int shift;
|
||||
|
||||
x = vec->x;
|
||||
y = vec->y;
|
||||
|
||||
shift = PVG_FT_MSB(PVG_FT_ABS(x) | PVG_FT_ABS(y));
|
||||
|
||||
if (shift <= PVG_FT_TRIG_SAFE_MSB) {
|
||||
shift = PVG_FT_TRIG_SAFE_MSB - shift;
|
||||
vec->x = (PVG_FT_Pos)((PVG_FT_ULong)x << shift);
|
||||
vec->y = (PVG_FT_Pos)((PVG_FT_ULong)y << shift);
|
||||
} else {
|
||||
shift -= PVG_FT_TRIG_SAFE_MSB;
|
||||
vec->x = x >> shift;
|
||||
vec->y = y >> shift;
|
||||
shift = -shift;
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
static void ft_trig_pseudo_rotate(PVG_FT_Vector* vec, PVG_FT_Angle theta)
|
||||
{
|
||||
PVG_FT_Int i;
|
||||
PVG_FT_Fixed x, y, xtemp, b;
|
||||
const PVG_FT_Fixed* arctanptr;
|
||||
|
||||
x = vec->x;
|
||||
y = vec->y;
|
||||
|
||||
/* Rotate inside [-PI/4,PI/4] sector */
|
||||
while (theta < -PVG_FT_ANGLE_PI4) {
|
||||
xtemp = y;
|
||||
y = -x;
|
||||
x = xtemp;
|
||||
theta += PVG_FT_ANGLE_PI2;
|
||||
}
|
||||
|
||||
while (theta > PVG_FT_ANGLE_PI4) {
|
||||
xtemp = -y;
|
||||
y = x;
|
||||
x = xtemp;
|
||||
theta -= PVG_FT_ANGLE_PI2;
|
||||
}
|
||||
|
||||
arctanptr = ft_trig_arctan_table;
|
||||
|
||||
/* Pseudorotations, with right shifts */
|
||||
for (i = 1, b = 1; i < PVG_FT_TRIG_MAX_ITERS; b <<= 1, i++) {
|
||||
PVG_FT_Fixed v1 = ((y + b) >> i);
|
||||
PVG_FT_Fixed v2 = ((x + b) >> i);
|
||||
if (theta < 0) {
|
||||
xtemp = x + v1;
|
||||
y = y - v2;
|
||||
x = xtemp;
|
||||
theta += *arctanptr++;
|
||||
} else {
|
||||
xtemp = x - v1;
|
||||
y = y + v2;
|
||||
x = xtemp;
|
||||
theta -= *arctanptr++;
|
||||
}
|
||||
}
|
||||
|
||||
vec->x = x;
|
||||
vec->y = y;
|
||||
}
|
||||
|
||||
static void ft_trig_pseudo_polarize(PVG_FT_Vector* vec)
|
||||
{
|
||||
PVG_FT_Angle theta;
|
||||
PVG_FT_Int i;
|
||||
PVG_FT_Fixed x, y, xtemp, b;
|
||||
const PVG_FT_Fixed* arctanptr;
|
||||
|
||||
x = vec->x;
|
||||
y = vec->y;
|
||||
|
||||
/* Get the vector into [-PI/4,PI/4] sector */
|
||||
if (y > x) {
|
||||
if (y > -x) {
|
||||
theta = PVG_FT_ANGLE_PI2;
|
||||
xtemp = y;
|
||||
y = -x;
|
||||
x = xtemp;
|
||||
} else {
|
||||
theta = y > 0 ? PVG_FT_ANGLE_PI : -PVG_FT_ANGLE_PI;
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
} else {
|
||||
if (y < -x) {
|
||||
theta = -PVG_FT_ANGLE_PI2;
|
||||
xtemp = -y;
|
||||
y = x;
|
||||
x = xtemp;
|
||||
} else {
|
||||
theta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
arctanptr = ft_trig_arctan_table;
|
||||
|
||||
/* Pseudorotations, with right shifts */
|
||||
for (i = 1, b = 1; i < PVG_FT_TRIG_MAX_ITERS; b <<= 1, i++) {
|
||||
PVG_FT_Fixed v1 = ((y + b) >> i);
|
||||
PVG_FT_Fixed v2 = ((x + b) >> i);
|
||||
if (y > 0) {
|
||||
xtemp = x + v1;
|
||||
y = y - v2;
|
||||
x = xtemp;
|
||||
theta += *arctanptr++;
|
||||
} else {
|
||||
xtemp = x - v1;
|
||||
y = y + v2;
|
||||
x = xtemp;
|
||||
theta -= *arctanptr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* round theta */
|
||||
if (theta >= 0)
|
||||
theta = PVG_FT_PAD_ROUND(theta, 32);
|
||||
else
|
||||
theta = -PVG_FT_PAD_ROUND(-theta, 32);
|
||||
|
||||
vec->x = x;
|
||||
vec->y = theta;
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Fixed PVG_FT_Cos(PVG_FT_Angle angle)
|
||||
{
|
||||
PVG_FT_Vector v;
|
||||
|
||||
v.x = PVG_FT_TRIG_SCALE >> 8;
|
||||
v.y = 0;
|
||||
ft_trig_pseudo_rotate(&v, angle);
|
||||
|
||||
return (v.x + 0x80L) >> 8;
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Fixed PVG_FT_Sin(PVG_FT_Angle angle)
|
||||
{
|
||||
return PVG_FT_Cos(PVG_FT_ANGLE_PI2 - angle);
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Fixed PVG_FT_Tan(PVG_FT_Angle angle)
|
||||
{
|
||||
PVG_FT_Vector v;
|
||||
|
||||
v.x = PVG_FT_TRIG_SCALE >> 8;
|
||||
v.y = 0;
|
||||
ft_trig_pseudo_rotate(&v, angle);
|
||||
|
||||
return PVG_FT_DivFix(v.y, v.x);
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Angle PVG_FT_Atan2(PVG_FT_Fixed dx, PVG_FT_Fixed dy)
|
||||
{
|
||||
PVG_FT_Vector v;
|
||||
|
||||
if (dx == 0 && dy == 0) return 0;
|
||||
|
||||
v.x = dx;
|
||||
v.y = dy;
|
||||
ft_trig_prenorm(&v);
|
||||
ft_trig_pseudo_polarize(&v);
|
||||
|
||||
return v.y;
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
void PVG_FT_Vector_Unit(PVG_FT_Vector* vec, PVG_FT_Angle angle)
|
||||
{
|
||||
vec->x = PVG_FT_TRIG_SCALE >> 8;
|
||||
vec->y = 0;
|
||||
ft_trig_pseudo_rotate(vec, angle);
|
||||
vec->x = (vec->x + 0x80L) >> 8;
|
||||
vec->y = (vec->y + 0x80L) >> 8;
|
||||
}
|
||||
|
||||
void PVG_FT_Vector_Rotate(PVG_FT_Vector* vec, PVG_FT_Angle angle)
|
||||
{
|
||||
PVG_FT_Int shift;
|
||||
PVG_FT_Vector v = *vec;
|
||||
|
||||
if ( v.x == 0 && v.y == 0 )
|
||||
return;
|
||||
|
||||
shift = ft_trig_prenorm( &v );
|
||||
ft_trig_pseudo_rotate( &v, angle );
|
||||
v.x = ft_trig_downscale( v.x );
|
||||
v.y = ft_trig_downscale( v.y );
|
||||
|
||||
if ( shift > 0 )
|
||||
{
|
||||
PVG_FT_Int32 half = (PVG_FT_Int32)1L << ( shift - 1 );
|
||||
|
||||
|
||||
vec->x = ( v.x + half - ( v.x < 0 ) ) >> shift;
|
||||
vec->y = ( v.y + half - ( v.y < 0 ) ) >> shift;
|
||||
}
|
||||
else
|
||||
{
|
||||
shift = -shift;
|
||||
vec->x = (PVG_FT_Pos)( (PVG_FT_ULong)v.x << shift );
|
||||
vec->y = (PVG_FT_Pos)( (PVG_FT_ULong)v.y << shift );
|
||||
}
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Fixed PVG_FT_Vector_Length(PVG_FT_Vector* vec)
|
||||
{
|
||||
PVG_FT_Int shift;
|
||||
PVG_FT_Vector v;
|
||||
|
||||
v = *vec;
|
||||
|
||||
/* handle trivial cases */
|
||||
if (v.x == 0) {
|
||||
return PVG_FT_ABS(v.y);
|
||||
} else if (v.y == 0) {
|
||||
return PVG_FT_ABS(v.x);
|
||||
}
|
||||
|
||||
/* general case */
|
||||
shift = ft_trig_prenorm(&v);
|
||||
ft_trig_pseudo_polarize(&v);
|
||||
|
||||
v.x = ft_trig_downscale(v.x);
|
||||
|
||||
if (shift > 0) return (v.x + (1 << (shift - 1))) >> shift;
|
||||
|
||||
return (PVG_FT_Fixed)((PVG_FT_UInt32)v.x << -shift);
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
void PVG_FT_Vector_Polarize(PVG_FT_Vector* vec, PVG_FT_Fixed* length,
|
||||
PVG_FT_Angle* angle)
|
||||
{
|
||||
PVG_FT_Int shift;
|
||||
PVG_FT_Vector v;
|
||||
|
||||
v = *vec;
|
||||
|
||||
if (v.x == 0 && v.y == 0) return;
|
||||
|
||||
shift = ft_trig_prenorm(&v);
|
||||
ft_trig_pseudo_polarize(&v);
|
||||
|
||||
v.x = ft_trig_downscale(v.x);
|
||||
|
||||
*length = (shift >= 0) ? (v.x >> shift)
|
||||
: (PVG_FT_Fixed)((PVG_FT_UInt32)v.x << -shift);
|
||||
*angle = v.y;
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
void PVG_FT_Vector_From_Polar(PVG_FT_Vector* vec, PVG_FT_Fixed length,
|
||||
PVG_FT_Angle angle)
|
||||
{
|
||||
vec->x = length;
|
||||
vec->y = 0;
|
||||
|
||||
PVG_FT_Vector_Rotate(vec, angle);
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Angle PVG_FT_Angle_Diff( PVG_FT_Angle angle1, PVG_FT_Angle angle2 )
|
||||
{
|
||||
PVG_FT_Angle delta = angle2 - angle1;
|
||||
|
||||
while ( delta <= -PVG_FT_ANGLE_PI )
|
||||
delta += PVG_FT_ANGLE_2PI;
|
||||
|
||||
while ( delta > PVG_FT_ANGLE_PI )
|
||||
delta -= PVG_FT_ANGLE_2PI;
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
/* END */
|
||||
436
3rdparty/plutosvg/plutovg/source/plutovg-ft-math.h
vendored
Normal file
436
3rdparty/plutosvg/plutovg/source/plutovg-ft-math.h
vendored
Normal file
@@ -0,0 +1,436 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* fttrigon.h */
|
||||
/* */
|
||||
/* FreeType trigonometric functions (specification). */
|
||||
/* */
|
||||
/* Copyright 2001, 2003, 2005, 2007, 2013 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* 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. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#ifndef PLUTOVG_FT_MATH_H
|
||||
#define PLUTOVG_FT_MATH_H
|
||||
|
||||
#include "plutovg-ft-types.h"
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* The min and max functions missing in C. As usual, be careful not to */
|
||||
/* write things like PVG_FT_MIN( a++, b++ ) to avoid side effects. */
|
||||
/* */
|
||||
#define PVG_FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) )
|
||||
#define PVG_FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) )
|
||||
|
||||
#define PVG_FT_ABS( a ) ( (a) < 0 ? -(a) : (a) )
|
||||
|
||||
/*
|
||||
* Approximate sqrt(x*x+y*y) using the `alpha max plus beta min'
|
||||
* algorithm. We use alpha = 1, beta = 3/8, giving us results with a
|
||||
* largest error less than 7% compared to the exact value.
|
||||
*/
|
||||
#define PVG_FT_HYPOT( x, y ) \
|
||||
( x = PVG_FT_ABS( x ), \
|
||||
y = PVG_FT_ABS( y ), \
|
||||
x > y ? x + ( 3 * y >> 3 ) \
|
||||
: y + ( 3 * x >> 3 ) )
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_MulFix */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A very simple function used to perform the computation */
|
||||
/* `(a*b)/0x10000' with maximum accuracy. Most of the time this is */
|
||||
/* used to multiply a given value by a 16.16 fixed-point factor. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* a :: The first multiplier. */
|
||||
/* b :: The second multiplier. Use a 16.16 factor here whenever */
|
||||
/* possible (see note below). */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* The result of `(a*b)/0x10000'. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* This function has been optimized for the case where the absolute */
|
||||
/* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */
|
||||
/* As this happens mainly when scaling from notional units to */
|
||||
/* fractional pixels in FreeType, it resulted in noticeable speed */
|
||||
/* improvements between versions 2.x and 1.x. */
|
||||
/* */
|
||||
/* As a conclusion, always try to place a 16.16 factor as the */
|
||||
/* _second_ argument of this function; this can make a great */
|
||||
/* difference. */
|
||||
/* */
|
||||
PVG_FT_Long
|
||||
PVG_FT_MulFix( PVG_FT_Long a,
|
||||
PVG_FT_Long b );
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_MulDiv */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A very simple function used to perform the computation `(a*b)/c' */
|
||||
/* with maximum accuracy (it uses a 64-bit intermediate integer */
|
||||
/* whenever necessary). */
|
||||
/* */
|
||||
/* This function isn't necessarily as fast as some processor specific */
|
||||
/* operations, but is at least completely portable. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* a :: The first multiplier. */
|
||||
/* b :: The second multiplier. */
|
||||
/* c :: The divisor. */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* The result of `(a*b)/c'. This function never traps when trying to */
|
||||
/* divide by zero; it simply returns `MaxInt' or `MinInt' depending */
|
||||
/* on the signs of `a' and `b'. */
|
||||
/* */
|
||||
PVG_FT_Long
|
||||
PVG_FT_MulDiv( PVG_FT_Long a,
|
||||
PVG_FT_Long b,
|
||||
PVG_FT_Long c );
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_DivFix */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A very simple function used to perform the computation */
|
||||
/* `(a*0x10000)/b' with maximum accuracy. Most of the time, this is */
|
||||
/* used to divide a given value by a 16.16 fixed-point factor. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* a :: The numerator. */
|
||||
/* b :: The denominator. Use a 16.16 factor here. */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* The result of `(a*0x10000)/b'. */
|
||||
/* */
|
||||
PVG_FT_Long
|
||||
PVG_FT_DivFix( PVG_FT_Long a,
|
||||
PVG_FT_Long b );
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Section> */
|
||||
/* computations */
|
||||
/* */
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @type:
|
||||
* PVG_FT_Angle
|
||||
*
|
||||
* @description:
|
||||
* This type is used to model angle values in FreeType. Note that the
|
||||
* angle is a 16.16 fixed-point value expressed in degrees.
|
||||
*
|
||||
*/
|
||||
typedef PVG_FT_Fixed PVG_FT_Angle;
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
* PVG_FT_ANGLE_PI
|
||||
*
|
||||
* @description:
|
||||
* The angle pi expressed in @PVG_FT_Angle units.
|
||||
*
|
||||
*/
|
||||
#define PVG_FT_ANGLE_PI ( 180L << 16 )
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
* PVG_FT_ANGLE_2PI
|
||||
*
|
||||
* @description:
|
||||
* The angle 2*pi expressed in @PVG_FT_Angle units.
|
||||
*
|
||||
*/
|
||||
#define PVG_FT_ANGLE_2PI ( PVG_FT_ANGLE_PI * 2 )
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
* PVG_FT_ANGLE_PI2
|
||||
*
|
||||
* @description:
|
||||
* The angle pi/2 expressed in @PVG_FT_Angle units.
|
||||
*
|
||||
*/
|
||||
#define PVG_FT_ANGLE_PI2 ( PVG_FT_ANGLE_PI / 2 )
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
* PVG_FT_ANGLE_PI4
|
||||
*
|
||||
* @description:
|
||||
* The angle pi/4 expressed in @PVG_FT_Angle units.
|
||||
*
|
||||
*/
|
||||
#define PVG_FT_ANGLE_PI4 ( PVG_FT_ANGLE_PI / 4 )
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Sin
|
||||
*
|
||||
* @description:
|
||||
* Return the sinus of a given angle in fixed-point format.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
* @return:
|
||||
* The sinus value.
|
||||
*
|
||||
* @note:
|
||||
* If you need both the sinus and cosinus for a given angle, use the
|
||||
* function @PVG_FT_Vector_Unit.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Fixed
|
||||
PVG_FT_Sin( PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Cos
|
||||
*
|
||||
* @description:
|
||||
* Return the cosinus of a given angle in fixed-point format.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
* @return:
|
||||
* The cosinus value.
|
||||
*
|
||||
* @note:
|
||||
* If you need both the sinus and cosinus for a given angle, use the
|
||||
* function @PVG_FT_Vector_Unit.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Fixed
|
||||
PVG_FT_Cos( PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Tan
|
||||
*
|
||||
* @description:
|
||||
* Return the tangent of a given angle in fixed-point format.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
* @return:
|
||||
* The tangent value.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Fixed
|
||||
PVG_FT_Tan( PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Atan2
|
||||
*
|
||||
* @description:
|
||||
* Return the arc-tangent corresponding to a given vector (x,y) in
|
||||
* the 2d plane.
|
||||
*
|
||||
* @input:
|
||||
* x ::
|
||||
* The horizontal vector coordinate.
|
||||
*
|
||||
* y ::
|
||||
* The vertical vector coordinate.
|
||||
*
|
||||
* @return:
|
||||
* The arc-tangent value (i.e. angle).
|
||||
*
|
||||
*/
|
||||
PVG_FT_Angle
|
||||
PVG_FT_Atan2( PVG_FT_Fixed x,
|
||||
PVG_FT_Fixed y );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Angle_Diff
|
||||
*
|
||||
* @description:
|
||||
* Return the difference between two angles. The result is always
|
||||
* constrained to the ]-PI..PI] interval.
|
||||
*
|
||||
* @input:
|
||||
* angle1 ::
|
||||
* First angle.
|
||||
*
|
||||
* angle2 ::
|
||||
* Second angle.
|
||||
*
|
||||
* @return:
|
||||
* Constrained value of `value2-value1'.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Angle
|
||||
PVG_FT_Angle_Diff( PVG_FT_Angle angle1,
|
||||
PVG_FT_Angle angle2 );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_Unit
|
||||
*
|
||||
* @description:
|
||||
* Return the unit vector corresponding to a given angle. After the
|
||||
* call, the value of `vec.x' will be `sin(angle)', and the value of
|
||||
* `vec.y' will be `cos(angle)'.
|
||||
*
|
||||
* This function is useful to retrieve both the sinus and cosinus of a
|
||||
* given angle quickly.
|
||||
*
|
||||
* @output:
|
||||
* vec ::
|
||||
* The address of target vector.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PVG_FT_Vector_Unit( PVG_FT_Vector* vec,
|
||||
PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_Rotate
|
||||
*
|
||||
* @description:
|
||||
* Rotate a vector by a given angle.
|
||||
*
|
||||
* @inout:
|
||||
* vec ::
|
||||
* The address of target vector.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PVG_FT_Vector_Rotate( PVG_FT_Vector* vec,
|
||||
PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_Length
|
||||
*
|
||||
* @description:
|
||||
* Return the length of a given vector.
|
||||
*
|
||||
* @input:
|
||||
* vec ::
|
||||
* The address of target vector.
|
||||
*
|
||||
* @return:
|
||||
* The vector length, expressed in the same units that the original
|
||||
* vector coordinates.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Fixed
|
||||
PVG_FT_Vector_Length( PVG_FT_Vector* vec );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_Polarize
|
||||
*
|
||||
* @description:
|
||||
* Compute both the length and angle of a given vector.
|
||||
*
|
||||
* @input:
|
||||
* vec ::
|
||||
* The address of source vector.
|
||||
*
|
||||
* @output:
|
||||
* length ::
|
||||
* The vector length.
|
||||
*
|
||||
* angle ::
|
||||
* The vector angle.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PVG_FT_Vector_Polarize( PVG_FT_Vector* vec,
|
||||
PVG_FT_Fixed *length,
|
||||
PVG_FT_Angle *angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_From_Polar
|
||||
*
|
||||
* @description:
|
||||
* Compute vector coordinates from a length and angle.
|
||||
*
|
||||
* @output:
|
||||
* vec ::
|
||||
* The address of source vector.
|
||||
*
|
||||
* @input:
|
||||
* length ::
|
||||
* The vector length.
|
||||
*
|
||||
* angle ::
|
||||
* The vector angle.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PVG_FT_Vector_From_Polar( PVG_FT_Vector* vec,
|
||||
PVG_FT_Fixed length,
|
||||
PVG_FT_Angle angle );
|
||||
|
||||
#endif /* PLUTOVG_FT_MATH_H */
|
||||
1706
3rdparty/plutosvg/plutovg/source/plutovg-ft-raster.c
vendored
Normal file
1706
3rdparty/plutosvg/plutovg/source/plutovg-ft-raster.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
420
3rdparty/plutosvg/plutovg/source/plutovg-ft-raster.h
vendored
Normal file
420
3rdparty/plutosvg/plutovg/source/plutovg-ft-raster.h
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* ftimage.h */
|
||||
/* */
|
||||
/* FreeType glyph image formats and default raster interface */
|
||||
/* (specification). */
|
||||
/* */
|
||||
/* Copyright 1996-2010, 2013 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* 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. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#ifndef PLUTOVG_FT_RASTER_H
|
||||
#define PLUTOVG_FT_RASTER_H
|
||||
|
||||
#include "plutovg-ft-types.h"
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* FT_BBox */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A structure used to hold an outline's bounding box, i.e., the */
|
||||
/* coordinates of its extrema in the horizontal and vertical */
|
||||
/* directions. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* xMin :: The horizontal minimum (left-most). */
|
||||
/* */
|
||||
/* yMin :: The vertical minimum (bottom-most). */
|
||||
/* */
|
||||
/* xMax :: The horizontal maximum (right-most). */
|
||||
/* */
|
||||
/* yMax :: The vertical maximum (top-most). */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* The bounding box is specified with the coordinates of the lower */
|
||||
/* left and the upper right corner. In PostScript, those values are */
|
||||
/* often called (llx,lly) and (urx,ury), respectively. */
|
||||
/* */
|
||||
/* If `yMin' is negative, this value gives the glyph's descender. */
|
||||
/* Otherwise, the glyph doesn't descend below the baseline. */
|
||||
/* Similarly, if `ymax' is positive, this value gives the glyph's */
|
||||
/* ascender. */
|
||||
/* */
|
||||
/* `xMin' gives the horizontal distance from the glyph's origin to */
|
||||
/* the left edge of the glyph's bounding box. If `xMin' is negative, */
|
||||
/* the glyph extends to the left of the origin. */
|
||||
/* */
|
||||
typedef struct PVG_FT_BBox_
|
||||
{
|
||||
PVG_FT_Pos xMin, yMin;
|
||||
PVG_FT_Pos xMax, yMax;
|
||||
|
||||
} PVG_FT_BBox;
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* PVG_FT_Outline */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* This structure is used to describe an outline to the scan-line */
|
||||
/* converter. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* n_contours :: The number of contours in the outline. */
|
||||
/* */
|
||||
/* n_points :: The number of points in the outline. */
|
||||
/* */
|
||||
/* points :: A pointer to an array of `n_points' @PVG_FT_Vector */
|
||||
/* elements, giving the outline's point coordinates. */
|
||||
/* */
|
||||
/* tags :: A pointer to an array of `n_points' chars, giving */
|
||||
/* each outline point's type. */
|
||||
/* */
|
||||
/* If bit~0 is unset, the point is `off' the curve, */
|
||||
/* i.e., a Bézier control point, while it is `on' if */
|
||||
/* set. */
|
||||
/* */
|
||||
/* Bit~1 is meaningful for `off' points only. If set, */
|
||||
/* it indicates a third-order Bézier arc control point; */
|
||||
/* and a second-order control point if unset. */
|
||||
/* */
|
||||
/* If bit~2 is set, bits 5-7 contain the drop-out mode */
|
||||
/* (as defined in the OpenType specification; the value */
|
||||
/* is the same as the argument to the SCANMODE */
|
||||
/* instruction). */
|
||||
/* */
|
||||
/* Bits 3 and~4 are reserved for internal purposes. */
|
||||
/* */
|
||||
/* contours :: An array of `n_contours' shorts, giving the end */
|
||||
/* point of each contour within the outline. For */
|
||||
/* example, the first contour is defined by the points */
|
||||
/* `0' to `contours[0]', the second one is defined by */
|
||||
/* the points `contours[0]+1' to `contours[1]', etc. */
|
||||
/* */
|
||||
/* flags :: A set of bit flags used to characterize the outline */
|
||||
/* and give hints to the scan-converter and hinter on */
|
||||
/* how to convert/grid-fit it. See @PVG_FT_OUTLINE_FLAGS.*/
|
||||
/* */
|
||||
typedef struct PVG_FT_Outline_
|
||||
{
|
||||
int n_contours; /* number of contours in glyph */
|
||||
int n_points; /* number of points in the glyph */
|
||||
|
||||
PVG_FT_Vector* points; /* the outline's points */
|
||||
char* tags; /* the points flags */
|
||||
int* contours; /* the contour end points */
|
||||
char* contours_flag; /* the contour open flags */
|
||||
|
||||
int flags; /* outline masks */
|
||||
|
||||
} PVG_FT_Outline;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Enum> */
|
||||
/* PVG_FT_OUTLINE_FLAGS */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A list of bit-field constants use for the flags in an outline's */
|
||||
/* `flags' field. */
|
||||
/* */
|
||||
/* <Values> */
|
||||
/* PVG_FT_OUTLINE_NONE :: */
|
||||
/* Value~0 is reserved. */
|
||||
/* */
|
||||
/* PVG_FT_OUTLINE_OWNER :: */
|
||||
/* If set, this flag indicates that the outline's field arrays */
|
||||
/* (i.e., `points', `flags', and `contours') are `owned' by the */
|
||||
/* outline object, and should thus be freed when it is destroyed. */
|
||||
/* */
|
||||
/* PVG_FT_OUTLINE_EVEN_ODD_FILL :: */
|
||||
/* By default, outlines are filled using the non-zero winding rule. */
|
||||
/* If set to 1, the outline will be filled using the even-odd fill */
|
||||
/* rule (only works with the smooth rasterizer). */
|
||||
/* */
|
||||
/* PVG_FT_OUTLINE_REVERSE_FILL :: */
|
||||
/* By default, outside contours of an outline are oriented in */
|
||||
/* clock-wise direction, as defined in the TrueType specification. */
|
||||
/* This flag is set if the outline uses the opposite direction */
|
||||
/* (typically for Type~1 fonts). This flag is ignored by the scan */
|
||||
/* converter. */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* There exists a second mechanism to pass the drop-out mode to the */
|
||||
/* B/W rasterizer; see the `tags' field in @PVG_FT_Outline. */
|
||||
/* */
|
||||
/* Please refer to the description of the `SCANTYPE' instruction in */
|
||||
/* the OpenType specification (in file `ttinst1.doc') how simple */
|
||||
/* drop-outs, smart drop-outs, and stubs are defined. */
|
||||
/* */
|
||||
#define PVG_FT_OUTLINE_NONE 0x0
|
||||
#define PVG_FT_OUTLINE_OWNER 0x1
|
||||
#define PVG_FT_OUTLINE_EVEN_ODD_FILL 0x2
|
||||
#define PVG_FT_OUTLINE_REVERSE_FILL 0x4
|
||||
|
||||
/* */
|
||||
|
||||
#define PVG_FT_CURVE_TAG( flag ) ( flag & 3 )
|
||||
|
||||
#define PVG_FT_CURVE_TAG_ON 1
|
||||
#define PVG_FT_CURVE_TAG_CONIC 0
|
||||
#define PVG_FT_CURVE_TAG_CUBIC 2
|
||||
|
||||
|
||||
#define PVG_FT_Curve_Tag_On PVG_FT_CURVE_TAG_ON
|
||||
#define PVG_FT_Curve_Tag_Conic PVG_FT_CURVE_TAG_CONIC
|
||||
#define PVG_FT_Curve_Tag_Cubic PVG_FT_CURVE_TAG_CUBIC
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_Outline_Check */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Check the contents of an outline descriptor. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* outline :: A handle to a source outline. */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* FreeType error code. 0~means success. */
|
||||
/* */
|
||||
PVG_FT_Error
|
||||
PVG_FT_Outline_Check( PVG_FT_Outline* outline );
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_Outline_Get_CBox */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Return an outline's `control box'. The control box encloses all */
|
||||
/* the outline's points, including Bézier control points. Though it */
|
||||
/* coincides with the exact bounding box for most glyphs, it can be */
|
||||
/* slightly larger in some situations (like when rotating an outline */
|
||||
/* that contains Bézier outside arcs). */
|
||||
/* */
|
||||
/* Computing the control box is very fast, while getting the bounding */
|
||||
/* box can take much more time as it needs to walk over all segments */
|
||||
/* and arcs in the outline. To get the latter, you can use the */
|
||||
/* `ftbbox' component, which is dedicated to this single task. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* outline :: A pointer to the source outline descriptor. */
|
||||
/* */
|
||||
/* <Output> */
|
||||
/* acbox :: The outline's control box. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* See @PVG_FT_Glyph_Get_CBox for a discussion of tricky fonts. */
|
||||
/* */
|
||||
void
|
||||
PVG_FT_Outline_Get_CBox( const PVG_FT_Outline* outline,
|
||||
PVG_FT_BBox *acbox );
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* PVG_FT_Span */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A structure used to model a single span of gray (or black) pixels */
|
||||
/* when rendering a monochrome or anti-aliased bitmap. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* x :: The span's horizontal start position. */
|
||||
/* */
|
||||
/* len :: The span's length in pixels. */
|
||||
/* */
|
||||
/* coverage :: The span color/coverage, ranging from 0 (background) */
|
||||
/* to 255 (foreground). Only used for anti-aliased */
|
||||
/* rendering. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* This structure is used by the span drawing callback type named */
|
||||
/* @PVG_FT_SpanFunc that takes the y~coordinate of the span as a */
|
||||
/* parameter. */
|
||||
/* */
|
||||
/* The coverage value is always between 0 and 255. If you want less */
|
||||
/* gray values, the callback function has to reduce them. */
|
||||
/* */
|
||||
typedef struct PVG_FT_Span_
|
||||
{
|
||||
int x;
|
||||
int len;
|
||||
int y;
|
||||
unsigned char coverage;
|
||||
|
||||
} PVG_FT_Span;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <FuncType> */
|
||||
/* PVG_FT_SpanFunc */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A function used as a call-back by the anti-aliased renderer in */
|
||||
/* order to let client applications draw themselves the gray pixel */
|
||||
/* spans on each scan line. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* y :: The scanline's y~coordinate. */
|
||||
/* */
|
||||
/* count :: The number of spans to draw on this scanline. */
|
||||
/* */
|
||||
/* spans :: A table of `count' spans to draw on the scanline. */
|
||||
/* */
|
||||
/* user :: User-supplied data that is passed to the callback. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* This callback allows client applications to directly render the */
|
||||
/* gray spans of the anti-aliased bitmap to any kind of surfaces. */
|
||||
/* */
|
||||
/* This can be used to write anti-aliased outlines directly to a */
|
||||
/* given background bitmap, and even perform translucency. */
|
||||
/* */
|
||||
/* Note that the `count' field cannot be greater than a fixed value */
|
||||
/* defined by the `PVG_FT_MAX_GRAY_SPANS' configuration macro in */
|
||||
/* `ftoption.h'. By default, this value is set to~32, which means */
|
||||
/* that if there are more than 32~spans on a given scanline, the */
|
||||
/* callback is called several times with the same `y' parameter in */
|
||||
/* order to draw all callbacks. */
|
||||
/* */
|
||||
/* Otherwise, the callback is only called once per scan-line, and */
|
||||
/* only for those scanlines that do have `gray' pixels on them. */
|
||||
/* */
|
||||
typedef void
|
||||
(*PVG_FT_SpanFunc)( int count,
|
||||
const PVG_FT_Span* spans,
|
||||
void* user );
|
||||
|
||||
#define PVG_FT_Raster_Span_Func PVG_FT_SpanFunc
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Enum> */
|
||||
/* PVG_FT_RASTER_FLAG_XXX */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A list of bit flag constants as used in the `flags' field of a */
|
||||
/* @PVG_FT_Raster_Params structure. */
|
||||
/* */
|
||||
/* <Values> */
|
||||
/* PVG_FT_RASTER_FLAG_DEFAULT :: This value is 0. */
|
||||
/* */
|
||||
/* PVG_FT_RASTER_FLAG_AA :: This flag is set to indicate that an */
|
||||
/* anti-aliased glyph image should be */
|
||||
/* generated. Otherwise, it will be */
|
||||
/* monochrome (1-bit). */
|
||||
/* */
|
||||
/* PVG_FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */
|
||||
/* rendering. In this mode, client */
|
||||
/* applications must provide their own span */
|
||||
/* callback. This lets them directly */
|
||||
/* draw or compose over an existing bitmap. */
|
||||
/* If this bit is not set, the target */
|
||||
/* pixmap's buffer _must_ be zeroed before */
|
||||
/* rendering. */
|
||||
/* */
|
||||
/* Note that for now, direct rendering is */
|
||||
/* only possible with anti-aliased glyphs. */
|
||||
/* */
|
||||
/* PVG_FT_RASTER_FLAG_CLIP :: This flag is only used in direct */
|
||||
/* rendering mode. If set, the output will */
|
||||
/* be clipped to a box specified in the */
|
||||
/* `clip_box' field of the */
|
||||
/* @PVG_FT_Raster_Params structure. */
|
||||
/* */
|
||||
/* Note that by default, the glyph bitmap */
|
||||
/* is clipped to the target pixmap, except */
|
||||
/* in direct rendering mode where all spans */
|
||||
/* are generated if no clipping box is set. */
|
||||
/* */
|
||||
#define PVG_FT_RASTER_FLAG_DEFAULT 0x0
|
||||
#define PVG_FT_RASTER_FLAG_AA 0x1
|
||||
#define PVG_FT_RASTER_FLAG_DIRECT 0x2
|
||||
#define PVG_FT_RASTER_FLAG_CLIP 0x4
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* PVG_FT_Raster_Params */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A structure to hold the arguments used by a raster's render */
|
||||
/* function. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* target :: The target bitmap. */
|
||||
/* */
|
||||
/* source :: A pointer to the source glyph image (e.g., an */
|
||||
/* @PVG_FT_Outline). */
|
||||
/* */
|
||||
/* flags :: The rendering flags. */
|
||||
/* */
|
||||
/* gray_spans :: The gray span drawing callback. */
|
||||
/* */
|
||||
/* black_spans :: The black span drawing callback. UNIMPLEMENTED! */
|
||||
/* */
|
||||
/* bit_test :: The bit test callback. UNIMPLEMENTED! */
|
||||
/* */
|
||||
/* bit_set :: The bit set callback. UNIMPLEMENTED! */
|
||||
/* */
|
||||
/* user :: User-supplied data that is passed to each drawing */
|
||||
/* callback. */
|
||||
/* */
|
||||
/* clip_box :: An optional clipping box. It is only used in */
|
||||
/* direct rendering mode. Note that coordinates here */
|
||||
/* should be expressed in _integer_ pixels (and not in */
|
||||
/* 26.6 fixed-point units). */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* An anti-aliased glyph bitmap is drawn if the @PVG_FT_RASTER_FLAG_AA */
|
||||
/* bit flag is set in the `flags' field, otherwise a monochrome */
|
||||
/* bitmap is generated. */
|
||||
/* */
|
||||
/* If the @PVG_FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */
|
||||
/* raster will call the `gray_spans' callback to draw gray pixel */
|
||||
/* spans, in the case of an aa glyph bitmap, it will call */
|
||||
/* `black_spans', and `bit_test' and `bit_set' in the case of a */
|
||||
/* monochrome bitmap. This allows direct composition over a */
|
||||
/* pre-existing bitmap through user-provided callbacks to perform the */
|
||||
/* span drawing/composition. */
|
||||
/* */
|
||||
/* Note that the `bit_test' and `bit_set' callbacks are required when */
|
||||
/* rendering a monochrome bitmap, as they are crucial to implement */
|
||||
/* correct drop-out control as defined in the TrueType specification. */
|
||||
/* */
|
||||
typedef struct PVG_FT_Raster_Params_
|
||||
{
|
||||
const void* source;
|
||||
int flags;
|
||||
PVG_FT_SpanFunc gray_spans;
|
||||
void* user;
|
||||
PVG_FT_BBox clip_box;
|
||||
|
||||
} PVG_FT_Raster_Params;
|
||||
|
||||
|
||||
void
|
||||
PVG_FT_Raster_Render(const PVG_FT_Raster_Params *params);
|
||||
|
||||
#endif // PLUTOVG_FT_RASTER_H
|
||||
1873
3rdparty/plutosvg/plutovg/source/plutovg-ft-stroker.c
vendored
Normal file
1873
3rdparty/plutosvg/plutovg/source/plutovg-ft-stroker.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
320
3rdparty/plutosvg/plutovg/source/plutovg-ft-stroker.h
vendored
Normal file
320
3rdparty/plutosvg/plutovg/source/plutovg-ft-stroker.h
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* ftstroke.h */
|
||||
/* */
|
||||
/* FreeType path stroker (specification). */
|
||||
/* */
|
||||
/* Copyright 2002-2006, 2008, 2009, 2011-2012 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* 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. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#ifndef PLUTOVG_FT_STROKER_H
|
||||
#define PLUTOVG_FT_STROKER_H
|
||||
|
||||
#include "plutovg-ft-raster.h"
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @type:
|
||||
* PVG_FT_Stroker
|
||||
*
|
||||
* @description:
|
||||
* Opaque handler to a path stroker object.
|
||||
*/
|
||||
typedef struct PVG_FT_StrokerRec_* PVG_FT_Stroker;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @enum:
|
||||
* PVG_FT_Stroker_LineJoin
|
||||
*
|
||||
* @description:
|
||||
* These values determine how two joining lines are rendered
|
||||
* in a stroker.
|
||||
*
|
||||
* @values:
|
||||
* PVG_FT_STROKER_LINEJOIN_ROUND ::
|
||||
* Used to render rounded line joins. Circular arcs are used
|
||||
* to join two lines smoothly.
|
||||
*
|
||||
* PVG_FT_STROKER_LINEJOIN_BEVEL ::
|
||||
* Used to render beveled line joins. The outer corner of
|
||||
* the joined lines is filled by enclosing the triangular
|
||||
* region of the corner with a straight line between the
|
||||
* outer corners of each stroke.
|
||||
*
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER_FIXED ::
|
||||
* Used to render mitered line joins, with fixed bevels if the
|
||||
* miter limit is exceeded. The outer edges of the strokes
|
||||
* for the two segments are extended until they meet at an
|
||||
* angle. If the segments meet at too sharp an angle (such
|
||||
* that the miter would extend from the intersection of the
|
||||
* segments a distance greater than the product of the miter
|
||||
* limit value and the border radius), then a bevel join (see
|
||||
* above) is used instead. This prevents long spikes being
|
||||
* created. PVG_FT_STROKER_LINEJOIN_MITER_FIXED generates a miter
|
||||
* line join as used in PostScript and PDF.
|
||||
*
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE ::
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER ::
|
||||
* Used to render mitered line joins, with variable bevels if
|
||||
* the miter limit is exceeded. The intersection of the
|
||||
* strokes is clipped at a line perpendicular to the bisector
|
||||
* of the angle between the strokes, at the distance from the
|
||||
* intersection of the segments equal to the product of the
|
||||
* miter limit value and the border radius. This prevents
|
||||
* long spikes being created.
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE generates a mitered line
|
||||
* join as used in XPS. PVG_FT_STROKER_LINEJOIN_MITER is an alias
|
||||
* for PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE, retained for
|
||||
* backwards compatibility.
|
||||
*/
|
||||
typedef enum PVG_FT_Stroker_LineJoin_
|
||||
{
|
||||
PVG_FT_STROKER_LINEJOIN_ROUND = 0,
|
||||
PVG_FT_STROKER_LINEJOIN_BEVEL = 1,
|
||||
PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE = 2,
|
||||
PVG_FT_STROKER_LINEJOIN_MITER = PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE,
|
||||
PVG_FT_STROKER_LINEJOIN_MITER_FIXED = 3
|
||||
|
||||
} PVG_FT_Stroker_LineJoin;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @enum:
|
||||
* PVG_FT_Stroker_LineCap
|
||||
*
|
||||
* @description:
|
||||
* These values determine how the end of opened sub-paths are
|
||||
* rendered in a stroke.
|
||||
*
|
||||
* @values:
|
||||
* PVG_FT_STROKER_LINECAP_BUTT ::
|
||||
* The end of lines is rendered as a full stop on the last
|
||||
* point itself.
|
||||
*
|
||||
* PVG_FT_STROKER_LINECAP_ROUND ::
|
||||
* The end of lines is rendered as a half-circle around the
|
||||
* last point.
|
||||
*
|
||||
* PVG_FT_STROKER_LINECAP_SQUARE ::
|
||||
* The end of lines is rendered as a square around the
|
||||
* last point.
|
||||
*/
|
||||
typedef enum PVG_FT_Stroker_LineCap_
|
||||
{
|
||||
PVG_FT_STROKER_LINECAP_BUTT = 0,
|
||||
PVG_FT_STROKER_LINECAP_ROUND,
|
||||
PVG_FT_STROKER_LINECAP_SQUARE
|
||||
|
||||
} PVG_FT_Stroker_LineCap;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @enum:
|
||||
* PVG_FT_StrokerBorder
|
||||
*
|
||||
* @description:
|
||||
* These values are used to select a given stroke border
|
||||
* in @PVG_FT_Stroker_GetBorderCounts and @PVG_FT_Stroker_ExportBorder.
|
||||
*
|
||||
* @values:
|
||||
* PVG_FT_STROKER_BORDER_LEFT ::
|
||||
* Select the left border, relative to the drawing direction.
|
||||
*
|
||||
* PVG_FT_STROKER_BORDER_RIGHT ::
|
||||
* Select the right border, relative to the drawing direction.
|
||||
*
|
||||
* @note:
|
||||
* Applications are generally interested in the `inside' and `outside'
|
||||
* borders. However, there is no direct mapping between these and the
|
||||
* `left' and `right' ones, since this really depends on the glyph's
|
||||
* drawing orientation, which varies between font formats.
|
||||
*
|
||||
* You can however use @PVG_FT_Outline_GetInsideBorder and
|
||||
* @PVG_FT_Outline_GetOutsideBorder to get these.
|
||||
*/
|
||||
typedef enum PVG_FT_StrokerBorder_
|
||||
{
|
||||
PVG_FT_STROKER_BORDER_LEFT = 0,
|
||||
PVG_FT_STROKER_BORDER_RIGHT
|
||||
|
||||
} PVG_FT_StrokerBorder;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_New
|
||||
*
|
||||
* @description:
|
||||
* Create a new stroker object.
|
||||
*
|
||||
* @input:
|
||||
* library ::
|
||||
* FreeType library handle.
|
||||
*
|
||||
* @output:
|
||||
* astroker ::
|
||||
* A new stroker object handle. NULL in case of error.
|
||||
*
|
||||
* @return:
|
||||
* FreeType error code. 0~means success.
|
||||
*/
|
||||
PVG_FT_Error
|
||||
PVG_FT_Stroker_New( PVG_FT_Stroker *astroker );
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_Set
|
||||
*
|
||||
* @description:
|
||||
* Reset a stroker object's attributes.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* The target stroker handle.
|
||||
*
|
||||
* radius ::
|
||||
* The border radius.
|
||||
*
|
||||
* line_cap ::
|
||||
* The line cap style.
|
||||
*
|
||||
* line_join ::
|
||||
* The line join style.
|
||||
*
|
||||
* miter_limit ::
|
||||
* The miter limit for the PVG_FT_STROKER_LINEJOIN_MITER_FIXED and
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE line join styles,
|
||||
* expressed as 16.16 fixed-point value.
|
||||
*
|
||||
* @note:
|
||||
* The radius is expressed in the same units as the outline
|
||||
* coordinates.
|
||||
*/
|
||||
void
|
||||
PVG_FT_Stroker_Set( PVG_FT_Stroker stroker,
|
||||
PVG_FT_Fixed radius,
|
||||
PVG_FT_Stroker_LineCap line_cap,
|
||||
PVG_FT_Stroker_LineJoin line_join,
|
||||
PVG_FT_Fixed miter_limit );
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_ParseOutline
|
||||
*
|
||||
* @description:
|
||||
* A convenience function used to parse a whole outline with
|
||||
* the stroker. The resulting outline(s) can be retrieved
|
||||
* later by functions like @PVG_FT_Stroker_GetCounts and @PVG_FT_Stroker_Export.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* The target stroker handle.
|
||||
*
|
||||
* outline ::
|
||||
* The source outline.
|
||||
*
|
||||
*
|
||||
* @return:
|
||||
* FreeType error code. 0~means success.
|
||||
*
|
||||
* @note:
|
||||
* If `opened' is~0 (the default), the outline is treated as a closed
|
||||
* path, and the stroker generates two distinct `border' outlines.
|
||||
*
|
||||
*
|
||||
* This function calls @PVG_FT_Stroker_Rewind automatically.
|
||||
*/
|
||||
PVG_FT_Error
|
||||
PVG_FT_Stroker_ParseOutline( PVG_FT_Stroker stroker,
|
||||
const PVG_FT_Outline* outline);
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_GetCounts
|
||||
*
|
||||
* @description:
|
||||
* Call this function once you have finished parsing your paths
|
||||
* with the stroker. It returns the number of points and
|
||||
* contours necessary to export all points/borders from the stroked
|
||||
* outline/path.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* The target stroker handle.
|
||||
*
|
||||
* @output:
|
||||
* anum_points ::
|
||||
* The number of points.
|
||||
*
|
||||
* anum_contours ::
|
||||
* The number of contours.
|
||||
*
|
||||
* @return:
|
||||
* FreeType error code. 0~means success.
|
||||
*/
|
||||
PVG_FT_Error
|
||||
PVG_FT_Stroker_GetCounts( PVG_FT_Stroker stroker,
|
||||
PVG_FT_UInt *anum_points,
|
||||
PVG_FT_UInt *anum_contours );
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_Export
|
||||
*
|
||||
* @description:
|
||||
* Call this function after @PVG_FT_Stroker_GetBorderCounts to
|
||||
* export all borders to your own @PVG_FT_Outline structure.
|
||||
*
|
||||
* Note that this function appends the border points and
|
||||
* contours to your outline, but does not try to resize its
|
||||
* arrays.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* The target stroker handle.
|
||||
*
|
||||
* outline ::
|
||||
* The target outline handle.
|
||||
*/
|
||||
void
|
||||
PVG_FT_Stroker_Export( PVG_FT_Stroker stroker,
|
||||
PVG_FT_Outline* outline );
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_Done
|
||||
*
|
||||
* @description:
|
||||
* Destroy a stroker object.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* A stroker handle. Can be NULL.
|
||||
*/
|
||||
void
|
||||
PVG_FT_Stroker_Done( PVG_FT_Stroker stroker );
|
||||
|
||||
|
||||
#endif // PLUTOVG_FT_STROKER_H
|
||||
173
3rdparty/plutosvg/plutovg/source/plutovg-ft-types.h
vendored
Normal file
173
3rdparty/plutosvg/plutovg/source/plutovg-ft-types.h
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* fttypes.h
|
||||
*
|
||||
* FreeType simple types definitions (specification only).
|
||||
*
|
||||
* Copyright (C) 1996-2020 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
* modified, and distributed under the terms of the FreeType project
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PLUTOVG_FT_TYPES_H
|
||||
#define PLUTOVG_FT_TYPES_H
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Fixed */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* This type is used to store 16.16 fixed-point values, like scaling */
|
||||
/* values or matrix coefficients. */
|
||||
/* */
|
||||
typedef signed long PVG_FT_Fixed;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Int */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for the int type. */
|
||||
/* */
|
||||
typedef signed int PVG_FT_Int;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_UInt */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for the unsigned int type. */
|
||||
/* */
|
||||
typedef unsigned int PVG_FT_UInt;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Long */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for signed long. */
|
||||
/* */
|
||||
typedef signed long PVG_FT_Long;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_ULong */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for unsigned long. */
|
||||
/* */
|
||||
typedef unsigned long PVG_FT_ULong;
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Short */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for signed short. */
|
||||
/* */
|
||||
typedef signed short PVG_FT_Short;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Byte */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A simple typedef for the _unsigned_ char type. */
|
||||
/* */
|
||||
typedef unsigned char PVG_FT_Byte;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Bool */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef of unsigned char, used for simple booleans. As usual, */
|
||||
/* values 1 and~0 represent true and false, respectively. */
|
||||
/* */
|
||||
typedef unsigned char PVG_FT_Bool;
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Error */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* The FreeType error code type. A value of~0 is always interpreted */
|
||||
/* as a successful operation. */
|
||||
/* */
|
||||
typedef int PVG_FT_Error;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Pos */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* The type PVG_FT_Pos is used to store vectorial coordinates. Depending */
|
||||
/* on the context, these can represent distances in integer font */
|
||||
/* units, or 16.16, or 26.6 fixed-point pixel coordinates. */
|
||||
/* */
|
||||
typedef signed long PVG_FT_Pos;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* PVG_FT_Vector */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A simple structure used to store a 2D vector; coordinates are of */
|
||||
/* the PVG_FT_Pos type. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* x :: The horizontal coordinate. */
|
||||
/* y :: The vertical coordinate. */
|
||||
/* */
|
||||
typedef struct PVG_FT_Vector_
|
||||
{
|
||||
PVG_FT_Pos x;
|
||||
PVG_FT_Pos y;
|
||||
|
||||
} PVG_FT_Vector;
|
||||
|
||||
|
||||
typedef long long int PVG_FT_Int64;
|
||||
typedef unsigned long long int PVG_FT_UInt64;
|
||||
|
||||
typedef signed int PVG_FT_Int32;
|
||||
typedef unsigned int PVG_FT_UInt32;
|
||||
|
||||
#define PVG_FT_BOOL( x ) ( (PVG_FT_Bool)( x ) )
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#endif // PLUTOVG_FT_TYPES_H
|
||||
231
3rdparty/plutosvg/plutovg/source/plutovg-matrix.c
vendored
Normal file
231
3rdparty/plutosvg/plutovg/source/plutovg-matrix.c
vendored
Normal file
@@ -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;
|
||||
}
|
||||
497
3rdparty/plutosvg/plutovg/source/plutovg-paint.c
vendored
Normal file
497
3rdparty/plutosvg/plutovg/source/plutovg-paint.c
vendored
Normal file
@@ -0,0 +1,497 @@
|
||||
#include "plutovg-private.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
void plutovg_color_init_rgb(plutovg_color_t* color, float r, float g, float b)
|
||||
{
|
||||
plutovg_color_init_rgba(color, r, g, b, 1.f);
|
||||
}
|
||||
|
||||
void plutovg_color_init_rgba(plutovg_color_t* color, float r, float g, float b, float a)
|
||||
{
|
||||
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_color_init_rgb8(plutovg_color_t* color, int r, int g, int b)
|
||||
{
|
||||
plutovg_color_init_rgba8(color, r, g, b, 255);
|
||||
}
|
||||
|
||||
void plutovg_color_init_rgba8(plutovg_color_t* color, int r, int g, int b, int a)
|
||||
{
|
||||
plutovg_color_init_rgba(color, r / 255.f, g / 255.f, b / 255.f, a / 255.f);
|
||||
}
|
||||
|
||||
void plutovg_color_init_rgba32(plutovg_color_t* color, unsigned int value)
|
||||
{
|
||||
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_color_init_argb32(plutovg_color_t* color, unsigned int value)
|
||||
{
|
||||
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_color_init_hsl(plutovg_color_t* color, float h, float s, float l)
|
||||
{
|
||||
plutovg_color_init_hsla(color, h, s, l, 1.f);
|
||||
}
|
||||
|
||||
static inline float hsl_component(float h, float s, float l, float n)
|
||||
{
|
||||
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_color_init_hsla(plutovg_color_t* color, float h, float s, float l, float a)
|
||||
{
|
||||
h = fmodf(h, 360.f);
|
||||
if(h < 0.f) { h += 360.f; }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned int plutovg_color_to_rgba32(const plutovg_color_t* color)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned int plutovg_color_to_argb32(const plutovg_color_t* color)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static inline uint8_t hex_digit(uint8_t c)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static inline uint8_t hex_byte(uint8_t c1, uint8_t c2)
|
||||
{
|
||||
uint8_t h1 = hex_digit(c1);
|
||||
uint8_t h2 = hex_digit(c2);
|
||||
return (h1 << 4) | h2;
|
||||
}
|
||||
|
||||
#define MAX_NAME 20
|
||||
typedef struct {
|
||||
const char* name;
|
||||
uint32_t value;
|
||||
} color_entry_t;
|
||||
|
||||
static int color_entry_compare(const void* a, const void* b)
|
||||
{
|
||||
const char* name = a;
|
||||
const color_entry_t* entry = b;
|
||||
return strcmp(name, entry->name);
|
||||
}
|
||||
|
||||
static bool parse_rgb_component(const char** begin, const char* end, float* component)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static bool parse_alpha_component(const char** begin, const char* end, float* component)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
int plutovg_color_parse(plutovg_color_t* color, const char* data, int length)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
plutovg_skip_ws(&it, end);
|
||||
return it - data;
|
||||
}
|
||||
|
||||
static void* plutovg_paint_create(plutovg_paint_type_t type, size_t size)
|
||||
{
|
||||
plutovg_paint_t* paint = malloc(size);
|
||||
paint->ref_count = 1;
|
||||
paint->type = type;
|
||||
return paint;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_rgb(float r, float g, float b)
|
||||
{
|
||||
return plutovg_paint_create_rgba(r, g, b, 1.f);
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_rgba(float r, float g, float b, float a)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_color(const plutovg_color_t* color)
|
||||
{
|
||||
return plutovg_paint_create_rgba(color->r, color->g, color->b, color->a);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
return gradient;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_texture(plutovg_surface_t* surface, plutovg_texture_type_t type, float opacity, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_reference(plutovg_paint_t* paint)
|
||||
{
|
||||
if(paint == NULL)
|
||||
return NULL;
|
||||
++paint->ref_count;
|
||||
return paint;
|
||||
}
|
||||
|
||||
void plutovg_paint_destroy(plutovg_paint_t* paint)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
int plutovg_paint_get_reference_count(const plutovg_paint_t* paint)
|
||||
{
|
||||
if(paint)
|
||||
return paint->ref_count;
|
||||
return 0;
|
||||
}
|
||||
924
3rdparty/plutosvg/plutovg/source/plutovg-path.c
vendored
Normal file
924
3rdparty/plutosvg/plutovg/source/plutovg-path.c
vendored
Normal file
@@ -0,0 +1,924 @@
|
||||
#include "plutovg-private.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
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;
|
||||
}
|
||||
145
3rdparty/plutosvg/plutovg/source/plutovg-private.h
vendored
Normal file
145
3rdparty/plutosvg/plutovg/source/plutovg-private.h
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
#ifndef PLUTOVG_PRIVATE_H
|
||||
#define PLUTOVG_PRIVATE_H
|
||||
|
||||
#include "plutovg.h"
|
||||
|
||||
struct plutovg_surface {
|
||||
int ref_count;
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
unsigned char* data;
|
||||
};
|
||||
|
||||
struct plutovg_path {
|
||||
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;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PLUTOVG_PAINT_TYPE_COLOR,
|
||||
PLUTOVG_PAINT_TYPE_GRADIENT,
|
||||
PLUTOVG_PAINT_TYPE_TEXTURE
|
||||
} plutovg_paint_type_t;
|
||||
|
||||
struct plutovg_paint {
|
||||
int ref_count;
|
||||
plutovg_paint_type_t type;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
plutovg_paint_t base;
|
||||
plutovg_color_t color;
|
||||
} plutovg_solid_paint_t;
|
||||
|
||||
typedef enum {
|
||||
PLUTOVG_GRADIENT_TYPE_LINEAR,
|
||||
PLUTOVG_GRADIENT_TYPE_RADIAL
|
||||
} plutovg_gradient_type_t;
|
||||
|
||||
typedef struct {
|
||||
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;
|
||||
int len;
|
||||
int y;
|
||||
unsigned char coverage;
|
||||
} plutovg_span_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
plutovg_span_t* data;
|
||||
int size;
|
||||
int capacity;
|
||||
} spans;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
} plutovg_span_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
float offset;
|
||||
struct {
|
||||
float* data;
|
||||
int size;
|
||||
int capacity;
|
||||
} array;
|
||||
} plutovg_stroke_dash_t;
|
||||
|
||||
typedef struct {
|
||||
float width;
|
||||
plutovg_line_cap_t cap;
|
||||
plutovg_line_join_t join;
|
||||
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_paint_t* paint;
|
||||
plutovg_font_face_t* font_face;
|
||||
plutovg_color_t color;
|
||||
plutovg_matrix_t matrix;
|
||||
plutovg_stroke_data_t stroke;
|
||||
plutovg_span_buffer_t clip_spans;
|
||||
plutovg_fill_rule_t winding;
|
||||
plutovg_operator_t op;
|
||||
float font_size;
|
||||
float opacity;
|
||||
bool clipping;
|
||||
struct plutovg_state* next;
|
||||
} plutovg_state_t;
|
||||
|
||||
struct plutovg_canvas {
|
||||
int ref_count;
|
||||
plutovg_surface_t* surface;
|
||||
plutovg_path_t* path;
|
||||
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_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
|
||||
377
3rdparty/plutosvg/plutovg/source/plutovg-rasterize.c
vendored
Normal file
377
3rdparty/plutosvg/plutovg/source/plutovg-rasterize.c
vendored
Normal file
@@ -0,0 +1,377 @@
|
||||
#include "plutovg-private.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#include "plutovg-ft-raster.h"
|
||||
#include "plutovg-ft-stroker.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
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);
|
||||
}
|
||||
1724
3rdparty/plutosvg/plutovg/source/plutovg-stb-image-write.h
vendored
Normal file
1724
3rdparty/plutosvg/plutovg/source/plutovg-stb-image-write.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7988
3rdparty/plutosvg/plutovg/source/plutovg-stb-image.h
vendored
Normal file
7988
3rdparty/plutosvg/plutovg/source/plutovg-stb-image.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5077
3rdparty/plutosvg/plutovg/source/plutovg-stb-truetype.h
vendored
Normal file
5077
3rdparty/plutosvg/plutovg/source/plutovg-stb-truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
300
3rdparty/plutosvg/plutovg/source/plutovg-surface.c
vendored
Normal file
300
3rdparty/plutosvg/plutovg/source/plutovg-surface.c
vendored
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
211
3rdparty/plutosvg/plutovg/source/plutovg-utils.h
vendored
Normal file
211
3rdparty/plutosvg/plutovg/source/plutovg-utils.h
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
#ifndef PLUTOVG_UTILS_H
|
||||
#define PLUTOVG_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#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
|
||||
291
3rdparty/plutosvg/source/plutosvg-ft.h
vendored
Normal file
291
3rdparty/plutosvg/source/plutosvg-ft.h
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2025 Samuel Ugochukwu <sammycageagle@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief FreeType hooks for rendering SVG glyphs with PlutoSVG.
|
||||
*
|
||||
* This file implements the integration layer between FreeType’s SVG module (typically
|
||||
* named "ot-svg") and PlutoSVG. It defines the necessary functions to initialize and
|
||||
* free the SVG rendering state, render an SVG glyph into a glyph slot, load (and cache)
|
||||
* SVG documents, and pre-configure glyph slots with appropriate metrics and transforms.
|
||||
*
|
||||
* These functions are aggregated into the `plutosvg_ft_hooks` structure.
|
||||
*
|
||||
* Usage example:
|
||||
* @code
|
||||
* #include <plutosvg-ft.h>
|
||||
*
|
||||
* #include <ft2build.h>
|
||||
* #include FT_FREETYPE_H
|
||||
* #include FT_MODULE_H
|
||||
*
|
||||
* int main(void)
|
||||
* {
|
||||
* FT_Library library;
|
||||
* if (FT_Init_FreeType(&library))
|
||||
* return -1;
|
||||
*
|
||||
* if (FT_Property_Set(library, "ot-svg", "svg-hooks", &plutosvg_ft_hooks))
|
||||
* return -1;
|
||||
*
|
||||
* // ... your code ...
|
||||
*
|
||||
* FT_Done_FreeType(library);
|
||||
* return 0;
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef PLUTOSVG_FT_H
|
||||
#define PLUTOSVG_FT_H
|
||||
|
||||
#include "plutosvg.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_OTSVG_H
|
||||
#include FT_COLOR_H
|
||||
|
||||
typedef struct {
|
||||
plutosvg_document_t* document;
|
||||
const FT_Byte* data;
|
||||
FT_ULong length;
|
||||
} plutosvg_ft_document_entry_t;
|
||||
|
||||
#define PLUTOSVG_FT_MAX_DOCS 16
|
||||
|
||||
typedef struct {
|
||||
plutosvg_document_t* document;
|
||||
plutovg_matrix_t matrix;
|
||||
plutovg_rect_t extents;
|
||||
plutosvg_ft_document_entry_t entries[PLUTOSVG_FT_MAX_DOCS];
|
||||
FT_ULong num_entries;
|
||||
} plutosvg_ft_state_t;
|
||||
|
||||
static FT_Error plutosvg_ft_init(FT_Pointer* ft_state)
|
||||
{
|
||||
plutosvg_ft_state_t* state = (plutosvg_ft_state_t*)malloc(sizeof(plutosvg_ft_state_t));
|
||||
memset(state, 0, sizeof(plutosvg_ft_state_t));
|
||||
*ft_state = state;
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
static void plutosvg_ft_free(FT_Pointer* ft_state)
|
||||
{
|
||||
plutosvg_ft_state_t* state = (plutosvg_ft_state_t*)(*ft_state);
|
||||
for(FT_ULong i = 0; i < state->num_entries; ++i)
|
||||
plutosvg_document_destroy(state->entries[i].document);
|
||||
free(state);
|
||||
}
|
||||
|
||||
#define PLUTOSVG_FT_PALETTE_INDEX 0
|
||||
|
||||
static bool plutosvg_ft_palette_func(void* closure, const char* name, int length, plutovg_color_t* color)
|
||||
{
|
||||
FT_Face ft_face = (FT_Face)(closure);
|
||||
if(length < 5 || strncmp(name, "color", 5) != 0)
|
||||
return false;
|
||||
FT_Palette_Data ft_palette_data;
|
||||
if(FT_Palette_Data_Get(ft_face, &ft_palette_data))
|
||||
return false;
|
||||
FT_Color* ft_palette = NULL;
|
||||
if(FT_Palette_Select(ft_face, PLUTOSVG_FT_PALETTE_INDEX, &ft_palette)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FT_Int index = 0;
|
||||
for(int i = 5; i < length; ++i) {
|
||||
const char ch = name[i];
|
||||
if(ch < '0' || ch > '9')
|
||||
return false;
|
||||
index = index * 10 + ch - '0';
|
||||
}
|
||||
|
||||
if(index >= ft_palette_data.num_palette_entries)
|
||||
return false;
|
||||
FT_Color* ft_color = ft_palette + index;
|
||||
color->r = ft_color->red / 255.f;
|
||||
color->g = ft_color->green / 255.f;
|
||||
color->b = ft_color->blue / 255.f;
|
||||
color->a = ft_color->alpha / 255.f;
|
||||
return true;
|
||||
}
|
||||
|
||||
static FT_Error plutosvg_ft_render(FT_GlyphSlot ft_slot, FT_Pointer* ft_state)
|
||||
{
|
||||
plutosvg_ft_state_t* state = (plutosvg_ft_state_t*)(*ft_state);
|
||||
if(state->document == NULL)
|
||||
return FT_Err_Invalid_SVG_Document;
|
||||
plutovg_surface_t* surface = plutovg_surface_create_for_data(ft_slot->bitmap.buffer, ft_slot->bitmap.width, ft_slot->bitmap.rows, ft_slot->bitmap.pitch);
|
||||
plutovg_canvas_t* canvas = plutovg_canvas_create(surface);
|
||||
|
||||
FT_SVG_Document ft_document = (FT_SVG_Document)ft_slot->other;
|
||||
FT_UShort start_glyph_id = ft_document->start_glyph_id;
|
||||
FT_UShort end_glyph_id = ft_document->end_glyph_id;
|
||||
|
||||
char buffer[64];
|
||||
char* id = NULL;
|
||||
if(start_glyph_id < end_glyph_id) {
|
||||
sprintf(buffer, "glyph%u", ft_slot->glyph_index);
|
||||
id = buffer;
|
||||
}
|
||||
|
||||
plutovg_canvas_translate(canvas, -state->extents.x, -state->extents.y);
|
||||
plutovg_canvas_transform(canvas, &state->matrix);
|
||||
plutosvg_document_render(state->document, id, canvas, NULL, plutosvg_ft_palette_func, ft_slot->face);
|
||||
|
||||
ft_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||
ft_slot->bitmap.num_grays = 256;
|
||||
ft_slot->format = FT_GLYPH_FORMAT_BITMAP;
|
||||
|
||||
plutovg_canvas_destroy(canvas);
|
||||
plutovg_surface_destroy(surface);
|
||||
state->document = NULL;
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
static plutosvg_document_t* plutosvg_ft_document_load(plutosvg_ft_state_t* state, const FT_Byte* data, FT_ULong length, FT_UShort units_per_EM)
|
||||
{
|
||||
for(FT_ULong i = 0; i < state->num_entries; ++i) {
|
||||
if(data == state->entries[i].data && length == state->entries[i].length) {
|
||||
plutosvg_ft_document_entry_t entry = state->entries[i];
|
||||
memmove(&state->entries[1], &state->entries[0], i * sizeof(plutosvg_ft_document_entry_t));
|
||||
state->entries[0] = entry;
|
||||
return entry.document;
|
||||
}
|
||||
}
|
||||
|
||||
plutosvg_document_t* document = plutosvg_document_load_from_data((const char*)data, length, units_per_EM, units_per_EM, NULL, NULL);
|
||||
if(document == NULL)
|
||||
return NULL;
|
||||
if(state->num_entries == PLUTOSVG_FT_MAX_DOCS) {
|
||||
state->num_entries--;
|
||||
plutosvg_document_destroy(state->entries[state->num_entries].document);
|
||||
}
|
||||
|
||||
memmove(&state->entries[1], &state->entries[0], state->num_entries * sizeof(plutosvg_ft_document_entry_t));
|
||||
state->entries[0].document = document;
|
||||
state->entries[0].data = data;
|
||||
state->entries[0].length = length;
|
||||
state->num_entries++;
|
||||
return document;
|
||||
}
|
||||
|
||||
static FT_Error plutosvg_ft_preset_slot(FT_GlyphSlot ft_slot, FT_Bool ft_cache, FT_Pointer* ft_state)
|
||||
{
|
||||
plutosvg_ft_state_t* state = (plutosvg_ft_state_t*)(*ft_state);
|
||||
|
||||
FT_SVG_Document ft_document = (FT_SVG_Document)ft_slot->other;
|
||||
FT_Size_Metrics ft_metrics = ft_document->metrics;
|
||||
|
||||
FT_UShort start_glyph_id = ft_document->start_glyph_id;
|
||||
FT_UShort end_glyph_id = ft_document->end_glyph_id;
|
||||
|
||||
plutosvg_document_t* document = plutosvg_ft_document_load(state, ft_document->svg_document, ft_document->svg_document_length, ft_document->units_per_EM);
|
||||
if(document == NULL) {
|
||||
return FT_Err_Invalid_SVG_Document;
|
||||
}
|
||||
|
||||
float document_width = plutosvg_document_get_width(document);
|
||||
float document_height = plutosvg_document_get_height(document);
|
||||
|
||||
plutovg_matrix_t transform = {
|
||||
(float)ft_document->transform.xx / (1 << 16),
|
||||
-(float)ft_document->transform.xy / (1 << 16),
|
||||
-(float)ft_document->transform.yx / (1 << 16),
|
||||
(float)ft_document->transform.yy / (1 << 16),
|
||||
(float)ft_document->delta.x / 64 * document_width / ft_metrics.x_ppem,
|
||||
-(float)ft_document->delta.y / 64 * document_height / ft_metrics.y_ppem
|
||||
};
|
||||
|
||||
float x_svg_to_out = ft_metrics.x_ppem / document_width;
|
||||
float y_svg_to_out = ft_metrics.y_ppem / document_height;
|
||||
|
||||
plutovg_matrix_t matrix;
|
||||
plutovg_matrix_init_scale(&matrix, x_svg_to_out, y_svg_to_out);
|
||||
plutovg_matrix_multiply(&matrix, &transform, &matrix);
|
||||
|
||||
char buffer[64];
|
||||
char* id = NULL;
|
||||
if(start_glyph_id < end_glyph_id) {
|
||||
sprintf(buffer, "glyph%u", ft_slot->glyph_index);
|
||||
id = buffer;
|
||||
}
|
||||
|
||||
plutovg_rect_t extents;
|
||||
if(!plutosvg_document_extents(document, id, &extents)) {
|
||||
return FT_Err_Invalid_SVG_Document;
|
||||
}
|
||||
|
||||
plutovg_matrix_map_rect(&matrix, &extents, &extents);
|
||||
ft_slot->bitmap_left = (FT_Int)extents.x;
|
||||
ft_slot->bitmap_top = (FT_Int)-extents.y;
|
||||
|
||||
ft_slot->bitmap.rows = (unsigned int)ceilf(extents.h);
|
||||
ft_slot->bitmap.width = (unsigned int)ceilf(extents.w);
|
||||
ft_slot->bitmap.pitch = (int)ft_slot->bitmap.width * 4;
|
||||
ft_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||
|
||||
float metrics_width = extents.w;
|
||||
float metrics_height = extents.h;
|
||||
|
||||
float horiBearingX = extents.x;
|
||||
float horiBearingY = -extents.y;
|
||||
|
||||
float vertBearingX = ft_slot->metrics.horiBearingX / 64.f - ft_slot->metrics.horiAdvance / 64.f / 2;
|
||||
float vertBearingY = (ft_slot->metrics.vertAdvance / 64.f - ft_slot->metrics.height / 64.f) / 2;
|
||||
|
||||
ft_slot->metrics.width = (FT_Pos)roundf(metrics_width * 64);
|
||||
ft_slot->metrics.height = (FT_Pos)roundf(metrics_height * 64);
|
||||
|
||||
ft_slot->metrics.horiBearingX = (FT_Pos)(horiBearingX * 64);
|
||||
ft_slot->metrics.horiBearingY = (FT_Pos)(horiBearingY * 64);
|
||||
ft_slot->metrics.vertBearingX = (FT_Pos)(vertBearingX * 64);
|
||||
ft_slot->metrics.vertBearingY = (FT_Pos)(vertBearingY * 64);
|
||||
if(ft_slot->metrics.vertAdvance == 0)
|
||||
ft_slot->metrics.vertAdvance = (FT_Pos)(metrics_height * 1.2f * 64);
|
||||
if(ft_cache) {
|
||||
state->document = document;
|
||||
state->extents = extents;
|
||||
state->matrix = matrix;
|
||||
}
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief FreeType SVG renderer hooks.
|
||||
*
|
||||
* This structure is passed to FreeType via FT_Property_Set to delegate SVG glyph
|
||||
* rendering to PlutoSVG.
|
||||
*/
|
||||
static SVG_RendererHooks plutosvg_ft_hooks = {
|
||||
(SVG_Lib_Init_Func)plutosvg_ft_init,
|
||||
(SVG_Lib_Free_Func)plutosvg_ft_free,
|
||||
(SVG_Lib_Render_Func)plutosvg_ft_render,
|
||||
(SVG_Lib_Preset_Slot_Func)plutosvg_ft_preset_slot
|
||||
};
|
||||
|
||||
#endif // PLUTOSVG_FT_H
|
||||
2655
3rdparty/plutosvg/source/plutosvg.c
vendored
Normal file
2655
3rdparty/plutosvg/source/plutosvg.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
191
3rdparty/plutosvg/source/plutosvg.h
vendored
Normal file
191
3rdparty/plutosvg/source/plutosvg.h
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2025 Samuel Ugochukwu <sammycageagle@gmail.com>
|
||||
*
|
||||
* 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 PLUTOSVG_H
|
||||
#define PLUTOSVG_H
|
||||
|
||||
#include <plutovg.h>
|
||||
|
||||
#if !defined(PLUTOSVG_BUILD_STATIC) && (defined(_WIN32) || defined(__CYGWIN__))
|
||||
#define PLUTOSVG_EXPORT __declspec(dllexport)
|
||||
#define PLUTOSVG_IMPORT __declspec(dllimport)
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
#define PLUTOSVG_EXPORT __attribute__((__visibility__("default")))
|
||||
#define PLUTOSVG_IMPORT
|
||||
#else
|
||||
#define PLUTOSVG_EXPORT
|
||||
#define PLUTOSVG_IMPORT
|
||||
#endif
|
||||
|
||||
#ifdef PLUTOSVG_BUILD
|
||||
#define PLUTOSVG_API PLUTOSVG_EXPORT
|
||||
#else
|
||||
#define PLUTOSVG_API PLUTOSVG_IMPORT
|
||||
#endif
|
||||
|
||||
#define PLUTOSVG_VERSION_MAJOR 0
|
||||
#define PLUTOSVG_VERSION_MINOR 0
|
||||
#define PLUTOSVG_VERSION_MICRO 6
|
||||
|
||||
#define PLUTOSVG_VERSION PLUTOVG_VERSION_ENCODE(PLUTOSVG_VERSION_MAJOR, PLUTOSVG_VERSION_MINOR, PLUTOSVG_VERSION_MICRO)
|
||||
#define PLUTOSVG_VERSION_STRING PLUTOVG_VERSION_STRINGIZE(PLUTOSVG_VERSION_MAJOR, PLUTOSVG_VERSION_MINOR, PLUTOSVG_VERSION_MICRO)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Returns the version number of PlutoSVG.
|
||||
*
|
||||
* @return The version number as an integer.
|
||||
*/
|
||||
PLUTOSVG_API int plutosvg_version(void);
|
||||
|
||||
/**
|
||||
* @brief Returns the version string of PlutoSVG.
|
||||
*
|
||||
* @return Pointer to a string containing the version information.
|
||||
*/
|
||||
PLUTOSVG_API const char* plutosvg_version_string(void);
|
||||
|
||||
/**
|
||||
* @brief plutosvg_document_t
|
||||
*/
|
||||
typedef struct plutosvg_document plutosvg_document_t;
|
||||
|
||||
/**
|
||||
* @brief Callback type for resolving CSS color variables in SVG documents.
|
||||
*
|
||||
* @param closure User-defined data for the callback.
|
||||
* @param name Name of the color variable.
|
||||
* @param length Length of the color variable name.
|
||||
* @param color Pointer to `plutovg_color_t` where the resolved color will be stored.
|
||||
* @return `true` if the color variable was successfully resolved; `false` otherwise.
|
||||
*/
|
||||
typedef bool(*plutosvg_palette_func_t)(void* closure, const char* name, int length, plutovg_color_t* color);
|
||||
|
||||
/**
|
||||
* @brief Loads an SVG document from a data buffer.
|
||||
*
|
||||
* @note The buffer pointed to by `data` must remain valid until the `plutosvg_document_t` object is destroyed.
|
||||
*
|
||||
* @param data Pointer to the SVG data buffer.
|
||||
* @param length Length of the data buffer.
|
||||
* @param width Container width for resolving the initial viewport.
|
||||
* @param height Container height for resolving the initial viewport.
|
||||
* @param destroy_func Custom function to call when the document is destroyed.
|
||||
* @param closure User-defined data for the `destroy_func` callback.
|
||||
* @return Pointer to the loaded `plutosvg_document_t` structure, or NULL if loading fails.
|
||||
*/
|
||||
PLUTOSVG_API plutosvg_document_t* plutosvg_document_load_from_data(const char* data, int length, float width, float height,
|
||||
plutovg_destroy_func_t destroy_func, void* closure);
|
||||
|
||||
/**
|
||||
* @brief Loads an SVG document from a file.
|
||||
*
|
||||
* @param filename Path to the SVG file.
|
||||
* @param width Container width for resolving the initial viewport.
|
||||
* @param height Container height for resolving the initial viewport.
|
||||
* @return Pointer to the loaded `plutosvg_document_t` structure, or NULL if loading fails.
|
||||
*/
|
||||
PLUTOSVG_API plutosvg_document_t* plutosvg_document_load_from_file(const char* filename, float width, float height);
|
||||
|
||||
/**
|
||||
* @brief Renders an SVG document or a specific element onto a canvas.
|
||||
*
|
||||
* @param document Pointer to the SVG document.
|
||||
* @param id ID of the SVG element to render, or `NULL` to render the entire document.
|
||||
* @param canvas Canvas onto which the SVG element or document will be rendered.
|
||||
* @param current_color Color used to resolve CSS `currentColor` values.
|
||||
* @param palette_func Callback for resolving CSS color variables.
|
||||
* @param closure User-defined data for the `palette_func` callback.
|
||||
* @return `true` if rendering was successful; `false` otherwise.
|
||||
*/
|
||||
PLUTOSVG_API bool plutosvg_document_render(const plutosvg_document_t* document, const char* id, plutovg_canvas_t* canvas,
|
||||
const plutovg_color_t* current_color, plutosvg_palette_func_t palette_func, void* closure);
|
||||
|
||||
/**
|
||||
* @brief Renders an SVG document or a specific element onto a surface.
|
||||
*
|
||||
* @param document Pointer to the SVG document.
|
||||
* @param id ID of the SVG element to render, or `NULL` to render the entire document.
|
||||
* @param width Width of the surface, or `-1` if unspecified.
|
||||
* @param height Height of the surface, or `-1` if unspecified.
|
||||
* @param current_color Color for resolving CSS `currentColor` values.
|
||||
* @param palette_func Callback for resolving CSS color variables.
|
||||
* @param closure User-defined data for the `palette_func` callback.
|
||||
* @return Pointer to the rendered `plutovg_surface_t` structure, or `NULL` if rendering fails.
|
||||
*/
|
||||
PLUTOSVG_API plutovg_surface_t* plutosvg_document_render_to_surface(const plutosvg_document_t* document, const char* id, int width, int height,
|
||||
const plutovg_color_t* current_color, plutosvg_palette_func_t palette_func, void* closure);
|
||||
|
||||
/**
|
||||
* @brief Returns the intrinsic width of the SVG document.
|
||||
*
|
||||
* @param document Pointer to the SVG document.
|
||||
* @return The intrinsic width of the SVG document.
|
||||
*/
|
||||
PLUTOSVG_API float plutosvg_document_get_width(const plutosvg_document_t* document);
|
||||
|
||||
/**
|
||||
* @brief Returns the intrinsic height of the SVG document.
|
||||
*
|
||||
* @param document Pointer to the SVG document.
|
||||
* @return The intrinsic height of the SVG document.
|
||||
*/
|
||||
PLUTOSVG_API float plutosvg_document_get_height(const plutosvg_document_t* document);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the bounding box of a specific element or the entire SVG document.
|
||||
*
|
||||
* Calculates and retrieves the extents of an element identified by `id` or the whole document if `id` is `NULL`.
|
||||
*
|
||||
* @param document Pointer to the SVG document.
|
||||
* @param id ID of the element whose extents to retrieve, or `NULL` to retrieve the extents of the entire document.
|
||||
* @param extents Pointer to a `plutovg_rect_t` structure where the extents will be stored.
|
||||
* @return `true` if extents were successfully retrieved; `false` otherwise.
|
||||
*/
|
||||
PLUTOSVG_API bool plutosvg_document_extents(const plutosvg_document_t* document, const char* id, plutovg_rect_t* extents);
|
||||
|
||||
/**
|
||||
* @brief Destroys an SVG document and frees its resources.
|
||||
*
|
||||
* @param document Pointer to a `plutosvg_document_t` structure to be destroyed. If `NULL`, the function does nothing.
|
||||
*/
|
||||
PLUTOSVG_API void plutosvg_document_destroy(plutosvg_document_t* document);
|
||||
|
||||
/**
|
||||
* @deprecated Use `plutosvg_ft_hooks` in "plutosvg-ft.h" instead.
|
||||
*
|
||||
* @brief Retrieves PlutoSVG hooks for integrating with FreeType's SVG module.
|
||||
*
|
||||
* Provides hooks that allow FreeType to use PlutoSVG for rendering SVG graphics in fonts.
|
||||
*
|
||||
* @return Pointer to the structure containing PlutoSVG hooks for FreeType's SVG module, or `NULL` if FreeType integration is not enabled.
|
||||
*/
|
||||
PLUTOSVG_API const void* plutosvg_ft_svg_hooks(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PLUTOSVG_H
|
||||
7
3rdparty/plutosvg/subprojects/plutovg.wrap
vendored
Normal file
7
3rdparty/plutosvg/subprojects/plutovg.wrap
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/sammycage/plutovg.git
|
||||
revision = head
|
||||
depth = 1
|
||||
|
||||
[provide]
|
||||
plutovg = plutovg_dep
|
||||
Reference in New Issue
Block a user