openscad-cpp-evaluator 1.28.1__tar.gz → 1.28.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/text_metrics.hpp +18 -4
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/function_builtins.cpp +8 -7
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/text.cpp +5 -4
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/text/freetype_font_provider.cpp +41 -6
- openscad_cpp_evaluator-1.28.3/src/text/text_metrics.cpp +95 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_text.cpp +63 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/uv.lock +1 -1
- openscad_cpp_evaluator-1.28.1/src/text/text_metrics.cpp +0 -70
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/README.md +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/tools/cli/main.cpp +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#include "openscad_cpp_evaluator/font_provider.hpp"
|
|
4
4
|
|
|
5
|
+
#include <functional>
|
|
5
6
|
#include <string>
|
|
6
7
|
#include <utility>
|
|
7
8
|
#include <vector>
|
|
@@ -12,7 +13,12 @@ namespace oscadeval {
|
|
|
12
13
|
// for `size`. `glyphs` is what text() places: each shaped glyph with its
|
|
13
14
|
// pen position, already scaled. An inkless glyph (a space) still advances
|
|
14
15
|
// the pen and still gets a glyphs entry -- it just contributes nothing to
|
|
15
|
-
// ascent/descent
|
|
16
|
+
// the ink box or ascent/descent.
|
|
17
|
+
//
|
|
18
|
+
// As in OpenSCAD's ShapeResults: left/right/bottom/top is the ink box of the
|
|
19
|
+
// glyphs where they are placed, while ascent/descent are the glyphs' own
|
|
20
|
+
// extents above and below THEIR baseline, ignoring where they sit. The two
|
|
21
|
+
// only differ for a vertical run or a glyph the shaper offsets (a mark).
|
|
16
22
|
//
|
|
17
23
|
// The run comes from the shaper, so kerning and ligatures are already
|
|
18
24
|
// applied and `spacing` scales the shaped advances rather than raw
|
|
@@ -23,8 +29,11 @@ struct TextMeasurement {
|
|
|
23
29
|
double x = 0, y = 0;
|
|
24
30
|
};
|
|
25
31
|
|
|
26
|
-
double ascent = 0, descent = 0
|
|
32
|
+
double ascent = 0, descent = 0;
|
|
33
|
+
double left = 0, right = 0, bottom = 0, top = 0;
|
|
27
34
|
double advanceX = 0, advanceY = 0;
|
|
35
|
+
bool hasInk = false;
|
|
36
|
+
bool vertical = false; // shaped ttb/btt
|
|
28
37
|
std::vector<Placed> glyphs;
|
|
29
38
|
};
|
|
30
39
|
|
|
@@ -32,9 +41,14 @@ TextMeasurement measureText(FontProvider& fp, FontHandle handle, const std::stri
|
|
|
32
41
|
double spacing, const ShapeOptions& opts = {});
|
|
33
42
|
|
|
34
43
|
// (offsetX, offsetY) translation for halign/valign, given a
|
|
35
|
-
// TextMeasurement.
|
|
44
|
+
// TextMeasurement. "default" is left/baseline for a horizontal run and
|
|
45
|
+
// center/top for a vertical one, as in OpenSCAD; text with no ink is not
|
|
46
|
+
// moved at all. Shared by textmetrics() (reports it) and text()
|
|
36
47
|
// (applies it).
|
|
48
|
+
// `warn`, when given, receives OpenSCAD's own warning for an unknown
|
|
49
|
+
// halign/valign, and for valign="baseline" on a vertical run.
|
|
37
50
|
std::pair<double, double> textAlignOffset(const std::string& halign, const std::string& valign,
|
|
38
|
-
const TextMeasurement& m
|
|
51
|
+
const TextMeasurement& m,
|
|
52
|
+
const std::function<void(const std::string&)>& warn = {});
|
|
39
53
|
|
|
40
54
|
} // namespace oscadeval
|
{openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/builtins/function_builtins.cpp
RENAMED
|
@@ -782,7 +782,7 @@ Value objectOf(std::vector<std::pair<std::string, Value>> items) {
|
|
|
782
782
|
// descent/offset/advance in real OpenSCAD's key order. Going through the
|
|
783
783
|
// same measureText() the geometry goes through is the point: the numbers
|
|
784
784
|
// a script positions against cannot disagree with what it draws.
|
|
785
|
-
Value builtinTextmetrics(Evaluator& ev, const CallArgs& args) {
|
|
785
|
+
Value builtinTextmetrics(Evaluator& ev, const CallArgs& args, const oscad::Position* pos) {
|
|
786
786
|
const std::string text = asStringOr(getArg(args, 0, "text", Value{std::string("")}), "");
|
|
787
787
|
const double size = toDoubleLenient(getArg(args, 1, "size", Value{10.0}));
|
|
788
788
|
// Positional indices, all of them: OpenSCAD's own signature is
|
|
@@ -792,8 +792,8 @@ Value builtinTextmetrics(Evaluator& ev, const CallArgs& args) {
|
|
|
792
792
|
// `font` being name-only here is what made
|
|
793
793
|
// `textmetrics("Hi", 10, "Liberation Sans:style=Bold")` silently
|
|
794
794
|
// measure the default face (BelfrySCAD #381).
|
|
795
|
-
const std::string halign = asStringOr(getArg(args, 6, "halign", Value{std::string("
|
|
796
|
-
const std::string valign = asStringOr(getArg(args, 7, "valign", Value{std::string("
|
|
795
|
+
const std::string halign = asStringOr(getArg(args, 6, "halign", Value{std::string("default")}), "default");
|
|
796
|
+
const std::string valign = asStringOr(getArg(args, 7, "valign", Value{std::string("default")}), "default");
|
|
797
797
|
const double spacing = toDoubleLenient(getArg(args, 8, "spacing", Value{1.0}));
|
|
798
798
|
const std::string fontSpec = asStringOr(getArg(args, 2, "font", Value{std::string("")}), "");
|
|
799
799
|
ShapeOptions shape;
|
|
@@ -804,11 +804,12 @@ Value builtinTextmetrics(Evaluator& ev, const CallArgs& args) {
|
|
|
804
804
|
FontProvider& fp = ev.fontProvider();
|
|
805
805
|
const FontHandle handle = fp.resolveFont(fontSpec);
|
|
806
806
|
const TextMeasurement m = measureText(fp, handle, text, size, spacing, shape);
|
|
807
|
-
const auto [offsetX, offsetY] = textAlignOffset(
|
|
807
|
+
const auto [offsetX, offsetY] = textAlignOffset(
|
|
808
|
+
halign, valign, m, [&](const std::string& w) { ev.warn(w, pos); });
|
|
808
809
|
|
|
809
810
|
return objectOf({
|
|
810
|
-
{"position", numList({offsetX + m.
|
|
811
|
-
{"size", numList({m.
|
|
811
|
+
{"position", numList({offsetX + m.left, offsetY + m.bottom})},
|
|
812
|
+
{"size", numList({m.right - m.left, m.top - m.bottom})},
|
|
812
813
|
{"ascent", Value{m.ascent}},
|
|
813
814
|
{"descent", Value{m.descent}},
|
|
814
815
|
{"offset", numList({offsetX, offsetY})},
|
|
@@ -1251,7 +1252,7 @@ Value evalBuiltinFunctionResolved(Evaluator& ev, BuiltinFnId id, const std::vect
|
|
|
1251
1252
|
|
|
1252
1253
|
switch (id) {
|
|
1253
1254
|
case BuiltinFnId::None: return Value{}; // unreachable: handled above
|
|
1254
|
-
case BuiltinFnId::TextMetrics: return builtinTextmetrics(ev, args);
|
|
1255
|
+
case BuiltinFnId::TextMetrics: return builtinTextmetrics(ev, args, &node.position());
|
|
1255
1256
|
case BuiltinFnId::FontMetrics: return builtinFontmetrics(ev, args);
|
|
1256
1257
|
case BuiltinFnId::Abs: return Value{std::fabs(toDoubleLenient(getArg(args, 0, "x", Value{})))};
|
|
1257
1258
|
case BuiltinFnId::Sign: {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
#include <algorithm>
|
|
9
9
|
|
|
10
|
-
// text(text=, size=10, font=, halign="
|
|
10
|
+
// text(text=, size=10, font=, halign="default", valign="default", spacing=1,
|
|
11
11
|
// direction=, language=, script=) -- renders `text` as 2D glyph outlines
|
|
12
12
|
// through the FontProvider (Evaluator::fontProvider(), lazily the built-in
|
|
13
13
|
// FreetypeFontProvider if none was injected).
|
|
@@ -46,8 +46,8 @@ CSGParams resolveText(Evaluator& ev, const oscad::ModularCall& node, EvalContext
|
|
|
46
46
|
// genuinely differ here -- textmetrics takes all nine positionally --
|
|
47
47
|
// so neither can be assumed from the other.
|
|
48
48
|
const std::string fontSpec = asStringOr(getArg(args, 2, "font", Value{std::string("")}), "");
|
|
49
|
-
const std::string halign = asStringOr(getArg(args, std::nullopt, "halign", Value{std::string("
|
|
50
|
-
const std::string valign = asStringOr(getArg(args, std::nullopt, "valign", Value{std::string("
|
|
49
|
+
const std::string halign = asStringOr(getArg(args, std::nullopt, "halign", Value{std::string("default")}), "default");
|
|
50
|
+
const std::string valign = asStringOr(getArg(args, std::nullopt, "valign", Value{std::string("default")}), "default");
|
|
51
51
|
const double spacing = toDoubleLenient(getArg(args, std::nullopt, "spacing", Value{1.0}));
|
|
52
52
|
ShapeOptions shape;
|
|
53
53
|
shape.direction = asStringOr(getArg(args, std::nullopt, "direction", Value{std::string("")}), "");
|
|
@@ -60,7 +60,8 @@ CSGParams resolveText(Evaluator& ev, const oscad::ModularCall& node, EvalContext
|
|
|
60
60
|
const double scale = size * (100.0 / 72.0) / fm.unitsPerEm;
|
|
61
61
|
const int segs = std::max(2, fnSegmentsFromCtx(effCtx) / 2);
|
|
62
62
|
const TextMeasurement m = measureText(fp, handle, text, size, spacing, shape);
|
|
63
|
-
const auto [offsetX, offsetY] = textAlignOffset(
|
|
63
|
+
const auto [offsetX, offsetY] = textAlignOffset(
|
|
64
|
+
halign, valign, m, [&](const std::string& w) { ev.warn(w, &node.position()); });
|
|
64
65
|
|
|
65
66
|
std::vector<Value> glyphs;
|
|
66
67
|
glyphs.reserve(m.glyphs.size());
|
{openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/src/text/freetype_font_provider.cpp
RENAMED
|
@@ -31,6 +31,45 @@ void scaleHbFontToEm(hb_font_t* font, unsigned int unitsPerEm) {
|
|
|
31
31
|
hb_font_set_scale(font, static_cast<int>(unitsPerEm), static_cast<int>(unitsPerEm));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// Vertical metrics come from FreeType, as they do in OpenSCAD (which shapes
|
|
35
|
+
// through hb-ft). For a font with no vmtx -- nearly every Latin font,
|
|
36
|
+
// Liberation Sans included -- the two disagree: hb-ot falls back to hhea
|
|
37
|
+
// ascender-descender, FreeType to OS/2 typo ascender-descender, so a ttb
|
|
38
|
+
// run of "abc" was 46.5 tall here and 39.1 there. Mirrors hb-ft's own
|
|
39
|
+
// callbacks; font units in and out, since the hb font is scaled to the em.
|
|
40
|
+
hb_position_t ftVAdvance(hb_font_t*, void* data, hb_codepoint_t glyph, void*) {
|
|
41
|
+
FT_Face ft = static_cast<FT_Face>(data);
|
|
42
|
+
if (FT_Load_Glyph(ft, glyph, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT) != 0) return 0;
|
|
43
|
+
return static_cast<hb_position_t>(-ft->glyph->metrics.vertAdvance); // FreeType's vertical grows downward
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
hb_bool_t ftVOrigin(hb_font_t*, void* data, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void*) {
|
|
47
|
+
FT_Face ft = static_cast<FT_Face>(data);
|
|
48
|
+
if (FT_Load_Glyph(ft, glyph, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT) != 0) return false;
|
|
49
|
+
const FT_Glyph_Metrics& m = ft->glyph->metrics;
|
|
50
|
+
*x = static_cast<hb_position_t>(m.horiBearingX - m.vertBearingX);
|
|
51
|
+
*y = static_cast<hb_position_t>(m.horiBearingY + m.vertBearingY);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// hb-ot for everything, with the vertical metrics overridden by FreeType.
|
|
56
|
+
hb_font_t* makeHbFont(hb_face_t* face, FT_Face ft, unsigned int unitsPerEm) {
|
|
57
|
+
static hb_font_funcs_t* vfuncs = [] {
|
|
58
|
+
hb_font_funcs_t* f = hb_font_funcs_create();
|
|
59
|
+
hb_font_funcs_set_glyph_v_advance_func(f, ftVAdvance, nullptr, nullptr);
|
|
60
|
+
hb_font_funcs_set_glyph_v_origin_func(f, ftVOrigin, nullptr, nullptr);
|
|
61
|
+
hb_font_funcs_make_immutable(f);
|
|
62
|
+
return f;
|
|
63
|
+
}();
|
|
64
|
+
hb_font_t* parent = hb_font_create(face);
|
|
65
|
+
hb_ot_font_set_funcs(parent);
|
|
66
|
+
scaleHbFontToEm(parent, unitsPerEm);
|
|
67
|
+
hb_font_t* font = hb_font_create_sub_font(parent); // everything unset delegates to parent
|
|
68
|
+
hb_font_destroy(parent);
|
|
69
|
+
hb_font_set_funcs(font, vfuncs, ft, nullptr);
|
|
70
|
+
return font;
|
|
71
|
+
}
|
|
72
|
+
|
|
34
73
|
struct OutlineSink {
|
|
35
74
|
GlyphContours contours;
|
|
36
75
|
std::vector<std::array<double, 2>> current;
|
|
@@ -159,10 +198,8 @@ struct FreetypeFontProvider::Impl {
|
|
|
159
198
|
return std::nullopt;
|
|
160
199
|
}
|
|
161
200
|
f.hbFace = hb_face_create(f.blob, static_cast<unsigned>(index));
|
|
162
|
-
f.hbFont = hb_font_create(f.hbFace);
|
|
163
|
-
hb_ot_font_set_funcs(f.hbFont);
|
|
164
201
|
f.metrics = readMetrics(f.ft);
|
|
165
|
-
|
|
202
|
+
f.hbFont = makeHbFont(f.hbFace, f.ft, static_cast<unsigned>(f.metrics.unitsPerEm));
|
|
166
203
|
faces.push_back(f);
|
|
167
204
|
return faces.size() - 1;
|
|
168
205
|
}
|
|
@@ -185,10 +222,8 @@ struct FreetypeFontProvider::Impl {
|
|
|
185
222
|
f.blob = hb_blob_create(reinterpret_cast<const char*>(src.data),
|
|
186
223
|
static_cast<unsigned>(src.size), HB_MEMORY_MODE_READONLY, nullptr, nullptr);
|
|
187
224
|
f.hbFace = hb_face_create(f.blob, 0);
|
|
188
|
-
f.hbFont = hb_font_create(f.hbFace);
|
|
189
|
-
hb_ot_font_set_funcs(f.hbFont);
|
|
190
225
|
f.metrics = readMetrics(f.ft);
|
|
191
|
-
|
|
226
|
+
f.hbFont = makeHbFont(f.hbFace, f.ft, static_cast<unsigned>(f.metrics.unitsPerEm));
|
|
192
227
|
faces.push_back(f);
|
|
193
228
|
}
|
|
194
229
|
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#include "openscad_cpp_evaluator/text_metrics.hpp"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cctype>
|
|
5
|
+
|
|
6
|
+
namespace oscadeval {
|
|
7
|
+
|
|
8
|
+
TextMeasurement measureText(FontProvider& fp, FontHandle handle, const std::string& text, double size,
|
|
9
|
+
double spacing, const ShapeOptions& opts) {
|
|
10
|
+
const FontMetrics fm = fp.metrics(handle);
|
|
11
|
+
// The 100/72 factor is real OpenSCAD's long-standing text() size bug
|
|
12
|
+
// (its issue #4304: FT_Set_Char_Size is given 100 dpi where 72 is
|
|
13
|
+
// correct, making glyphs ~1.39x the nominal size). It is reproduced
|
|
14
|
+
// deliberately -- a decade of models are drawn to it, and OpenSCAD
|
|
15
|
+
// itself chose to keep the bug and add an `em=` parameter rather than
|
|
16
|
+
// fix it.
|
|
17
|
+
const double scale = size * (100.0 / 72.0) / fm.unitsPerEm;
|
|
18
|
+
|
|
19
|
+
TextMeasurement m;
|
|
20
|
+
// hb_direction_from_string reads only the first letter, so this is
|
|
21
|
+
// exactly the set of strings the shaper takes as vertical.
|
|
22
|
+
const char d = opts.direction.empty() ? 'l' : static_cast<char>(std::tolower(opts.direction[0]));
|
|
23
|
+
m.vertical = d == 't' || d == 'b';
|
|
24
|
+
double penX = 0.0, penY = 0.0;
|
|
25
|
+
|
|
26
|
+
for (const ShapedGlyph& g : fp.shapeText(handle, text, opts)) {
|
|
27
|
+
const double x = (penX + g.xOffset) * scale;
|
|
28
|
+
const double y = (penY + g.yOffset) * scale;
|
|
29
|
+
|
|
30
|
+
if (const std::optional<std::array<double, 4>> b = fp.glyphInkBounds(handle, g.glyph)) {
|
|
31
|
+
const double gl = x + (*b)[0] * scale, gr = x + (*b)[2] * scale;
|
|
32
|
+
const double gb = y + (*b)[1] * scale, gt = y + (*b)[3] * scale;
|
|
33
|
+
const double asc = (*b)[3] * scale, desc = (*b)[1] * scale;
|
|
34
|
+
if (!m.hasInk) {
|
|
35
|
+
m.left = gl, m.right = gr, m.bottom = gb, m.top = gt;
|
|
36
|
+
m.ascent = asc, m.descent = desc;
|
|
37
|
+
m.hasInk = true;
|
|
38
|
+
} else {
|
|
39
|
+
m.left = std::min(m.left, gl);
|
|
40
|
+
m.right = std::max(m.right, gr);
|
|
41
|
+
m.bottom = std::min(m.bottom, gb);
|
|
42
|
+
m.top = std::max(m.top, gt);
|
|
43
|
+
m.ascent = std::max(m.ascent, asc);
|
|
44
|
+
m.descent = std::min(m.descent, desc);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
m.glyphs.push_back(TextMeasurement::Placed{g.glyph, x, y});
|
|
49
|
+
penX += g.xAdvance * spacing;
|
|
50
|
+
penY += g.yAdvance * spacing;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
m.advanceX = penX * scale;
|
|
54
|
+
m.advanceY = penY * scale;
|
|
55
|
+
return m;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// OpenSCAD's ShapeResults::calc_offsets_horiz/_vert, warnings included. An
|
|
59
|
+
// unknown value, or valign="baseline" on a vertical run, leaves that axis
|
|
60
|
+
// where it is. Text with no ink never gets this far there, so it never
|
|
61
|
+
// warns either.
|
|
62
|
+
std::pair<double, double> textAlignOffset(const std::string& halign, const std::string& valign,
|
|
63
|
+
const TextMeasurement& m,
|
|
64
|
+
const std::function<void(const std::string&)>& warn) {
|
|
65
|
+
if (!m.hasInk) return {0.0, 0.0};
|
|
66
|
+
auto unknown = [&](const char* param, const char* choices, const std::string& value) {
|
|
67
|
+
if (warn) {
|
|
68
|
+
warn(std::string("Unknown value for the ") + param + " parameter (use " + choices + "): '" + value + "'");
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const char* hChoices = "\"left\", \"right\" or \"center\"";
|
|
72
|
+
const char* vChoices = "\"baseline\", \"bottom\", \"top\" or \"center\"";
|
|
73
|
+
double offsetX = 0.0, offsetY = 0.0;
|
|
74
|
+
if (m.vertical) {
|
|
75
|
+
if (halign == "right") offsetX = -m.right;
|
|
76
|
+
else if (halign == "left") offsetX = -m.left;
|
|
77
|
+
else if (halign != "center" && halign != "default") unknown("halign", hChoices, halign);
|
|
78
|
+
if (valign == "center") offsetY = -m.advanceY / 2;
|
|
79
|
+
else if (valign == "bottom") offsetY = -m.advanceY;
|
|
80
|
+
else if (valign == "baseline") {
|
|
81
|
+
if (warn) warn("Don't use valign=\"baseline\" with vertical layouts");
|
|
82
|
+
} else if (valign != "top" && valign != "default") unknown("valign", vChoices, valign);
|
|
83
|
+
} else {
|
|
84
|
+
if (halign == "center") offsetX = -0.5 * m.advanceX;
|
|
85
|
+
else if (halign == "right") offsetX = -m.advanceX;
|
|
86
|
+
else if (halign != "left" && halign != "default") unknown("halign", hChoices, halign);
|
|
87
|
+
if (valign == "top") offsetY = -m.ascent;
|
|
88
|
+
else if (valign == "center") offsetY = -(m.ascent + m.descent) / 2;
|
|
89
|
+
else if (valign == "bottom") offsetY = -m.descent;
|
|
90
|
+
else if (valign != "baseline" && valign != "default") unknown("valign", vChoices, valign);
|
|
91
|
+
}
|
|
92
|
+
return {offsetX, offsetY};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
} // namespace oscadeval
|
|
@@ -97,6 +97,69 @@ TEST(Textmetrics, AdvanceXIsPositiveForNonEmptyText) {
|
|
|
97
97
|
EXPECT_DOUBLE_EQ(asNum(items[1]), 0.0);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
// Vertical runs, against OpenSCAD 2026.02.01 (it hints, so ~0.01 apart).
|
|
101
|
+
// Its vertical metrics are FreeType's -- OS/2 typo ascender-descender for a
|
|
102
|
+
// font without vmtx -- not hb-ot's hhea fallback, which gave 46.5 here.
|
|
103
|
+
namespace {
|
|
104
|
+
double vec(const Value& obj, const std::string& key, int i) {
|
|
105
|
+
return asNum(std::get<ListPtr>(objGet(obj, key))->items[i]);
|
|
106
|
+
}
|
|
107
|
+
} // namespace
|
|
108
|
+
|
|
109
|
+
TEST(Textmetrics, VerticalRunMatchesOpenscad) {
|
|
110
|
+
Evaluator ev;
|
|
111
|
+
Value v = asExpr("textmetrics(\"abc\", size=10, direction=\"ttb\")", ev);
|
|
112
|
+
EXPECT_NEAR(vec(v, "advance", 1), -39.1032, 1e-3);
|
|
113
|
+
EXPECT_NEAR(vec(v, "position", 0), -3.2733, 0.01);
|
|
114
|
+
EXPECT_NEAR(vec(v, "position", 1), -36.3957, 0.01);
|
|
115
|
+
EXPECT_NEAR(vec(v, "size", 1), 33.6848, 0.01);
|
|
116
|
+
EXPECT_NEAR(asNum(objGet(v, "ascent")), 10.0672, 0.01); // the glyphs' own, not their placement
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
TEST(Textmetrics, VerticalRunAlignsByItsOwnRules) {
|
|
120
|
+
Evaluator ev;
|
|
121
|
+
Value lc = asExpr("textmetrics(\"abc\", size=10, direction=\"ttb\", halign=\"left\", valign=\"center\")", ev);
|
|
122
|
+
EXPECT_NEAR(vec(lc, "offset", 0), 3.2733, 0.01);
|
|
123
|
+
EXPECT_NEAR(vec(lc, "offset", 1), 19.5516, 1e-3);
|
|
124
|
+
Value rb = asExpr("textmetrics(\"abc\", size=10, direction=\"ttb\", halign=\"right\", valign=\"bottom\")", ev);
|
|
125
|
+
EXPECT_NEAR(vec(rb, "offset", 0), -3.8627, 0.01);
|
|
126
|
+
EXPECT_NEAR(vec(rb, "offset", 1), 39.1032, 1e-3);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// OpenSCAD 2026.02.01's warnings, verbatim. Inkless text never reaches
|
|
130
|
+
// its alignment code there, so it does not warn.
|
|
131
|
+
TEST(Text, UnknownAlignmentWarnsAsOpenscadDoes) {
|
|
132
|
+
const std::pair<const char*, std::vector<std::string>> cases[] = {
|
|
133
|
+
{"m = textmetrics(\"ab\", halign=\"middle\");",
|
|
134
|
+
{"Unknown value for the halign parameter (use \"left\", \"right\" or \"center\"): 'middle'"}},
|
|
135
|
+
{"m = textmetrics(\"ab\", valign=\"mid\");",
|
|
136
|
+
{"Unknown value for the valign parameter (use \"baseline\", \"bottom\", \"top\" or \"center\"): 'mid'"}},
|
|
137
|
+
{"m = textmetrics(\"ab\", direction=\"ttb\", valign=\"baseline\");",
|
|
138
|
+
{"Don't use valign=\"baseline\" with vertical layouts"}},
|
|
139
|
+
{"text(\"ab\", direction=\"ttb\", halign=\"x\", valign=\"y\");",
|
|
140
|
+
{"Unknown value for the halign parameter (use \"left\", \"right\" or \"center\"): 'x'",
|
|
141
|
+
"Unknown value for the valign parameter (use \"baseline\", \"bottom\", \"top\" or \"center\"): 'y'"}},
|
|
142
|
+
{"m = textmetrics(\" \", halign=\"bogus\");", {}},
|
|
143
|
+
{"m = textmetrics(\"ab\", halign=\"default\", valign=\"default\");", {}},
|
|
144
|
+
{"m = textmetrics(\"ab\", direction=\"ttb\", valign=\"top\");", {}},
|
|
145
|
+
};
|
|
146
|
+
for (const auto& [src, want] : cases) {
|
|
147
|
+
std::vector<std::string> log;
|
|
148
|
+
evalSrc(src, [&](const std::string& m) { log.push_back(m); });
|
|
149
|
+
ASSERT_EQ(log.size(), want.size()) << src;
|
|
150
|
+
for (size_t i = 0; i < want.size(); ++i) {
|
|
151
|
+
EXPECT_EQ(log[i], "WARNING: " + want[i] + " in file <string>, line 1") << src;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
TEST(Textmetrics, InklessTextIsNotAligned) {
|
|
157
|
+
Evaluator ev;
|
|
158
|
+
Value v = asExpr("textmetrics(\" \", size=10, halign=\"right\")", ev);
|
|
159
|
+
EXPECT_EQ(vec(v, "offset", 0), 0.0);
|
|
160
|
+
EXPECT_GT(vec(v, "advance", 0), 7.0);
|
|
161
|
+
}
|
|
162
|
+
|
|
100
163
|
TEST(Textmetrics, AscentIsPositiveDescentIsNonPositive) {
|
|
101
164
|
Evaluator ev;
|
|
102
165
|
Value v = asExpr("textmetrics(text=\"Hi\", size=10)", ev);
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
#include "openscad_cpp_evaluator/text_metrics.hpp"
|
|
2
|
-
|
|
3
|
-
#include <algorithm>
|
|
4
|
-
|
|
5
|
-
namespace oscadeval {
|
|
6
|
-
|
|
7
|
-
TextMeasurement measureText(FontProvider& fp, FontHandle handle, const std::string& text, double size,
|
|
8
|
-
double spacing, const ShapeOptions& opts) {
|
|
9
|
-
const FontMetrics fm = fp.metrics(handle);
|
|
10
|
-
// The 100/72 factor is real OpenSCAD's long-standing text() size bug
|
|
11
|
-
// (its issue #4304: FT_Set_Char_Size is given 100 dpi where 72 is
|
|
12
|
-
// correct, making glyphs ~1.39x the nominal size). It is reproduced
|
|
13
|
-
// deliberately -- a decade of models are drawn to it, and OpenSCAD
|
|
14
|
-
// itself chose to keep the bug and add an `em=` parameter rather than
|
|
15
|
-
// fix it.
|
|
16
|
-
const double scale = size * (100.0 / 72.0) / fm.unitsPerEm;
|
|
17
|
-
|
|
18
|
-
TextMeasurement m;
|
|
19
|
-
double penX = 0.0, penY = 0.0;
|
|
20
|
-
bool hasInk = false;
|
|
21
|
-
|
|
22
|
-
for (const ShapedGlyph& g : fp.shapeText(handle, text, opts)) {
|
|
23
|
-
const double x = (penX + g.xOffset) * scale;
|
|
24
|
-
const double y = (penY + g.yOffset) * scale;
|
|
25
|
-
|
|
26
|
-
if (const std::optional<std::array<double, 4>> b = fp.glyphInkBounds(handle, g.glyph)) {
|
|
27
|
-
const double left = x + (*b)[0] * scale;
|
|
28
|
-
const double right = x + (*b)[2] * scale;
|
|
29
|
-
const double bottom = y + (*b)[1] * scale;
|
|
30
|
-
const double top = y + (*b)[3] * scale;
|
|
31
|
-
if (!hasInk) {
|
|
32
|
-
m.inkMinX = left;
|
|
33
|
-
m.inkMaxX = right;
|
|
34
|
-
m.ascent = top;
|
|
35
|
-
m.descent = bottom;
|
|
36
|
-
hasInk = true;
|
|
37
|
-
} else {
|
|
38
|
-
m.inkMinX = std::min(m.inkMinX, left);
|
|
39
|
-
m.inkMaxX = std::max(m.inkMaxX, right);
|
|
40
|
-
m.ascent = std::max(m.ascent, top);
|
|
41
|
-
m.descent = std::min(m.descent, bottom);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
m.glyphs.push_back(TextMeasurement::Placed{g.glyph, x, y});
|
|
46
|
-
penX += g.xAdvance * spacing;
|
|
47
|
-
penY += g.yAdvance * spacing;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
m.advanceX = penX * scale;
|
|
51
|
-
m.advanceY = penY * scale;
|
|
52
|
-
return m;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
std::pair<double, double> textAlignOffset(const std::string& halign, const std::string& valign,
|
|
56
|
-
const TextMeasurement& m) {
|
|
57
|
-
double offsetX = 0.0;
|
|
58
|
-
if (halign == "center") offsetX = -0.5 * m.advanceX;
|
|
59
|
-
else if (halign == "right") offsetX = -1.0 * m.advanceX;
|
|
60
|
-
|
|
61
|
-
double offsetY = 0.0;
|
|
62
|
-
if (valign == "top") offsetY = -m.ascent;
|
|
63
|
-
else if (valign == "center") offsetY = -(m.ascent + m.descent) / 2;
|
|
64
|
-
else if (valign == "bottom") offsetY = -m.descent;
|
|
65
|
-
// "baseline" (or anything else) -> 0
|
|
66
|
-
|
|
67
|
-
return {offsetX, offsetY};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
} // namespace oscadeval
|
|
File without changes
|
{openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/.github/workflows/wheels.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.28.1 → openscad_cpp_evaluator-1.28.3}/examples/minimal_debugger.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|