diff options
Diffstat (limited to 'testfiles')
199 files changed, 11686 insertions, 0 deletions
diff --git a/testfiles/CMakeLists.txt b/testfiles/CMakeLists.txt new file mode 100644 index 0000000..9fbffc1 --- /dev/null +++ b/testfiles/CMakeLists.txt @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# ----------------------------------------------------------------------------- + +# custom "check" target with proper dependencies (builds inkscape and tests) +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + DEPENDS tests + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_dependencies(check inkscape) + + +# create symlink "inkscape_datadir" to use as INKSCAPE_DATADIR +# - ensures tests can be run without installing the project +# - also helpful for running Inkscape uninstalled: 'INKSVAPE_DATADIR=inkscape_datadir bin/inkscape' +set(INKSCAPE_DATADIR ${CMAKE_BINARY_DIR}/inkscape_datadir) +if(NOT EXISTS ${INKSCAPE_DATADIR}/inkscape) + set(link_source ${INKSCAPE_DATADIR}/inkscape) + set(link_target ${CMAKE_SOURCE_DIR}/share) + message(STATUS "Creating link '${link_source}' --> '${link_target}'") + execute_process(COMMAND mkdir inkscape_datadir) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${link_target} ${link_source} + RESULT_VARIABLE result) + if(result) + message(WARNING "Creation of link failed: ${result}") + endif() +endif() +# check if creation succeeded +if(EXISTS ${INKSCAPE_DATADIR}/inkscape) + set(CMAKE_CTEST_ENV INKSCAPE_DATADIR=${INKSCAPE_DATADIR}) +else() + message(WARNING "Directory 'inkscape_datadir/inkscape' missing. Tests might not run properly.\n" + "Possible solutions:\n" + " - create a suitable symlink yourself, e.g.\n" + " ln -s ${CMAKE_SOURCE_DIR}/share ${INKSCAPE_DATADIR}/inkscape\n" + " - run '${CMAKE_MAKE_PROGRAM} install' before running tests (only for not relocatable packages.\n" + " - set the environment variable 'INKSCAPE_DATADIR' manually (every time you run tests)") +endif() + + +# Set custom profile directory for tests using environment variable. +# Copy CTestCustom.cmake into binary dir, where it will be picked up automatically by ctest for cleanup. +set(INKSCAPE_TEST_PROFILE_DIR ${CMAKE_CURRENT_BINARY_DIR}/test_profile_dir) +set(INKSCAPE_TEST_PROFILE_DIR_ENV INKSCAPE_PROFILE_DIR=${INKSCAPE_TEST_PROFILE_DIR}) +configure_file(CTestCustom.cmake.in ${CMAKE_BINARY_DIR}/CTestCustom.cmake) + + + +### tests using gtest +include_directories("${CMAKE_SOURCE_DIR}/src/3rdparty/adaptagrams") # TODO: remove this hack + +set(TEST_SOURCES + uri-test + drag-and-drop-svgz + extract-uri-test + attributes-test + color-profile-test + dir-util-test + sp-object-test + object-set-test + object-style-test + style-elem-test + style-test + svg-stringstream-test + sp-gradient-test + object-test + curve-test + 2geom-characterization-test + lpe-bool-test + sp-item-group-test) + +set(TEST_LIBS + ${GTEST_LIBRARIES} + inkscape_base) + +add_library(cpp_test_object_library OBJECT unittest.cpp doc-per-case-test.cpp) + +add_custom_target(tests) +foreach(test_source ${TEST_SOURCES}) + string(REPLACE "-test" "" testname "test_${test_source}") + add_executable(${testname} src/${test_source}.cpp $<TARGET_OBJECTS:cpp_test_object_library>) + target_include_directories(${testname} SYSTEM PRIVATE ${GTEST_INCLUDE_DIRS}) + target_link_libraries(${testname} ${TEST_LIBS}) + add_test(NAME ${testname} COMMAND ${testname}) + set_tests_properties(${testname} PROPERTIES ENVIRONMENT "${INKSCAPE_TEST_PROFILE_DIR_ENV}/${testname};${CMAKE_CTEST_ENV}") + add_dependencies(tests ${testname}) +endforeach() + + +### CLI and rendering tests +add_subdirectory(cli_tests) +add_subdirectory(rendering_tests) + + +### Fuzz test +if(WITH_FUZZ) + # to use the fuzzer, make sure you use the right compiler (clang) + # with the right flags -fsanitize=address -fsanitize-coverage=edge,trace-pc-guard,indirect-calls,trace-cmp,trace-div,trace-gep -fno-omit-frame-pointer + # (see libfuzzer doc for info in flags) + # first line is for integration into oss-fuzz https://github.com/google/oss-fuzz + add_executable(fuzz fuzzer.cpp) + if(LIB_FUZZING_ENGINE) + target_link_libraries(fuzz inkscape_base -lFuzzingEngine) + else() + target_link_libraries(fuzz inkscape_base -lFuzzer) + endif() +endif() diff --git a/testfiles/CTestCustom.cmake.in b/testfiles/CTestCustom.cmake.in new file mode 100644 index 0000000..9c1c834 --- /dev/null +++ b/testfiles/CTestCustom.cmake.in @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Cleanup test-specific profile directories whenever running tests (before and after, just to be safe) +set(CTEST_CUSTOM_PRE_TEST "rm -rf ${INKSCAPE_TEST_PROFILE_DIR}") +set(CTEST_CUSTOM_POST_TEST "rm -rf ${INKSCAPE_TEST_PROFILE_DIR}") diff --git a/testfiles/cli_tests/CMakeLists.txt b/testfiles/cli_tests/CMakeLists.txt new file mode 100644 index 0000000..032cd95 --- /dev/null +++ b/testfiles/cli_tests/CMakeLists.txt @@ -0,0 +1,441 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + + +# Helper function to add a CLI test +# +# Run an Inkscape command line and check for pass/fail condition (by default only exit status is checked) +# +# Command line options: +# INPUT_FILENAME - name of input file (optional) +# OUTPUT_FILENAME - name of output file (optional) +# PARAMETERS - additional command line parameters to pass to Inkscape +# +# Pass/fail criteria: +# PASS_FOR_OUTPUT - pass if output matches the given value, otherwise fail +# see https://cmake.org/cmake/help/latest/prop_test/PASS_REGULAR_EXPRESSION.html for details +# FAIL_FOR_OUTPUT - fail if output matches the given value +# see https://cmake.org/cmake/help/latest/prop_test/FAIL_REGULAR_EXPRESSION.html for details +# REFERENCE_FILENAME - compare OUTPUT_FILENAME with this pre-rendered reference file +# both files are converted to PNG and compared with ImageMagick's 'compare' +# EXPECTED_FILES - verify the command produced the expected files (i.e. they exist on disk) +# TEST_SCRIPT - additional script to run after performing all checks and before cleaning up +# +# Other options: +# ENVIRONMENT - Additional environment variables to set while running the test +function(add_cli_test name) + # parse arguments + set(oneValueArgs INPUT_FILENAME OUTPUT_FILENAME PASS_FOR_OUTPUT FAIL_FOR_OUTPUT REFERENCE_FILENAME) + set(multiValueArgs PARAMETERS EXPECTED_FILES TEST_SCRIPT ENVIRONMENT) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set(testname cli_${name}) + + if(DEFINED ARG_OUTPUT_FILENAME) + set(ARG_PARAMETERS ${ARG_PARAMETERS} "--export-filename=${ARG_OUTPUT_FILENAME}") + endif() + if(DEFINED ARG_INPUT_FILENAME) + set(ARG_INPUT_FILENAME "${CMAKE_CURRENT_SOURCE_DIR}/testcases/${ARG_INPUT_FILENAME}") + set(ARG_PARAMETERS ${ARG_PARAMETERS} ${ARG_INPUT_FILENAME}) + endif() + + set(CMAKE_CTEST_ENV "${INKSCAPE_TEST_PROFILE_DIR_ENV}/${testname};${CMAKE_CTEST_ENV}") + if(DEFINED ARG_ENVIRONMENT) + if(ARG_ENVIRONMENT STREQUAL "unset") + unset(CMAKE_CTEST_ENV) + else() + # variables might already be set, however the last value wins + list(APPEND CMAKE_CTEST_ENV ${ARG_ENVIRONMENT}) + endif() + endif() + + # add test for main command line + add_test(NAME ${testname} COMMAND inkscape ${ARG_PARAMETERS}) + set_tests_properties(${testname} PROPERTIES ENVIRONMENT "${CMAKE_CTEST_ENV}") + if(DEFINED ARG_PASS_FOR_OUTPUT) + set_tests_properties(${testname} PROPERTIES PASS_REGULAR_EXPRESSION ${ARG_PASS_FOR_OUTPUT}) + endif() + if(DEFINED ARG_FAIL_FOR_OUTPUT) + set_tests_properties(${testname} PROPERTIES FAIL_REGULAR_EXPRESSION ${ARG_FAIL_FOR_OUTPUT}) + endif() + + # add test to check output files + if(DEFINED ARG_REFERENCE_FILENAME OR DEFINED ARG_EXPECTED_FILES OR DEFINED ARG_TEST_SCRIPT) + if(DEFINED ARG_REFERENCE_FILENAME) + file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/testcases/${ARG_REFERENCE_FILENAME}" ARG_REFERENCE_FILENAME) + endif() + if(DEFINED ARG_EXPECTED_FILES) + string(REPLACE ";" " " ARG_EXPECTED_FILES "${ARG_EXPECTED_FILES}") + endif() + if(DEFINED ARG_TEST_SCRIPT) + set(ARG_TEST_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${ARG_TEST_SCRIPT}") + endif() + + add_test(NAME ${testname}_check_output + COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/check_output.sh + "${ARG_OUTPUT_FILENAME}" "${ARG_REFERENCE_FILENAME}" "${ARG_EXPECTED_FILES}" "${ARG_TEST_SCRIPT}") + set_tests_properties(${testname}_check_output PROPERTIES + ENVIRONMENT "${CMAKE_CTEST_ENV}" DEPENDS ${testname} SKIP_RETURN_CODE 42) + endif() +endfunction(add_cli_test) + + + +##### Tests follow below ##### + + + +############################################################################################# +### Command line options (basic tests for all program options as listed in --help output) ### +############################################################################################# + +# --help + +# --version (check if we can run inkscape and the revision is known) +add_cli_test(version PARAMETERS --version) +add_cli_test(version_known PARAMETERS --version FAIL_FOR_OUTPUT unknown) + +# --system-data-directory / --user-data-directory (unset environment variables to override our override) +# TODO: Can we make these tests more specific without making too many assumptions? +add_cli_test(system-data-directory PARAMETERS --system-data-directory ENVIRONMENT unset PASS_FOR_OUTPUT "inkscape\n$") +add_cli_test(user-data-directory PARAMETERS --user-data-directory ENVIRONMENT unset PASS_FOR_OUTPUT "inkscape\n$") + +# --pipe + +# --pdf-page=PAGE + +# --pdf-poppler +add_cli_test(pdf-poppler-mesh-import + PARAMETERS --pdf-poppler + INPUT_FILENAME pdf-mesh.pdf + OUTPUT_FILENAME pdf-mesh_poppler.svg + TEST_SCRIPT match_regex.sh pdf-mesh_poppler.svg "<image") +add_cli_test(pdf-internal-mesh-import + INPUT_FILENAME pdf-mesh.pdf + OUTPUT_FILENAME pdf-mesh_internal.svg + TEST_SCRIPT match_regex_fail.sh pdf-mesh_internal.svg "<image") + +# --convert-dpi-method=METHOD + +# --no-convert-text-baseline-spacing + +# --export-filename=FILENAME + +# --export-overwrite + +# --export-type=TYPE[,TYPE]* + +## test whether we can export all default types in principle (and in one command) +add_cli_test(export-type PARAMETERS --export-type=svg,png,ps,eps,pdf,emf,wmf,xaml + INPUT_FILENAME empty.svg OUTPUT_FILENAME empty + EXPECTED_FILES empty.svg empty.png empty.ps empty.eps empty.pdf empty.emf empty.wmf empty.xaml) + +## test whether we produce sane output for the default types +add_cli_test(export-type_svg PARAMETERS --export-type=svg INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.svg REFERENCE_FILENAME shapes.svg) +add_cli_test(export-type_png PARAMETERS --export-type=png INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.png REFERENCE_FILENAME shapes_expected.png) +add_cli_test(export-type_ps PARAMETERS --export-type=ps INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.ps REFERENCE_FILENAME shapes_expected.ps) +add_cli_test(export-type_eps PARAMETERS --export-type=eps INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.eps REFERENCE_FILENAME shapes_expected.eps) +add_cli_test(export-type_pdf PARAMETERS --export-type=pdf INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.pdf REFERENCE_FILENAME shapes_expected.pdf) +add_cli_test(export-type_emf PARAMETERS --export-type=emf INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.emf REFERENCE_FILENAME shapes_expected.emf) +add_cli_test(export-type_wmf PARAMETERS --export-type=wmf INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.wmf REFERENCE_FILENAME shapes_expected.wmf) +# XAML is not supported by ImageMagick's convert, so simply compare binary +add_cli_test(export-type_xaml PARAMETERS --export-type=xaml INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.xaml + TEST_SCRIPT compare.sh shapes.xaml "${CMAKE_CURRENT_SOURCE_DIR}/testcases/shapes_expected.xaml") + +# --export-area-page +add_cli_test(export-area-page_png PARAMETERS --export-area-page --export-type=png INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page.png REFERENCE_FILENAME export-area-page_expected.png) +add_cli_test(export-area-page_svg PARAMETERS --export-area-page --export-type=svg INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page.svg REFERENCE_FILENAME export-area-page_expected.svg) +add_cli_test(export-area-page_pdf PARAMETERS --export-area-page --export-type=pdf INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page.pdf REFERENCE_FILENAME export-area-page_expected.pdf) +add_cli_test(export-area-page_ps PARAMETERS --export-area-page --export-type=ps INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page.ps REFERENCE_FILENAME export-area-page_expected.ps) +# EPS: Currently not supported. Feature request: https://gitlab.com/inkscape/inkscape/-/issues/1074 +# add_cli_test(export-area-page_eps PARAMETERS --export-area-page --export-type=eps INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page.eps REFERENCE_FILENAME export-area-page_expected.eps) +add_cli_test(export-area-page_emf PARAMETERS --export-area-page --export-type=emf INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page.emf REFERENCE_FILENAME export-area-page_expected.emf) +add_cli_test(export-area-page_wmf PARAMETERS --export-area-page --export-type=wmf INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page.wmf REFERENCE_FILENAME export-area-page_expected.wmf) + +# --export-area-page + --export-id (+ --export-id-only) +# TODO: PDF/PS/EPS always behave as if --export-id-only was given, see https://gitlab.com/inkscape/inkscape/-/issues/1173 +add_cli_test(export-area-page_export-id_png PARAMETERS --export-area-page --export-id=MyStar --export-id-only INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page_export-id.png REFERENCE_FILENAME export-area-page_export-id.png) +add_cli_test(export-area-page_export-id_svg PARAMETERS --export-area-page --export-id=MyStar --export-id-only INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page_export-id.svg REFERENCE_FILENAME export-area-page_export-id.svg) +add_cli_test(export-area-page_export-id_pdf PARAMETERS --export-area-page --export-id=MyStar INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page_export-id.pdf REFERENCE_FILENAME export-area-page_export-id.pdf) +add_cli_test(export-area-page_export-id_ps PARAMETERS --export-area-page --export-id=MyStar INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page_export-id.ps REFERENCE_FILENAME export-area-page_export-id.ps) +# EPS: Currently not supported. Feature request: https://gitlab.com/inkscape/inkscape/-/issues/1074 +#add_cli_test(export-area-page_export-id_eps PARAMETERS --export-area-page --export-id=MyStar INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-page_export-id.eps REFERENCE_FILENAME export-area-page_export-id.eps) +# EMF, WMF: Nont supported. + +# --export-area-drawing +add_cli_test(export-area-drawing_png PARAMETERS --export-area-drawing --export-type=png INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-drawing.png REFERENCE_FILENAME export-area-drawing_expected.png) +add_cli_test(export-area-drawing_svg PARAMETERS --export-area-drawing --export-type=svg INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-drawing.svg REFERENCE_FILENAME export-area-drawing_expected.svg) +add_cli_test(export-area-drawing_pdf PARAMETERS --export-area-drawing --export-type=pdf INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-drawing.pdf REFERENCE_FILENAME export-area-drawing_expected.pdf) +add_cli_test(export-area-drawing_ps PARAMETERS --export-area-drawing --export-type=ps INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-drawing.ps REFERENCE_FILENAME export-area-drawing_expected.ps) +add_cli_test(export-area-drawing_eps PARAMETERS --export-area-drawing --export-type=eps INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-drawing.eps REFERENCE_FILENAME export-area-drawing_expected.eps) +# EMF, WMF: Currently not supported. Feature request: https://gitlab.com/inkscape/inkscape/-/issues/1056 +# add_cli_test(export-area-drawing_emf PARAMETERS --export-area-drawing --export-type=emf INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-drawing.emf REFERENCE_FILENAME export-area-drawing_expected.emf) +# add_cli_test(export-area-drawing_wmf PARAMETERS --export-area-drawing --export-type=wmf INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area-drawing.wmf REFERENCE_FILENAME export-area-drawing_expected.wmf) + +# --export-area=x0:y0:x1:y1 +add_cli_test(export-area_png PARAMETERS --export-area=150:150:350:300 --export-type=png INPUT_FILENAME areas.svg OUTPUT_FILENAME export-area.png REFERENCE_FILENAME export-area_expected.png) +# SVG, PDF, PS, EPS, EMF, WMF: Not supported. Feature request: https://gitlab.com/inkscape/inkscape/-/issues/678 + +# --export-area-snap +add_cli_test(export-area-snap_export-id PARAMETERS --export-id=rect_misaligned --export-area-snap --export-type=png INPUT_FILENAME pyramids.svg OUTPUT_FILENAME export-area-snap-id.png REFERENCE_FILENAME export-area-snap_expected.png) +add_cli_test(export-area-snap_export-area-drawing PARAMETERS --export-area-drawing --export-area-snap --export-type=png INPUT_FILENAME pyramids.svg OUTPUT_FILENAME export-area-snap-drawing.png REFERENCE_FILENAME export-area-snap_expected.png) +# SVG, PDF, PS, EPS, EMF, WMF: doesn't make sense + +# --export-dpi=DPI +add_cli_test(export-dpi_png PARAMETERS --export-dpi=12 --export-type=png INPUT_FILENAME filter.svg OUTPUT_FILENAME export-dpi.png REFERENCE_FILENAME export-dpi_expected.png) +# SVG: doesn't make sense +add_cli_test(export-dpi_pdf PARAMETERS --export-dpi=12 --export-type=pdf INPUT_FILENAME filter.svg OUTPUT_FILENAME export-dpi.pdf REFERENCE_FILENAME export-dpi_expected.pdf) +add_cli_test(export-dpi_ps PARAMETERS --export-dpi=12 --export-type=ps INPUT_FILENAME filter.svg OUTPUT_FILENAME export-dpi.ps REFERENCE_FILENAME export-dpi_expected.ps) +add_cli_test(export-dpi_eps PARAMETERS --export-dpi=12 --export-type=eps INPUT_FILENAME filter.svg OUTPUT_FILENAME export-dpi.eps REFERENCE_FILENAME export-dpi_expected.eps) +# EMF, WMF: doesn't make sense + +# --export-width=WIDTH / --export-height=HEIGHT +add_cli_test(export-width PARAMETERS --export-width=380 --export-type=png INPUT_FILENAME export_hints.svg OUTPUT_FILENAME export-width.png REFERENCE_FILENAME export-width_expected.png) +add_cli_test(export-width_export-dpi PARAMETERS --export-width=380 --export-dpi=300 --export-type=png INPUT_FILENAME export_hints.svg OUTPUT_FILENAME export-width2.png REFERENCE_FILENAME export-width_expected.png) +add_cli_test(export-width_export-use-hints PARAMETERS --export-width=380 --export-use-hints --export-id=rect1 --export-type=png INPUT_FILENAME export_hints.svg + PASS_FOR_OUTPUT "Area 10:10:90:70 exported to 380 x 285 pixels \\(456 dpi\\)" + EXPECTED_FILES "${CMAKE_CURRENT_SOURCE_DIR}/testcases/export_hints_rectangle.png") +add_cli_test(export-height PARAMETERS --export-height=40 --export-type=png INPUT_FILENAME export_hints.svg OUTPUT_FILENAME export-height.png REFERENCE_FILENAME export-height_expected.png) +add_cli_test(export-height_export-dpi PARAMETERS --export-height=40 --export-dpi=300 --export-type=png INPUT_FILENAME export_hints.svg OUTPUT_FILENAME export-height2.png REFERENCE_FILENAME export-height_expected.png) +add_cli_test(export-height_export-use-hints PARAMETERS --export-height=40 --export-use-hints --export-id=rect1 --export-type=png INPUT_FILENAME export_hints.svg + PASS_FOR_OUTPUT "Area 10:10:90:70 exported to 53 x 40 pixels \\(64 dpi\\)" + EXPECTED_FILES "${CMAKE_CURRENT_SOURCE_DIR}/testcases/export_hints_rectangle.png") +# SVG, PDF, PS, EPS, EMF, WMF: doesn't make sense + +# --export-margin=MARGIN +# There are many problems: +# - PNG, EPS, EMF, WMF: --export-margin is't supported. This affects all PNG, EPS, EMF, WMF tests below. Feature request: https://gitlab.com/inkscape/inkscape/-/issues/1142 +# - PDF: Defaults to margin in millimeters. This affects all mm based PDF tests below. Feature request: https://gitlab.com/inkscape/inkscape/-/issues/1142 +# - PS: Defaults to margin in pixels. This affects all px based OS tests below. Feature request: https://gitlab.com/inkscape/inkscape/-/issues/1142 +# - --export-id for PDF/PS/EPS is buggy: works as --export-id + --export-id-only should work. See: https://gitlab.com/inkscape/inkscape/-/issues/1173 +# - --export-margin + --export-area=x0:y0:x1:y1 is PNG only feature. +# - --export-margin + --export-use-hints is PNG only feature. +# There is no test for --export-margin + --export-area-page combination because it's equivalent to --export-margin + +## simple --export-margin (millimeter based) +# add_cli_test(export-margin_mm_png PARAMETERS --export-margin=50 --export-type=png INPUT_FILENAME square_mm.svg OUTPUT_FILENAME export-margin_mm.png REFERENCE_FILENAME export-margin_mm_expected.png ) +add_cli_test(export-margin_mm_svg PARAMETERS --export-margin=50 --export-type=svg INPUT_FILENAME square_mm.svg OUTPUT_FILENAME export-margin_mm.svg REFERENCE_FILENAME export-margin_mm_expected.svg ) +add_cli_test(export-margin_mm_pdf PARAMETERS --export-margin=50 --export-type=pdf INPUT_FILENAME square_mm.svg OUTPUT_FILENAME export-margin_mm.pdf REFERENCE_FILENAME export-margin_mm_expected.pdf ) +# add_cli_test(export-margin_mm_ps PARAMETERS --export-margin=50 --export-type=ps INPUT_FILENAME square_mm.svg OUTPUT_FILENAME export-margin_mm.ps REFERENCE_FILENAME export-margin_mm_expected.ps ) +# add_cli_test(export-margin_mm_eps PARAMETERS --export-margin=50 --export-type=eps INPUT_FILENAME square_mm.svg OUTPUT_FILENAME export-margin_mm.eps REFERENCE_FILENAME export-margin_mm_expected.eps ) +# add_cli_test(export-margin_mm_emf PARAMETERS --export-margin=50 --export-type=emf INPUT_FILENAME square_mm.svg OUTPUT_FILENAME export-margin_mm.emf REFERENCE_FILENAME export-margin_mm_expected.emf ) +# add_cli_test(export-margin_mm_wmf PARAMETERS --export-margin=50 --export-type=wmf INPUT_FILENAME square_mm.svg OUTPUT_FILENAME export-margin_mm.wmf REFERENCE_FILENAME export-margin_mm_expected.wmf ) + +## simple --export-margin (pixel based) +# add_cli_test(export-margin_px_png PARAMETERS --export-margin=50 --export-type=png INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_px.png REFERENCE_FILENAME export-margin_px_expected.png ) +add_cli_test(export-margin_px_svg PARAMETERS --export-margin=50 --export-type=svg INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_px.svg REFERENCE_FILENAME export-margin_px_expected.svg ) +# add_cli_test(export-margin_px_pdf PARAMETERS --export-margin=50 --export-type=pdf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_px.pdf REFERENCE_FILENAME export-margin_px_expected.pdf ) +add_cli_test(export-margin_px_ps PARAMETERS --export-margin=50 --export-type=ps INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_px.ps REFERENCE_FILENAME export-margin_px_expected.ps ) +# add_cli_test(export-margin_px_eps PARAMETERS --export-margin=50 --export-type=eps INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_px.eps REFERENCE_FILENAME export-margin_px_expected.eps ) +# add_cli_test(export-margin_px_emf PARAMETERS --export-margin=50 --export-type=emf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_px.emf REFERENCE_FILENAME export-margin_px_expected.emf ) +# add_cli_test(export-margin_px_wmf PARAMETERS --export-margin=50 --export-type=wmf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_px.wmf REFERENCE_FILENAME export-margin_px_expected.wmf ) + +## --export-margin + --export-id (pixel based) +# add_cli_test(export-margin_export-id_png PARAMETERS --export-margin=50 --export-id=square-red --export-type=png INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id.png REFERENCE_FILENAME export-margin_export-id_expected.png ) +add_cli_test(export-margin_export-id_svg PARAMETERS --export-margin=50 --export-id=square-red --export-type=svg INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id.svg REFERENCE_FILENAME export-margin_export-id_expected.svg ) +# add_cli_test(export-margin_export-id_pdf PARAMETERS --export-margin=50 --export-id=square-red --export-type=pdf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id.pdf REFERENCE_FILENAME export-margin_export-id_expected.pdf ) +# add_cli_test(export-margin_export-id_ps PARAMETERS --export-margin=50 --export-id=square-red --export-type=ps INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id.ps REFERENCE_FILENAME export-margin_export-id_expected.ps ) +# add_cli_test(export-margin_export-id_eps PARAMETERS --export-margin=50 --export-id=square-red --export-type=eps INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id.eps REFERENCE_FILENAME export-margin_export-id_expected.eps ) +# add_cli_test(export-margin_export-id_emf PARAMETERS --export-margin=50 --export-id=square-red --export-type=emf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id.emf REFERENCE_FILENAME export-margin_export-id_expected.emf ) +# add_cli_test(export-margin_export-id_wmf PARAMETERS --export-margin=50 --export-id=square-red --export-type=wmf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id.wmf REFERENCE_FILENAME export-margin_export-id_expected.wmf ) + +## --export-margin + --export-id + export-id-only (pixel based) +# add_cli_test(export-margin_export-id_export-id-only_png PARAMETERS --export-margin=50 --export-id=square-red --export-id-only --export-type=png INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id_export-id-only.png REFERENCE_FILENAME export-margin_export-id_export-id-only_expected.png ) +add_cli_test(export-margin_export-id_export-id-only_svg PARAMETERS --export-margin=50 --export-id=square-red --export-id-only --export-type=svg INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id_export-id-only.svg REFERENCE_FILENAME export-margin_export-id_export-id-only_expected.svg ) +# add_cli_test(export-margin_export-id_export-id-only_pdf PARAMETERS --export-margin=50 --export-id=square-red --export-id-only --export-type=pdf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id_export-id-only.pdf REFERENCE_FILENAME export-margin_export-id_export-id-only_expected.pdf ) +add_cli_test(export-margin_export-id_export-id-only_ps PARAMETERS --export-margin=50 --export-id=square-red --export-id-only --export-type=ps INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id_export-id-only.ps REFERENCE_FILENAME export-margin_export-id_export-id-only_expected.ps ) +# add_cli_test(export-margin_export-id_export-id-only_eps PARAMETERS --export-margin=50 --export-id=square-red --export-id-only --export-type=eps INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id_export-id-only.eps REFERENCE_FILENAME export-margin_export-id_export-id-only_expected.eps ) +# add_cli_test(export-margin_export-id_export-id-only_emf PARAMETERS --export-margin=50 --export-id=square-red --export-id-only --export-type=emf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id_export-id-only.emf REFERENCE_FILENAME export-margin_export-id_export-id-only_expected.emf ) +# add_cli_test(export-margin_export-id_export-id-only_wmf PARAMETERS --export-margin=50 --export-id=square-red --export-id-only --export-type=wmf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-id_export-id-only.wmf REFERENCE_FILENAME export-margin_export-id_export-id-only_expected.wmf ) + +## --export-margin + --export-area-drawing (pixel based) +# add_cli_test(export-margin_export-area-drawing_png PARAMETERS --export-margin=50 --export-area-drawing --export-type=png INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_drawing.png REFERENCE_FILENAME export-margin_drawing_expected.png ) +add_cli_test(export-margin_export-area-drawing_svg PARAMETERS --export-margin=50 --export-area-drawing --export-type=svg INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_drawing.svg REFERENCE_FILENAME export-margin_drawing_expected.svg ) +# add_cli_test(export-margin_export-area-drawing_pdf PARAMETERS --export-margin=50 --export-area-drawing --export-type=pdf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_drawing.pdf REFERENCE_FILENAME export-margin_drawing_expected.pdf ) +add_cli_test(export-margin_export-area-drawing_ps PARAMETERS --export-margin=50 --export-area-drawing --export-type=ps INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_drawing.ps REFERENCE_FILENAME export-margin_drawing_expected.ps ) +# add_cli_test(export-margin_export-area-drawing_eps PARAMETERS --export-margin=50 --export-area-drawing --export-type=eps INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_drawing.eps REFERENCE_FILENAME export-margin_drawing_expected.eps ) +# add_cli_test(export-margin_export-area-drawing_emf PARAMETERS --export-margin=50 --export-area-drawing --export-type=emf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_drawing.emf REFERENCE_FILENAME export-margin_drawing_expected.emf ) +# add_cli_test(export-margin_export-area-drawing_wmf PARAMETERS --export-margin=50 --export-area-drawing --export-type=wmf INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_drawing.wmf REFERENCE_FILENAME export-margin_drawing_expected.wmf ) + +## --export-margin + --export-area=x0:y0:x1:y1 (pixel based) +# add_cli_test(export-margin_export-area_png PARAMETERS --export-margin=50 --export-area=50:50:100:100 --export-type=png INPUT_FILENAME square_px.svg OUTPUT_FILENAME export-margin_export-area.png REFERENCE_FILENAME export-margin_export-area_expected.png ) + +## --export-margin + --export-use-hints (pixel based) +# add_cli_test(export-margin_export-use-hints_export-id PARAMETERS --export-margin=50 --export-use-hints --export-id=rect1 INPUT_FILENAME export_hints.svg PASS_FOR_OUTPUT "Area 10:10:90:70 exported to 203 x 177 pixels \\(123 dpi\\)" EXPECTED_FILES "${CMAKE_CURRENT_SOURCE_DIR}/testcases/export_hints_rectangle.png") + +## --export-margin (millimeter based, user units rescaled via viewBox) +# add_cli_test(export-margin_viewbox_png PARAMETERS --export-margin=50 --export-type=png INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox.png REFERENCE_FILENAME export-margin_mm_viewbox_page_expected.png ) +add_cli_test(export-margin_viewbox_svg PARAMETERS --export-margin=50 --export-type=svg INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox.svg REFERENCE_FILENAME export-margin_mm_viewbox_page_expected.svg ) +# add_cli_test(export-margin_viewbox_pdf PARAMETERS --export-margin=50 --export-type=pdf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox.pdf REFERENCE_FILENAME export-margin_mm_viewbox_page_expected.pdf ) +# add_cli_test(export-margin_viewbox_ps PARAMETERS --export-margin=50 --export-type=ps INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox.ps REFERENCE_FILENAME export-margin_mm_viewbox_page_expected.ps ) +# add_cli_test(export-margin_viewbox_eps PARAMETERS --export-margin=50 --export-type=eps INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox.eps REFERENCE_FILENAME export-margin_mm_viewbox_page_expected.eps ) +# add_cli_test(export-margin_viewbox_emf PARAMETERS --export-margin=50 --export-type=emf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox.emf REFERENCE_FILENAME export-margin_mm_viewbox_page_expected.emf ) +# add_cli_test(export-margin_viewbox_wmf PARAMETERS --export-margin=50 --export-type=wmf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox.wmf REFERENCE_FILENAME export-margin_mm_viewbox_page_expected.wmf ) + +## --export-margin + --export-area-drawing (millimeter based, user units rescaled via viewBox) +# add_cli_test(export-margin_viewbox_drawing_png PARAMETERS --export-margin=50 --export-area-drawing --export-type=png INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_drawing.png REFERENCE_FILENAME export-margin_mm_viewbox_drawing_expected.png ) +add_cli_test(export-margin_viewbox_drawing_svg PARAMETERS --export-margin=50 --export-area-drawing --export-type=svg INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_drawing.svg REFERENCE_FILENAME export-margin_mm_viewbox_drawing_expected.svg ) +# add_cli_test(export-margin_viewbox_drawing_pdf PARAMETERS --export-margin=50 --export-area-drawing --export-type=pdf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_drawing.pdf REFERENCE_FILENAME export-margin_mm_viewbox_drawing_expected.pdf ) +# add_cli_test(export-margin_viewbox_drawing_ps PARAMETERS --export-margin=50 --export-area-drawing --export-type=ps INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_drawing.ps REFERENCE_FILENAME export-margin_mm_viewbox_drawing_expected.ps ) +# add_cli_test(export-margin_viewbox_drawing_eps PARAMETERS --export-margin=50 --export-area-drawing --export-type=eps INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_drawing.eps REFERENCE_FILENAME export-margin_mm_viewbox_drawing_expected.eps ) +# add_cli_test(export-margin_viewbox_drawing_emf PARAMETERS --export-margin=50 --export-area-drawing --export-type=emf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_drawing.emf REFERENCE_FILENAME export-margin_mm_viewbox_drawing_expected.emf ) +# add_cli_test(export-margin_viewbox_drawing_wmf PARAMETERS --export-margin=50 --export-area-drawing --export-type=wmf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_drawing.wmf REFERENCE_FILENAME export-margin_mm_viewbox_drawing_expected.wmf ) + +## --export-margin + --export-id (millimeter based, user units rescaled via viewBox) +# add_cli_test(export-margin_viewbox_id_png PARAMETERS --export-margin=50 --export-id=square-red --export-type=png INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_id.png REFERENCE_FILENAME export-margin_mm_viewbox_id_expected.png ) +add_cli_test(export-margin_viewbox_id_svg PARAMETERS --export-margin=50 --export-id=square-red --export-type=svg INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_id.svg REFERENCE_FILENAME export-margin_mm_viewbox_id_expected.svg ) +# add_cli_test(export-margin_viewbox_id_pdf PARAMETERS --export-margin=50 --export-id=square-red --export-type=pdf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_id.pdf REFERENCE_FILENAME export-margin_mm_viewbox_id_expected.pdf ) +# add_cli_test(export-margin_viewbox_id_ps PARAMETERS --export-margin=50 --export-id=square-red --export-type=ps INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_id.ps REFERENCE_FILENAME export-margin_mm_viewbox_id_expected.ps ) +# add_cli_test(export-margin_viewbox_id_eps PARAMETERS --export-margin=50 --export-id=square-red --export-type=eps INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_id.eps REFERENCE_FILENAME export-margin_mm_viewbox_id_expected.eps ) +# add_cli_test(export-margin_viewbox_id_emf PARAMETERS --export-margin=50 --export-id=square-red --export-type=emf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_id.emf REFERENCE_FILENAME export-margin_mm_viewbox_id_expected.emf ) +# add_cli_test(export-margin_viewbox_id_wmf PARAMETERS --export-margin=50 --export-id=square-red --export-type=wmf INPUT_FILENAME square_mm_viewbox.svg OUTPUT_FILENAME export-margin_viewbox_id.wmf REFERENCE_FILENAME export-margin_mm_viewbox_id_expected.wmf ) + +# --export-id=OBJECT-ID[;OBJECT-ID]* + +# --export-id-only + +# --export-plain-svg +add_cli_test(export-plain-svg PARAMETERS --export-type=svg --export-plain-svg + INPUT_FILENAME shapes.svg OUTPUT_FILENAME shapes.svg REFERENCE_FILENAME shapes.svg + TEST_SCRIPT match_regex_fail.sh "shapes.svg" "inkscape:|sodipodi:") + +# --export-ps-level=LEVEL + +# --export-pdf-version=VERSION + +# --export-text-to-path +add_cli_test(export-text-to-path PARAMETERS --export-text-to-path + INPUT_FILENAME text.svg OUTPUT_FILENAME text.svg + TEST_SCRIPT match_regex_fail.sh "text.svg" "<text") + +# --export-latex +add_cli_test(export-latex PARAMETERS --export-type=pdf --export-latex + INPUT_FILENAME text.svg OUTPUT_FILENAME text.pdf + EXPECTED_FILES text.pdf text.pdf_tex + TEST_SCRIPT match_regex.sh "text.pdf_tex" "some text") + +# --export-ignore-filters + +# --export-use-hints +add_cli_test(export-use-hints_export-id PARAMETERS --export-use-hints --export-id=rect1 INPUT_FILENAME export_hints.svg + PASS_FOR_OUTPUT "Area 10:10:90:70 exported to 103 x 77 pixels \\(123 dpi\\)" + EXPECTED_FILES "${CMAKE_CURRENT_SOURCE_DIR}/testcases/export_hints_rectangle.png") +add_cli_test(export-use-hints_export-area-drawing PARAMETERS --export-use-hints --export-area-drawing INPUT_FILENAME export_hints.svg + PASS_FOR_OUTPUT "Area 10:10:180:70 exported to 197 x 69 pixels \\(111 dpi\\)" + EXPECTED_FILES "${CMAKE_CURRENT_SOURCE_DIR}/testcases/export_hints_drawing.png") + +# --export-background=COLOR + +# --export-background-opacity=VALUE + +# --query-id=OBJECT-ID[,OBJECT-ID]* + +# --query-all / --query-x / --query-y / --query-width / --query-height +string(CONCAT query_all_expected "rect1,10,10,80,80\n" + "rect2,110,20,80,70\n" + "rect3,210,30,80,60") +add_cli_test(query-all PARAMETERS --query-id=rect2 --query-all INPUT_FILENAME rects.svg PASS_FOR_OUTPUT ${query_all_expected}) +add_cli_test(query-x PARAMETERS --query-id=rect2 --query-x INPUT_FILENAME rects.svg PASS_FOR_OUTPUT 110) +add_cli_test(query-y PARAMETERS --query-id=rect2 --query-y INPUT_FILENAME rects.svg PASS_FOR_OUTPUT 20) +add_cli_test(query-width PARAMETERS --query-id=rect2 --query-width INPUT_FILENAME rects.svg PASS_FOR_OUTPUT 80) +add_cli_test(query-height PARAMETERS --query-id=rect2 --query-height INPUT_FILENAME rects.svg PASS_FOR_OUTPUT 70) + +# --vacuum-defs + +# --select=OBJECT-ID[,OBJECT-ID]* + +# --actions / --verbs +# (see below) + +# --action-list / --verb-list +add_cli_test(action-list PARAMETERS --action-list PASS_FOR_OUTPUT "file-new") +add_cli_test(verb-list PARAMETERS --verb-list PASS_FOR_OUTPUT "FileNew:") + +# --with-gui + +# --batch-process + +# --shell + + + +######################### +### actions and verbs ### +######################### + +# (TODO) + + + +########################### +### file format support ### +########################### + +# librevenge formats +if(WITH_LIBCDR) + # add_cli_test(import_cdr PARAMETERS --export-type=png # fails to open (regression in libcdr 1.6.0) + # INPUT_FILENAME librevenge_formats/corel_draw.cdr OUTPUT_FILENAME format_corel_draw.png + # REFERENCE_FILENAME librevenge_formats/corel_draw_expected.png) + add_cli_test(import_cdr2 PARAMETERS --export-type=png + INPUT_FILENAME librevenge_formats/corel_draw2.cdr OUTPUT_FILENAME format_corel_draw2.png + REFERENCE_FILENAME librevenge_formats/corel_draw2_expected.png) +endif() +if(WITH_LIBVISIO) + add_cli_test(import_vsd PARAMETERS --export-type=png + INPUT_FILENAME librevenge_formats/visio.vsd OUTPUT_FILENAME format_visio.vsd.png + REFERENCE_FILENAME librevenge_formats/visio.vsd_expected.png) + add_cli_test(import_vsdx PARAMETERS --export-type=png + INPUT_FILENAME librevenge_formats/visio.vsdx OUTPUT_FILENAME format_visio.vsdx.png + REFERENCE_FILENAME librevenge_formats/visio.vsdx_expected.png) +endif() +if(WITH_LIBWPG) + add_cli_test(import_wpg PARAMETERS --export-type=png + INPUT_FILENAME librevenge_formats/word_perfect.wpg OUTPUT_FILENAME format_word_perfect.png + REFERENCE_FILENAME librevenge_formats/word_perfect_expected.png) +endif() + + + +############################## +### advanced functionality ### +############################## + +# check whether INKSCAPE_DATADIR / INKSCAPE_PROFILE_DIR environment variables work +# TODO: INKSCAPE_PROFILE_DIR does not seem to be sanitized at all (i.e. is used verbatim by Inkscape) +set(fancy_dir "i_certainly_do_not_exist") +file(TO_NATIVE_PATH "${fancy_dir}/inkscape" expected_dir) +string(REPLACE "\\" "\\\\" expected_dir "${expected_dir}") +add_cli_test(inkscape_datadir PARAMETERS --system-data-directory + ENVIRONMENT INKSCAPE_DATADIR=${fancy_dir} + PASS_FOR_OUTPUT "${expected_dir}\n$") +add_cli_test(inkscape_profile_dir PARAMETERS --user-data-directory + ENVIRONMENT INKSCAPE_PROFILE_DIR=${fancy_dir}/inkscape + PASS_FOR_OUTPUT "${fancy_dir}/inkscape\n$") +add_cli_test(inkscape_profile_dir_handle_illegal + ENVIRONMENT INKSCAPE_PROFILE_DIR=invalid:dir + INPUT_FILENAME empty.svg OUTPUT_FILENAME empty.svg) + +# check if "systemLanguage" attribute is properly handled +add_cli_test(systemLanguage_en ENVIRONMENT LANGUAGE=en INPUT_FILENAME systemLanguage.svg + OUTPUT_FILENAME systemLanguage_en.png + REFERENCE_FILENAME systemLanguage_en.png) +add_cli_test(systemLanguage_fr ENVIRONMENT LANGUAGE=fr_FR INPUT_FILENAME systemLanguage.svg + OUTPUT_FILENAME systemLanguage_fr.png + REFERENCE_FILENAME systemLanguage_fr.png) +add_cli_test(systemLanguage_fr2 ENVIRONMENT LANGUAGE=fr_FR.UTF-8 INPUT_FILENAME systemLanguage.svg + OUTPUT_FILENAME systemLanguage_fr2.png + REFERENCE_FILENAME systemLanguage_fr.png) +add_cli_test(systemLanguage_de ENVIRONMENT LANGUAGE=de INPUT_FILENAME systemLanguage.svg + OUTPUT_FILENAME systemLanguage_de.png + REFERENCE_FILENAME systemLanguage_de.png) +add_cli_test(systemLanguage_de-CH ENVIRONMENT LANGUAGE=de_CH INPUT_FILENAME systemLanguage.svg + OUTPUT_FILENAME systemLanguage_de-CH.png + REFERENCE_FILENAME systemLanguage_de.png) +add_cli_test(systemLanguage_pt ENVIRONMENT LANGUAGE=pt INPUT_FILENAME systemLanguage.svg + OUTPUT_FILENAME systemLanguage_pt.png + REFERENCE_FILENAME systemLanguage_pt.png) +add_cli_test(systemLanguage_xy ENVIRONMENT LANGUAGE=xy INPUT_FILENAME systemLanguage.svg + OUTPUT_FILENAME systemLanguage_xy.png + REFERENCE_FILENAME systemLanguage_default.png) +add_cli_test(systemLanguage_fr_RDF ENVIRONMENT LANGUAGE=xy INPUT_FILENAME systemLanguage_RDF.svg + OUTPUT_FILENAME systemLanguage_fr_RDF.png + REFERENCE_FILENAME systemLanguage_fr.png) diff --git a/testfiles/cli_tests/check_output.sh b/testfiles/cli_tests/check_output.sh new file mode 100644 index 0000000..66baa73 --- /dev/null +++ b/testfiles/cli_tests/check_output.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later + +command -v convert >/dev/null 2>&1 || { echo >&2 "I require ImageMagick's 'convert' but it's not installed. Aborting."; exit 1; } +command -v compare >/dev/null 2>&1 || { echo >&2 "I require ImageMagick's 'compare' but it's not installed. Aborting."; exit 1; } + +OUTPUT_FILENAME=$1 +REFERENCE_FILENAME=$2 +EXPECTED_FILES=$3 +TEST_SCRIPT=$4 + +# check if expected files exist +for file in ${EXPECTED_FILES}; do + test -f "${file}" || { echo "Error: Expected file '${file}' not found."; exit 1; } +done + +# if reference file is given check if input files exist and continue with comparison +if [ -n "${REFERENCE_FILENAME}" ]; then + if [ ! -f "${OUTPUT_FILENAME}" ]; then + echo "Error: Test file '${OUTPUT_FILENAME}' not found." + exit 1 + fi + if [ ! -f "${REFERENCE_FILENAME}" ]; then + echo "Error: Reference file '${REFERENCE_FILENAME}' not found." + exit 1 + fi + + # convert testfile and reference file to PNG format + # - use internal MSVG delegate in SVG conversions for reproducibility reasons (avoid inkscape or rsvg delegates) + [ "${OUTPUT_FILENAME##*.}" = "svg" ] && delegate1=MSVG: + [ "${REFERENCE_FILENAME##*.}" = "svg" ] && delegate2=MSVG: + if ! convert ${delegate1}${OUTPUT_FILENAME} ${OUTPUT_FILENAME}.png; then + echo "Warning: Failed to convert test file '${OUTPUT_FILENAME}' to PNG format. Skipping comparison test." + exit 42 + fi + if ! convert ${delegate2}${REFERENCE_FILENAME} ${OUTPUT_FILENAME}_reference.png; then + echo "Warning: Failed to convert reference file '${REFERENCE_FILENAME}' to PNG format. Skipping comparison test." + exit 42 + fi + + # compare files + if ! compare -metric AE ${OUTPUT_FILENAME}.png ${OUTPUT_FILENAME}_reference.png ${OUTPUT_FILENAME}_compare.png; then + echo && echo "Error: Comparison failed." + exit 1 + fi +fi + +# if additional test file is specified, check existence and execute the command +if [ -n "${TEST_SCRIPT}" ]; then + script=${TEST_SCRIPT%%;*} + arguments=${TEST_SCRIPT#*;} + IFS_OLD=$IFS IFS=';' arguments_array=($arguments) IFS=$IFS_OLD + + if [ ! -f "${script}" ]; then + echo "Error: Additional test script file '${script}' not found." + exit 1 + fi + + if ! sh ${script} "${arguments_array[@]}"; then + echo "Error: Additional test script failed." + echo "Full call: sh ${script} $(printf "\"%s\" " "${arguments_array[@]}")" + exit 1 + fi +fi + +# cleanup +for file in ${OUTPUT_FILENAME}{,.png,_reference.png,_compare.png} ${EXPECTED_FILES}; do + rm -f ${file} +done diff --git a/testfiles/cli_tests/compare.sh b/testfiles/cli_tests/compare.sh new file mode 100644 index 0000000..e928da3 --- /dev/null +++ b/testfiles/cli_tests/compare.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later + +file1=$1 +file2=$2 + +test -f "${file1}" || { echo "compare.sh: First file '${file1}' not found."; exit 1; } +test -f "${file2}" || { echo "compare.sh: Second file '${file2}' not found."; exit 1; } + +if ! cmp "${file1}" "${file2}"; then + echo "compare.sh: Files '${file1}' and '${file2}' are not identical'." + exit 1 +fi diff --git a/testfiles/cli_tests/match_regex.sh b/testfiles/cli_tests/match_regex.sh new file mode 100644 index 0000000..24a6347 --- /dev/null +++ b/testfiles/cli_tests/match_regex.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later + +testfile=$1 +regex=$2 + +test -f "${testfile}" || { echo "match_regex.sh: testfile '${testfile}' not found."; exit 1; } +test -n "${regex}" || { echo "match_regex.sh: no regex to match spoecified."; exit 1; } + +if ! grep -E "${regex}" "${testfile}"; then + echo "match_regex.sh: regex '${regex}' does not match in testfile '${testfile}'." + exit 1 +fi diff --git a/testfiles/cli_tests/match_regex_fail.sh b/testfiles/cli_tests/match_regex_fail.sh new file mode 100644 index 0000000..b6abca8 --- /dev/null +++ b/testfiles/cli_tests/match_regex_fail.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later + +testfile=$1 +regex=$2 + +test -f "${testfile}" || { echo "match_regex.sh: testfile '${testfile}' not found."; exit 1; } +test -n "${regex}" || { echo "match_regex.sh: no regex to match spoecified."; exit 1; } + +if grep -E "${regex}" "${testfile}"; then + echo "match_regex.sh: regex '${regex}' matches in testfile '${testfile}'." + exit 1 +fi diff --git a/testfiles/cli_tests/testcases/areas.svg b/testfiles/cli_tests/testcases/areas.svg new file mode 100644 index 0000000..b07a5b5 --- /dev/null +++ b/testfiles/cli_tests/testcases/areas.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="120mm" height="105mm" version="1.1" viewBox="0 0 120 105" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns="http://www.w3.org/2000/svg"> + <rect x="15" y="15" width="50" height="30" rx="5" fill="royalblue" /> + <path id="MyStar" d="m100.96 68.703-20.799-1.1756-12.76 16.461-5.3089-20.138-19.604-7.0445 17.518-11.27 0.64404-20.815 16.136 13.172 20.002-5.8198-7.5458 19.411z" fill="red" stroke-width="1.5" stroke="purple" /> + <rect x="29" y="21" width="53" height="53" fill="yellow" fill-opacity="0.7" /> + <path d="M 56,69 A 18,18 0 0 1 38,87 18,18 0 0 1 20,69 18,18 0 0 1 38,51 18,18 0 0 1 56,69 Z" fill="green" stroke-width="1" stroke="black" /> + <rect id="MyRect" x="24.5" y="18.5" width="70" height="60" fill="none" inkscape:export-ydpi="600" inkscape:export-xdpi="600" inkscape:export-filename="export-use-hints.png" + /> +</svg> diff --git a/testfiles/cli_tests/testcases/empty.svg b/testfiles/cli_tests/testcases/empty.svg new file mode 100644 index 0000000..b1010c3 --- /dev/null +++ b/testfiles/cli_tests/testcases/empty.svg @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="100px"> +</svg> diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.emf b/testfiles/cli_tests/testcases/export-area-drawing_expected.emf Binary files differnew file mode 100644 index 0000000..5f64188 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-drawing_expected.emf diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.eps b/testfiles/cli_tests/testcases/export-area-drawing_expected.eps new file mode 100644 index 0000000..f225577 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-drawing_expected.eps @@ -0,0 +1,443 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Thu Feb 27 23:52:53 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%BoundingBox: 0 0 248 206 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 248 206 +%%EndPageSetup +q 0 0 248 206 rectclip +1 0 0 -1 0 206 cm q +0.254902 0.411765 0.882353 rg +14.172 0 m 127.559 0 l 135.41 0 141.73 6.32 141.73 14.172 c 141.73 70.867 + l 141.73 78.719 135.41 85.039 127.559 85.039 c 14.172 85.039 l 6.32 85.039 + 0 78.719 0 70.867 c 0 14.172 l 0 6.32 6.32 0 14.172 0 c h +14.172 0 m f +1 0 0 rg +243.668 152.23 m 184.707 148.898 l 148.539 195.559 l 133.488 138.473 l +77.918 118.504 l 127.578 86.559 l 129.402 27.555 l 175.141 64.895 l 231.84 + 48.395 l 210.449 103.418 l h +243.668 152.23 m f +0.501961 0 0.501961 rg +4.251969 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 1 0 0 cm +243.668 152.23 m 184.707 148.898 l 148.539 195.559 l 133.488 138.473 l +77.918 118.504 l 127.578 86.559 l 129.402 27.555 l 175.141 64.895 l 231.84 + 48.395 l 210.449 103.418 l h +243.668 152.23 m S Q +0 0.501961 0 rg +116.219 153.07 m 116.219 181.25 93.375 204.094 65.195 204.094 c 37.016 +204.094 14.172 181.25 14.172 153.07 c 14.172 124.891 37.016 102.047 65.195 + 102.047 c 93.375 102.047 116.219 124.891 116.219 153.07 c h +116.219 153.07 m f +0 g +2.834646 w +q 1 0 0 1 0 0 cm +116.219 153.07 m 116.219 181.25 93.375 204.094 65.195 204.094 c 37.016 +204.094 14.172 181.25 14.172 153.07 c 14.172 124.891 37.016 102.047 65.195 + 102.047 c 93.375 102.047 116.219 124.891 116.219 153.07 c h +116.219 153.07 m S Q +Q q +39 17 151 151 re W n +q +39 17 151 151 re W n +% Fallback Image: x=39 y=17 w=151 h=151 res=300ppi size=1190700 +[ 151.2 0 0 -151.2 39 168.2 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 630 + /Height 630 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 630 0 0 -630 0 630 ] +>> +cairo_image + Gb"0WGFVoNIH^]DMs@>:hKuG,0.X(r,f,<D":W*XK,nD0\,\G>]L#qUH]rg8Q\:I]joW(", + UT5GOfW;#Y*)i!>1t<?OgJ;oZn#j7[<;+'RY=2/m*%TT3Tkb7bia8bs1$/s0@o^<pTmA2k' + OD+/BWFIk]aa_D"kaT!0Cru<WE'#>E8h,\<brKfOp8ZGO/`<82]"7f&+'H&b&%#Ka!R\-nI + JJ@0*/\$4G0V=9'e0_SS)C(-kKeYj`'T"d%.\/3H:.!MhOZ$dVXO!%EoE_D;lA5Y@fUn-k! + SOO>O.4@<NXUbiDdcVR^D.?23]1DCTi8u&W[%#"kHdO6Y/6X^"k1^XW::fm]HNP`Og'G`r+ + UTj4rKa!Rd-nIJJ@0*/\$4G0V=9'e0_SS)C(-kKeYj`'T"d%.\/3H:.!MhOZ$dVXO!%EoE_ + D;lAJ2M\6XUtLM&k-6f)%$beR`"SVj:M>G&jg$c)%$beRNlaq3MXV8gH@>\(UFekStW@gX? + $.>Co=LtPM<#'4hP%tkD9FtKkDeb!,IV_T%-_@a8<&7bW2mqr'uX$_SS)C(4\9_G0atVltr + 63+5F1fr249KKnX.f/-'IGmJ?4e7NHbiNqa.9"ptaa:fm_K*.NCV]nLU!fK!g;d=C*N6t,$ + l$4FY<j0)7nDdaZa[SG\'BUSWkGV9C3cVR^Dei;9]%k=[@o]?JWEu'W4OE[D&n-k!S@*Qe6 + ;qi^:MkI2JTWmnoK`tl/amE#9(=mJQf8MkDq,is"_D;lAJ2O75`DtRS8r>%u=\1nfi>Dt1^ + m\2+-c]BBi2i`IYj`'T"^oUP>:.?sfTqd:L\ArYrL#)c4@<NX=EF>H":H/kFSG,bE^)@6Kk + Deb!,G>JSmYCI?`g+`OtH5\;cn:!_?-t(bbjoBKtY0_@`tR;K*!PP-nIJJ@0'J?SC\OS2iU + &+DkYKA1PLNq-nG?[p)IAsZEPp.?:dFki>Dt1^lH)uZE4i7N5$kl-nIJJ@0,#cp[E3-Klrp + @k0lp0$4G0V=9*O241*4@@F%>C;XE;Uf]sWK_SS)C(4[Dc#;$bc[S>cm^$"cT$470e:fm^@ + j;_9:^T^SUG0f_s,mB!VB.,;248/,Mi_a,)-['aBP(LQf1DCUT*W'mnHWSiU^KO46eG>5#@ + Gr(2$c%c)q\FH\fJC!<;G9'SfCDN@$4G0V=9*M(mIRon/WRJ$a5W.S@Gr(2$c%dTHPZBT=N + Bs`Xf\ClYj`'T"^oBEpZD?R=N@CXPP6*'n>$$k$dVXO!-T?.GFkF\Fe%<)@3l)2KkDeb!': + \(qiK-X]ku5CVsJ;MC^LQr:fm^@*.DP'5[gGCXJDMnn-k!S@)nD=k"$6<EH:qUZ]u4=(7q5 + (!:2Zp>$/iB>:/JP=H_m/9juuu$4FY0UMnGD/aSnh8rA6-Y,%_pn-k!S@)oP.ZOE:I;%Knf + fctF]NW7%rYj`'T"^oBU2eEuXYYf%>f3S"?(qYnn^2nUj.k)kt4@<NXfPu;j%"f6Pl&8hMe + `dQtHDKB<`jq7a_SS)C(4[FG?_;5__2(j-$L;Y/>G?o*NU5oS'DCV-=@keei>Dt1^lB'iV\ + qnleuoJIE,&U[qq6tqR8)]P^[k8@5;n4LB.,;24&5.0RV;\@p"7j.[]7d3Sc?CZc5t_'F3h + ,gIk46$i>Dt1^lFW5V^*1p4?_i`_E)FSVgLY]DIairP(LQf1DCUT*N-=l>Z`AKpFWJA;.g[ + /@<NlBhj"li(7q5(!:2\QF`O4u/'t%4<7pETZK^QF+M3b!ZYB?R4U^]UYph4d6X^#JEGE[m + 7!j,YO(b;m/[";DQ6WHN*I2Eql]4bKi>Dt1^lJ.rS![mRcKX:B$gXbB=k6YPSCfi=Dfd9/K + nX.f/-%b,Dk<&(k)/f8GREce8rBa[=&MjsG_X':YiGAQnVK0,=:^CtYhlLX\6Q=EH4D0&;- + 3gA(^/,5B)I@"=\3U9pTY[jgeHh4jtDl=`CNT8(4ZR8Nik(7>H&[6:gq%A8TE_9m,fYo\eo + Tf=9'-'2(Iqr4ij;#/Lr7WCp0W_IV3t*h)aegN+>7`!EcT#8@Ch60'WILL%T+*7DY!U2_.s + %O(BRG$4FY$I>=+-'Wk('2_Jpia0O8<i1@Q+r3_]adZYQjJ\hJm@,IYh#!';kqme.l$SPOY + Pb4=e.j@0L&U"j(J-@q<Q^WS$pN9iq>LA]Mq6j@&PjFsgeA0,1E.c"/YTW,E&qc'AkWW#Sl + _rG&cfu*c,?qZnErD!JdSh(C7:?4!Y^c[^K7mOX]keG7dB(eiojGCoc.b"I\h%'3:a;ba/- + $(Ok:ACPf2^YU@UZ$68V,fmYQ-46Y]$4$]IJ%7gP*?.]'a<_-,i/N;BSgN(4ZPnpF\/@<gE + +@7:C+'T+k+p8(il<d9G'<C=bueD1i1K"^o0_4nB,OF\R)OW3EbD=\4ajI:DToLSa/l_LfW + +Yi*lTo*g4n?$GtEYd_8L8Q!]($H.S6!jLV0]-`66eleR[[RKg[!B)1g-p'JVPn]%._?-t" + n2h-uFK.fSp7\^NRbK>A/3bSVFRRH9#4?n+)^m6;$]_k_f-!u!\s#@4FYr<*p/b/)5.UYR. + k0s1'Gc3&8)B\E:oKkpUMkk"'jXCN?4X=\ft8mMDHpF!4in:0'Gc3&8)KhROJb.q_9^!,W6 + i6F7b1FcC7b&O7fZCg!#?R14j+sA%D'7QKtS4,8Wh%c$@%TJ!jLV8)`%r'e>P/l$@=;7P+k + d6Zl@\>Dbb/J@3l(\;-3f6*8<?g+A#9g6`R@#kJ+]4&%*A0r,!*_.p,Ao().O7"ijuBDU>. + jSM"$s>LA]MA_'p\C`6Z+G-U[U7hAL!!#?R33R&[9:>fXjgEO4l_XbaQXJ>iM"^o<+*@?IT + DelCWh9#LcMW/iX2qG*r*qBk1@0'JLEr4?S"-f_(LkkXu%D(@UlROE-:;0l=;L6VU$AAXk_ + 9$Om'!749bpZoK]<IG"<`)s!(7a)>3RRI5kY^>2]rrrtQef`SM6<Y16oIRHI/&Z;!jLV4Q: + VD_%B:Hu*n(@NY+unE2mVUfAi2NQOs6`!=9',Ls4YCZMfVp[&2.`:=@iPF-nG?+:2c_cBPr + _"E:JmqX\!/ikTP*oS%ifLc/f\gP99dsYQ-46]d_pW(@,Dg%?2g2dk9m6FsEKgC&HNZ7FK' + q5+o+[/3'tMI%m<S/e>o')CLSH;FHtapF3XM=9*7+3OZdI0r93#GWOmJd7T:n\olF9J9NCm + !4VYA2(@m;4\35T$#.nW7=(?Wa;4-0<*-J"3X"pXKa$DchBU\XEOi"QMFTI"&J%o?jDH#g] + l]Za$fD0q$c&mXLR/sEV+_C20;]Uf;BS.;(4]Wd%P9JMasGk>]TpL:FdD]c'W(\=ZB?EB:f + m^8jW%N?En.&aMMKUh031sbm[@C1A$pCp?jhYli)\-S,mH6;XS[fTdNpPI;WM\c^e0Jp6"' + f([=A3cK9T@!hVsB60;?pc?PVosQB`0+K#.S.COaVRK8s3a]u9e]M\dlm/f^>9gr.7=TgiG + k\922O8RX,l:[p2DjN1#OG?@EKC(qG6>6jmT1rtGnh'\d_]0'7gEO0\^F=CUP_?+]Bi1:)V + mC9%*M)WhnLebR\#M>#PmcO&k8sW)i!X:&(!4NHO2r>_tf6(0b+F:tiPnYV.h27"9!st[*! + 8KX-mQ?,4gsB?F;s55T<`51KS^Gs&a0HjT@0*l\pmm0KH;UHD`&m1^HJSS%*aq"5XJ?+:$4 + FYO,B(mcLdeH6/07*\21)Tk@`sGiZ>AcK+<D44J6PP#RU]0OS%>A>!I_dVMNgP<!P!:Ec.N + ;hW7)c_gZP3p\uYdp'F.c4&TAF"J6PNfcS>bo]l#JE5!M'Zlih^"h8gAF26EQqNH@\[+;>T + A>K:p51oNcoDC8aRT<XP'`DBY:DB7JC;HP;*ilUea=">_W=\02j'Gc4'a'YHId"Q)&0&AZ= + d3f+MN3&f@kZh.d":Ttfi7@GMV]->d\XF0bSY0_gQ#D!q7HrZsbmiJ*'H@f&J6OCE:,BtBG + iQ_"k]YNY;OlQ#V>`M+.0>+<!c[JdNi@ki+BOU=%pTZ&lh'dpYhdC_D4,A'ic=:n?mC@/i8 + 2TC;\H2t^)eM*\)=43^$S;?;/p3!FC.:A!P!8e>Jc(Gd%eRl(+@dWf0!)3,T@'u^o^O>-RU + tQ$h['\W!,ndmSISD-,mDRV`*,/Pn$O2U9FXQH@O,V6mr";4[Qep!S!o$MY0fXOj2cAZ*rY + #l.2XW$4FYOe#t'&fQ2AKGg:miU=77I=@l@iZpZr6.>YhBE9m/Y$&Qt*,!AW4AO.);8R_F) + =]SEs=9,%9B%-NCVgYfk.UKB1X3mL0ok:t"/_MqTWICC[G>\[""lP]_W%Z\R`=j#7?EBqNg + c>1B'i,10YQ.!tcd<I3F8ifn,i5_$Lp!NjA2gfqUnFpl6=K>FCkEm\5n=Zj=,:,/^$J5>;1 + <7d,dK_I6-5,'!cV`>iT1:(rLt>USulsgY,&<"Uk&%sZ^Mh98O6bc"Ot.Qb7&!0RI2`bXO) + g,U_mf)ZKL)7g/,+F\jXYt_?+[&kFbCTbB71^@"hIAc7%(-lp`m_gVfQ(/#6[>PUJ'_=)nd + %243ZqFW^-WKiCI<?./]<7Q,J>poF4KUjJ>R-nG@"p?u?t0[_InDt-e\RR\kW,0ep?6t$*! + `VuCH#/g@rmNipRYcH<FXKSEJIWp*:*@iQe/:]uFY]#Z?,ep@+MAI`K2!W:/4j7eS$[,4DX + '-h*VW:!N!P!/Xmm;X]?E&:-k:&E9Z'$;ToD%XJbG=`o"=Pf$<t=Y$?nfL!FEd75,nj<W"; + 6Cli6%bfjr7"_laj-AQ'+hKcEb0IU3,9d<`2ar!)a<?43q;Vhp>ZIPE^I-=@mN+N@FNZ<_K + >?UaRbo<t;q@OMT^q0"AiHPa&g_8WgK)!\5]J/-,\jIV5h"d&tce`FG.6,!,+smUJ2]XJDM + n!;q'%XZ6S!]2j+g02Zc]@O9!I6aN8OpfNj!!q=</UVbUH%cRpiHHr]K"kHaQ]Yd>K$4FWs + 8)KhR0W=;[Hgq*4!fpA[goOa0*Nr;4YQ.og[X4=VP]"k8`9WU2,!,+c*agq4\XUWH.p4@XY + Mc1[!*hPX`_;!sm9EkPV^J<cZBF4c]NZ!<M?OlO"lRPn>r)nDF-Fl\O%u_F@O4IbhAK#sHn + 7p!!I3W!ldH:iF$up_(FKC:lh4ua#eQ3NgbkLb'GM=5(Ja=eAh]Nh;-5!5XJFK(Tt2dZ3bJ + I]@0*lY@`Qtd#BHsg.it//`_$RF$QoRIDP**]-'')lSJ\<k\uYLh'Gh;)@3l)2"^oNqD$_" + :?]Puk$QM*J`r\EHDIe[^Rat<I7QPAe6"'f(Ebaq$7#/!&e]$R#(1+)<aPT1dp?KQDFUJ6X + $c&$+>:(XWJ^<TniakD+Y?"O8Z]]pW!c[9"f-Vh*Ia@9;i`X*'.WnP!O`cm/SX\=`.4?_I= + &*\*OQbUSd_j"UJpZ&3XF/bQ.8'?[Ci2esH_2];!*;p6)P?6C/_3;.CP)Fud-[p<Uc>u%9) + \G4>Y.4i!OuSmE_H$9nW_rtRWWqU*c*d@[oZI48thLa9b$EkT3nH[ql^\LJ?_7-=.&p1TcP + cA&[][Z8d\)-R0DU;o2J*%R``Ld-$s7bDSH&c4+Gr^b7k_BZ+WV\]q>U%(Bh!Kf3RuaYGA[ + IE-@DHUi?<QC+c\<5;B?LkM8)I;cj$;logMK0P3!'!TNo?4R.$D6JF">cFl6GZ$*6o)-q88 + =0%4ES3J\XDp&7OoV8Vjgt6ga\\X4Ve,@8?JN,OON++s"DIi@J9rtH&iC]!K`nDpRQ_0^jm + ]F!BEDos>DX9Hlb[A4mdf%,%JbVZU>+#UG.@b0=q.RdAZ#8s:P,3#&Y#8@%f&[lVC+rr:F^ + OZR+Al.M]CdNT"El([,dO,HC=Ul47E+_a4T:_b!cTgU^_2:A;ka)EpAtP6Ff0UMg2:GlKK0 + j*i^n"7gp$dtL#l)($aqFq$^AL0Y\X:<`<MOhMXDc3$^gHn,t6eYP@[fn3</Bkj_Do/).tk + \r9'fY!8Q5!ZcHPF>h)!V9*&PI3rQ]4A2gf>>:/.8\D5]ZeR*gLVJp1b%u6m`!.8`nha2t; + ;lP,"B*'\kdClV/WVk8Y87[@N@K"`cCiX-q/;<R-Ka$DS_7^3b-;Top/fk;.kK->R"1'4HQ + 6R>_hJi@4p!gWq]AraR%>=rs":+\F2jc_ZF>r_N^l%>JMNN)"FRIDQcBY:(YVt%61]*IIK` + r"jLYeM50R91(+7V2'Q6r/"ik\4okGluVXHAKb<N@Up/;S?r"GI!j=GP`j.;ZE;'(5lQMWh + E?\t@e@j_bud21JK9Q`KfFDHp:mnaN']XYQ6D'Gc4ALYmBu@.Mh2cJh]OFWRZ\Lbq?cA(fF + Og#OLZOCAP)+Q/9m4kF*4eETfg3Iho.>"R+@\*c2a/N%CD0$CuB'OliOV%==V5[YUXCQ?6l + \Z%ZJ[f@I`d-]-CiHA."Y]E_8V<ls'X7$5aEg=KCYjU_EZOJ6WSaIUA!dMbDPn[[!ceUfS@ + 0%3,\pKaZjD!!.`@Cql<Tr<!NUpMK*om0A;5Ll`lHEJg'nlg!m+<75%AqM>i?LMciI`)\Mc + 1VclM9A>*a,ZCf'(BkSbAO;!=B4MKk%`,(lY4:SKU2pi=@SB;?TCj*`oFu?I?IO*ct`iKa$ + DOn^gL,T%U3o`@!lt'4"0a6p-:6jQk20omlA>C[@BBKa$DOnX\,;B%1bt9c?o[o5FQ4mNWc + C2i@73$JkT1Q`KjL@0*lW@Y[N``<SRpGd3FK;pOLi"[2?V[k/Kq,?%\E/tC^gnFkHr4[shK + 6])[1.BGV37lXT*GMfi>JAMA,iT.Er#1j%<Euoq'lbOc.9K]*Er8KZD<"Cn%>eMct$c%Hp> + :1dZapRbhnKAEGcF)U74]&ek/XNO4q3I!l'Gc3,Vm[k`)n&S('VFk#Jh+F!86'a(fFg?cq/ + <J2HLhGs"lR8pY>$j`C(R$)#`*5djkEB7k?#8Nh*8&\g"8W"!P!)pF2EV_d_j$/4+bA\OE> + s9nh.!jhm0M@_?+]8oVR9`G[7D+M,/6sMY35K/`3kEVRm0'2PI>T>W@rBUVr[*.R)8m4;Ls + q[!^%D5YiK!YQ.Aa3OZe4%$p1pntQ_HFBs)`F<sAI*b54S2RZFa!2fH02(@m;4\1%o+fK;D + :'GrCbZ@[#m:Y,EoBKO<[SU'+VY2(Q2CRo\4]$V"+i#/+P+q&B2O1jdUM_IY6cOhs!\h%Vn + 8a/uQK\G@UCY3'>a\pJ"'R?ZrVi+B/JJtNWI9Pf)&2e-mO(6q&-b(8(XJF7G`'?>0U6]uWB + jt9F^Osl#P`hd!\fm\@#70X0C(gmUCZhpK`tk!s8KtAKrr_8j[UEN!t#FOeG^GO_HtX'j@: + <M!t#FOe:E%+$jp4<HchC5^]tPhJ>n0J(E+!r8p?UDI=MhV/-&TRpFJ!Hlo!TnIe3Y)TWeD + i*I;Y<6"-t_Y4A=un,\4H@-Z+No*btQ6[+Y7I=MhV/-&V(hg*;9YVeI7Ie3Y)TWeDi*I3"7 + 6"+POBDKp[pjg3_0QlHY3<k2NWB87`5/7C;(4`BZDpC6hCn9u:5Pb@%:fm^pNp`KM:tT_O/ + HpqPK`tlLf^>.3Kl%+=j0JcQ-nG?sa**jb[S^\[O$:>a'Gc4uj0-c_-u?4bQQLX+%k&t/;o + `7;DG\uA:6QcJJ.F%Z!)k7g:,=<"r7hDP6"'e]3k8a8U3Y#6A*)kpi"$/&^spKn;\CZu^)e + L`pAf\>=9,3nD+hCC"a[QRg]RI?@0)`V[<6MaKe:e!jl[]C%gi][eGEGs-<f'.HA)4O"8kG + n!LPqH>/GtVVh`IA4hr-R(4`C5RjTIbfHNIPIdR79TWeDiS_5h`dD?[bU%378n-=XN?n0R: + 3_K'Qq7-b*K>I[DZKLEYK>O53KB22:i"$/&^rY@Wf`m/DTEiWc4hr-R(4_O\LR/qop7`TN5 + PG/-:fm]ep)R=K:tRPZ?[hDDrh-IqN8ts8.;ZQ_.mNb.Io'5I7WJti2(7g&h+)q^!WJar!0 + $:%^VleL'tUmPg]RI?@0%4uT<m1CYZGp"q7-b*K>I[DEa[cKK>LsF4ltiJi"$/&^rV)?$Om + GIWI)_44hr-R(4_O"HPRG4[Rtb1T6l)Q-nG?CLYeM=:tY*FX8L`Tr'=`l(ch6V4G1N-cs>_ + q*oIP9$c'iWG98RgCphQOT6l)Q-nG?CLYnM8:tQ]B=aoc>rh-IqN#[+YN^7)hFXR!q#P`qg + !\eZEW3CEUKDaL,r'=`l(chHTCkKUUlh9mj&+BgX"^pEDmTBaJD:%\2k8rOl$4FYjYr?85' + XgkOb0N5d*u#K@OlO&c(_jDMB?8C^^`O7+J<Alq:H'\<7&S5S4hr-R(4_M\4/Wr1p6JI;T6 + l)Q-nG?C-[&0X1p=H9XSgEIHp_<C(cf-T8tq$adpqHo*oItE$c'j*D$_":?]UKpH@To^/-$ + om[SBT)YQ]?;r6POn6X^!43ONErU4kb28&u3(^c)rCJ<BS5S![ktcfsEZ6P&YqK`tlFo]?I + :(:HaEP95+$D^[.:,H!J[:UI@FHDpbg"+3IE!>nBbYDs5Y7"4>#^7hb2'"@&f$A63]lG<$Y + &+C$^"d$7-7YSOK#K[K>^c)rC5iVJYaYkR676NnbkQ/DkYQ,<Fp[E3U_NsHcnj<rW%>=tI\ + :'-u)&2e-mO(6k!8gUT!/\lZ\C@1UjgqYnci\Y_@0%W+kJ.^__H,kanj<rW%>=tI\Gc:@)\ + i"'mNk*i!8gUT!/]I&ZcJfD=*7=7Ta1@I_?*9`JUIn8$<sKVa:CGL2\[#miXYB^?r5K*h-G + Kn!PY83!"sKpc[:A^?IR`kLE>@m$4@trLYag9luh,aIcpgHl)t$^hl\s<mQ^:N8ll*[4Rru + O'Xh1XaU^PM2r3#d?_&^VDJ]N,G[/KP\X0fqGEs=sJ8ZheJ-8l=AJa^#A5Lo^h+<(Z!PY83 + !92R/\*h+af`l;1EDq(G+*rHU-nKoD>UrsG^MT]b?6+1"KDa'uHp_<C`6qJgVI\!]2f3EZT + \IX#4hruj(-if_[r6$(HYnB3]K-sRVYndCHp_<C4@%`1<CLh%ZdRD?9fbXjkQ/DkYQ4+=gp + FfTb_"Wpj"9EDdB(gYLE>@m$4Ge$eR!Orll/mi[^AOlVo]H4^c)rC^ooUSXtN!o06`WA9@m + 58'+aRGK`r$1j5TY-mB40^e$_A%7Xj=tI\O&3b%n"]GOb/Bn(R%dVh`m/D??el_?-^]r>pg + (jm'*PFK\nr!fIa\@=_BhCQCk&MY5>B[S.fT;-4qE75e0^0$\miX#laiq0G`"mOg``!'q;7 + 828]i8DL7F%q^5'5[f5n&S^+[`?'jt($JLRFBA:["p=s\"]BtsHR)d#e-"?]#lFm\"d5G.H + R'SbH=W$'/3hL35bYDI;S,f7]Q!%En(O52a-Gt>X@!-YK>I[]MEMT&0FA15UDk#8ZUY'.7U + ^l/dSR9IFRMn!04!6U!Q9]/!_FWJ7j;lp"Rk'e*XNqi'Ga4Hm#_8LLVa*9kK=p'dF[%r!@3 + Q>!b'(i#p?`+/.bSCOT9un_?(l[I4<p;4VI#M1C=C@$4DNE5C4YnZ:=t8O2:tWiPQ^n$Jh0 + dLk$K[('k$98-%U9@=_gE6oJ!Z/b*qD6lp\#!&%/N+Md9GY@`gu&69J\#c>\_X8.\+,6<H7 + Ka!'`4VC"8TWg\CYX\ac*Y]@q%/*3l8VP"_!ROrXQ9>jGZD"LQ2"jH?abdk9EnDT;,Voc88 + FU8Q7&B<#5@f;/7:?5SYt"jd#o"0EP:q8.Y3BipZNU>_"oNE4lH41[Vg<[RarUj35U\2A^# + l3bjep`U!MgP>$[@Un&jV>KY^gAT)qL>rSa5NI$aW>)#VHGlG_8-l5cUT`J8G`QCJ+<GnFY + .o4VC!c:ftLSp.,2Y%13JF;La+;nN52_]l[hH":umo(3%Us4VISWOT7_'_?00#YXd])*loB + /+FGRg@#@)[!89bJ!@(q>O`6QLrlsel!5aZ2!XW=s"G"!Y=<J4BOT5qG$4FeMn`JQsqe(2# + l,k%R+K81>+:db#!0AlA$abaR&c`>;=PuKt,6>Rh$4GW"HR&U$7:Cc)`Z>EdG#6gn)B(M=] + XXu7@)[s9b75Loin1YS_2]Q-[r.c2lDq635PicdJ,"e5NdpuIBeB@S?i4Ano,hr<fsAcqcQ + >9Z`;)V^GOFE/2qEldj.L6HjXU[]:@e&*Ps#aFW^uNo2E,P&.9ZK?gC&N-e(NXUhUFdioC: + -h1\.fkL9+b>Dr/,JUITOreh'g'4WQSZ%iWr;lI;u[QhULXh]MXHcOPHp`NfI?Io$'1J!mQ + eo0Z9kCMMFWs08@Hp.,1f/7f08p$*IYEmhM6r78>(54QRqN>qc@T%uO[/&Q6iXdktGgGqLQ + UQ5n4qWX-f:[@r&c;2aYYGZd#,B6l\@?1PQ>*?7sV55]OCmk%bDbp;p7gDhZeu`H&FQmVQ4 + _\VFaH2Etf(=CY\^CHGs33ZHA8-JjHLX5_,etH-!+&6S_E+eZEFRU^IPg)=(IgJ&Vu?L:OR + Aea-SmPqe>U[<5OZcKO)qIFSNhZr7/l(4\?JI)J;6Hqf^n9-3a$b)l&gl>okN)29fdKL38M + /WY$BZ#$1<foo5ELH$F_SreS@e6S)NV..siOl<#;.C2E#I*^OO@L^,,RP*uZt\E(B/]"oWQ + 0R-sn?nbi!RJ,.9uQS5NXs48&0m#_;+O'id4WG08A4c>hgZL$r7_7V9I/8)hQ/rr4\oZ'1f + =](=0[B7.=Yh+4I0'WK(OT9?)+:DC[^A?A]B0Yq)YQ4i(iY,<V:O7?@m+L3%G[^6)*V13h2 + i.LGp'l?o!;J-"Klo"L%ie^BX`$p=[&B<i!U1/l`9H*irM,D`r.fchG5hD3nH+#o4V@_t8/ + J_GHJMAG1<Z*W4aOK!%Sl:1k?"*4F*`5o)roe)J%9e5mIFhL`!H'-!4WQ5_VVr9rkJJ[mUM + :el-dQAdNjjr1MKb=QX:eXqK+Kgp;VgJ"ku2QFCgL9J@>5W==:17s7r/qIs=dL_O@/t=/Ga + B2+":!8ki?$G18lO/WO#.eB4^#7'6F\s0s?Ns1@dPs7tp,s4aeN%9BL,;BbjPH.K(bhu<>f + _SR&ITet+m];B]-9M[<IfcpM?#%%_ld'1?s@f=s"#$YI+lh4jXX68P^O](M0H:4`n.J5&\4 + epM.P^:;)?W65mV4LTMO-TRZBUuK#Ua\/nWF!uX#O+AC:liBfX%=T`iV9K4'%p*,G-Udg,^ + RPHGl\&<a+_d_c$oZfdIKqrS7W4d?AC.hQLp64Fo/2*%<^]BV7rVP-^FO9[(J2i(XZBOs%! + bc)&[/SfD#0qcfR4%08X?660bLP(V_obdn<d98-"I42heB7>Q<uhZWF<rP9tENE$qK:.5`a + sW@*pV8NN;@]V*d7dD(U2*W;lL\i"<>J.=6F0KLj?>J-lK-*m&5mR",O86jbPjkmBE_SUJ) + :S(hbbVLJjpMTHoh!Z2qelrshHe0(0;s9:G8$Bl2+SqMp.&Hk?,BnT\>-XgJ:OY(Bq/&_dY + ;`L_(;2TMdnA:#H6@P[!$oQ^@;k"-s+;Ce?b!><Ij7-UWSu77HpjssV.1;E:2iE2r>fC*;V + _u]PB;#=hkn-WKi(bB*rE?8,"qp;$6XFq(\[F]e_g/A\:4C(q4ol@W<l2!<pEW2RtY1bK7- + %bhiHXf4M\McN8r78h+:C<qnNI5n(tancb.h04C#C3ZDX%lm#_9Uc:)15o2e'QoZ5=K4hgM + F?)^-;CXpJ#[fF*n`&ZHEO%)@ImFoQ%[%0!oB(mDGBSP.9(n2GpYt"j\cl!Sl^k!em4Z4Q1 + _ok]JXQZ!a5+")IWqtc;k^?egUS$:eq4#cf&Y6]0Xbi=.CV7`(F]in(%e`En#eWP4gXNUhe + Q6D0S(GQqd6(C-LSLIhEk1JCkG*5m9on.TmEOnCUYQ;2N%Q]ip-m]4\om31cgp_V[7Cg<Ns + #GEi[_+ZefXm1`otg@]pco-PZeb!kjT>^mVC3'#Wo$Yk+TESgS[:+`3A7\LL'&MWb@70HR- + U;dCjF;kmG4l=G:U0^4"fuIXDr-L2UFqQ7MW@dYU8JQ_HEN:\SD'@nUIZY%R^e,LK9cr<OO + 64LhVXaN"8VY;oOYG]7`JJEU>D5:mli4NNH.?&hkM0=C#n.H?=n*-LMoWd++Rfm#B(Ok4q* + WcWI\G9VRuo74^GfJ.mLm-^1[CWGZ+XIkX##NGKCkg&6tb3mBob'<dIO_&)Y3a6fFe[`/dH + @"hu*XMff\u2de[`u..0@R/h?,80dpB&@)hi$W#rh-](\'11G*`l@Lp-,*CGeZbC5``LM]? + %_f!@4p3$@DXAo(D>Gfpn`f(TgJ*f)`=m'`DA*-tVr@lIG;ahjJlTpLe9FYX\a[;MZ*sU8$ + XCs7B6XRJ+AP3[4DpOQ>''O*a$de9m`E6qs6+Fm%'G54"CkX%1\)cLUEc!3)X'qX/RBgT+C + /4+f:OH@*jLddnR[pi:J/V7hrU="ijIiu^d;e5l96!:ZJ[n^p&%W46K9B0Q7fEqDFW6^3k" + R@3d=&+hjNmpk_H27c;PKDaI55Y?$'fIkS?['JEtO"3(_=ZJXVB"[mdI8Bgi6<i+f!C2U5_ + Y.'r&Y<uphtC%A6+o1B*`!j+n`SdMmO#.(OT6NGXK[,JhnENA0HT9_dG)akQ-5AREVhDKO8 + Lin^GKP`"9<_((:Ijt"i8fe#<5'/)*=B03hY:>rd797H"E$>J3\q*Yha"DN;RC3f<Ms5VPU + 9Lc0i%/a.qC,.siNA"@tY/mAAB:^>''>Sr,`$fA5]?,NINc)"=32Z:=s]Yd@]g:=4j>d8no + jKMo^QbHl5<Qa_H$lHZi0eK\h],68p#*`Ue!khk_i-U!QRPWf`Y5i9QFR[*m(cOFEG"FrbL + Ddc/A9GeiJ>4eQpGC(,Jaj-p].=3<?"P$e3m1ipo/j=`H,/+c)g"=8-lk03G49%\E9`tIje + QUW!dFCp<j9koMiT_#^R2P;OO/Sp_9#$Vki%?U8SYjoCdUO&lm,dF@PKq>G/=ETbrNl..#l + sDS'_\<MdhQQd>kF@Ge'gHQrV/D;2\Z8!l7P5!J\*nVo(>i!kHSi'qd7ci.fdp1(4l+P;N& + fO5g:4LcLNp6!5q`:"P.4M)Q:kTT5JE@T1cr0!2MR]M]hnc;V?fN_TU/"s5T:mo&%l60`WY + \_BScHE%XbJg%h1aWp8K<hdldc'88k']Vs=BATl'&<[[lAqMb\%"]8BTa<)=LB=;#Woui\t + heN3i%>@6\4KHt6AT0EQeT[XII_,VO.23Pko5aK&!L_*g4T,<S.g#2JKgeO\<iOrui;E"*< + V)j2mlLNKJANMC^7s+&AT4N-<2DgDId7#*H5%-gp9IRH9t!7qm]DNIJ(!dL!6L5;+piW`W@ + X=ul.S^GGt%Q=#U"t$=<r[JS#f_.T?6,<!-j78,&+]ce1?mK8P`:boOlTj6NB]7_BR+':\\ + GQZo#KH$buiY(<Pb"8p+*iSeqAkqTT9ga\Z(bV5KPu?J>c-+q)15$B&Hf-'N\JSm8IfH/K\ + C.jus3fN4=VV\2-7b>sV;OFC[@8-0J@amJCdbu'=hO"=jj0`]fR/5j;fV:&=0kHSk&\eorZ + 'G`.WObCKgo@/($+gM*,;-9WSO!OYI]4ZRoqAfnc]I5=/asWEgY7`nRpo*hS'L52d=JVB]. + b-g2FM@^oddL*7@74OdJt>f=Z\ndYV5`oH.K*9N&3:L@WTbk.\uPOd'A<EW[.LsF5e'WmUo + _lkeP4#41,IFWY=lW=!JC`474NXFYq+MQ*Rqg<Q@@-]#R^ut'_bR9T?.T0V2G8Uo\1-H-r= + %(ZV#@<nXiB?<TUtg^N0DY+,'k<T1\HsZHK/GqO^EqGl\$fK`tY-4L'lAO0=^qo)]1W$4F6 + ;Lf,*?rq"CTUu/oeJrIPJGPY,;%gY^!;ucDWl*i?s^nS'K>rJYV:PX+@Ig<ak:fuX^$W[+; + BHMB]?_uZ$!!7tn!r%"DWMqBHP<DVtr^-Ip$m943/9"rL3`i4/rq"niddL`I5so(3#C0XTh + C?g7QDXZA"mNKPJ3]g45T?:q.SIa+\o^n!r_E;1%3RVY/C:h$-Er>9ggF.$6:Cl+-nGqY,: + `]aa?gX;Ds@!RJ0:Mh5Wf\Trm(Ok>l&jX+:'AH&<F"F2-RtEg1@:Ss!@Wp"sArC!c`N]WGX + 321NB@nq+p7!2ZQtp(5UkG'=dAman=*ND?-sj/<GsQ.fT%_Q_`Ns!!H/$+AoIES>T.AFl>j + =mr8>*-nLIYQ]rDii]O8So&Ul7<Dcl6^b\T*;K8;sr/((#*.S;%$^c3=`HaMQ=3(;0qOJ,3 + IhWYP2FGH/VN4[c5F6i*"7R1^"cRjeJVW]Aqi@T2li;E&@0&=d7&^S0cfrqcjo(tHq]13Z- + nO<)EY[b?5*c#&JQ+sE!LI+nC4qK9r:ACcDg;>sTs0&oT3&%FMW]*-;Wl_!!Mfu.$Wupb($ + BjaZ1PXLJ3PG5@*<d0kP=q3dVjL55+o-1/^Giq?H$sipK#oF6i+J,^hXW"Y\:.ro/un9l1[ + @AY>JE;U6h,`Wo?&+1Y%o^9>CE+G`'?>G!-`3%Z9/3-iN`Di$f!@=LV8KH+&/hH3+*9%YY( + fHV(3N.\8G1W+u6aoFM#\&IJnjiKGb:o63u&%flYOTs0&;VQ4r:YHFnba3o#/J/9Ubi/q[4 + ?)@>g#GgM_!&%/N^cN(-GYYkEFm=>%UB#ge'Gg2`91nkTnXL+@aGf=>q1/O]+pn^&l9d%mP + Er(pp:l?Hl2J*%PPeM_?j25f]J`*qF-b.s3hs_U$MDK`\kdrr00^NY\3XO(YC0HNF;<-tO1 + uUa'%n$hH<@$3fq^Fb#6b)0'Gg2SC_b9!1o'Z5Kl'haLKr<a,!'"Y@K;3+K`ukn>eJtLq:E + A$HJce)o(8<-H9en+_ECa]3)E_m+3RVGB@b!r%k;Cr!^3PgpZ%hn+Qt4)i/]NAeOd`$IdlM + f@RdfF=ZrKGpMS@Fj<k7aHVmn\2_.iiBBn-0VuJi]_R:rF6b+QO#TO0ZpuX)!F]S%&s7=Ck + KF6HX=-"r`K<OUDHr(1R!eggUZqA;Yk"iVh9uV+pf:t"a!B%Hpr.G)K)2/7loMqa!W-HV6^ + ,+P=A6\MZ\ubeYZb->N6"'edX]=n]%kR23^9Dh<'6Qb<C=J[B1C$Gk'Gg2k91j>*0i(8.g) + L'9Pf:_Ph@inc]/R(/!q65E"oPi9`H*+#?r-*BD7q=^Jf`#($G]j[(@^4>ESXTaeL>qH^Q7 + n5Z7YY?BHH@>G_O!9,2uhso\:hkH<Sr_5H&.="^i4%"[kJN<'(ido^A>rioahMM/3P@kQ=p + S@0%hI4`KS6IW9n1Kl,5C]H[2;+$QV,9MnnWb3,!];_cV*E?5!2Co`j,qQRU60L9+J6/ts- + k83$`Y^OBbQ3[99kmm8_$O@+I$OHT=(!l^.`ZF,nD8eY85eJKr+DZdjH+IUa+8J]>mrsWob + :A)[-nHM,%ob[Sn,I.hff,da=7ol^cj+e<$4FrORSm9<k#o:&f<&6rl`[KE5;fWPq]t^9hM + ^J1^tgCi+E!m1kF=T@gki*W'%p*.jl*M?F7Zh6&.e*?$MDK`\k`D=oDp?k+R[QT4QkC18%0 + 2@<HHXc)]+g4c^AofPC-L$`UXA33XQ5t_/L.\o]ai=Y&=2DO_rKF^TOSM8b'FA`N+;l-$i+ + (Gm3q1+iR8[+:'#cnXNZfSUKD4[]7*I]&LqcZb$9b:D=?36#**t5S1T(<$rFPCu![XmD?<3 + X'/MP@UB&BM;hsW=3L.AmYO:$UTd!KbYp5l]67miY,mI9ZFB:ZC>McmQ@8;mS@mI*GY]$s/ + !/g?/.`@gWd)f"IP<qa_Z&\hW5eM^8sZ'pR?bBu]QdQI<NLsr:DAs'Ka!&QNr;`=f(CgICo + bRFCF]c/(VM\#]W1^8Gm0??Ka!'<K8Os.[7dR!=R@H@^UbfXqX&X($=BDV*nG]"o0=BC#7: + hAa)akLX-i(Brb7hu_VPX;nqmK3lE]hVcghEr'SQ\lAX&'t<itY&X0?g('6X:>5aPQBeK_6 + \?B%!EIV&ZOUTd"VHpGY5)&[.T0!2E#fbR<TlRL45/p]UH+4Q<$eUtE.7;,M"+AeYR$E@R, + ^]421*Yl+`A*r!Nq25T("n%#s$Jep8EWYd(YX$Qo;)(jiG&OPlgT"h17;s=3;lkbs:JN#R' + G^tChc2C,7Y[HqMA$QS=EAc,`PZb;?PEE.D6=r#A)@k.'G^tC0?<`%`BX1?/7/e^CTS->&R + 8X>Xg@)D-P-rF"TiA-MKqDbnKB*1D:Pr)6KE\]jgqYnn-!3pYWr3eSr.gip[?Ja]KnH]/aB + LBnp,N"3B^VrGQKTs=<N-c="6q`49lBL&^P6ngWM)sr**LD&n?RpKa!'BOG\=tq9AHh@D,H + OJ%`K=GI*&He6^a4jl\#<2@9fpdkV[0/7.+)]VfU[DHL7gDM^k*e<]@uo(*N.)heHIku0(o + aiI$>ENrC[C=cE#/jB$l</ZG^e0F)<-dXaY$O"r1Q0PG[Sl]9i/KW:6eR)ZhI`gC8$6J#`T + VJ_V?qjKQcf:&s(%5b/Cd$.C8p?UDTg0PF/.bp'HtR*]i/Zg91tK7N_X)h;(\Bug&IPmr_? + ,;]XGZ0T'W_jaV+[*:()mrG?]UKpTg0PF/.c=o<Qt%fs"Zr(OY/N@X>0U1i]>m]IYn1;6=G + Ef>HD;*c[9?7GTts">7#FPpQV;E^k5Hc+NQaH@\,#I\r-70]s=DS%16=>#Kon?i'AbB&7f. + .]fn/&9nhS2Z#.+%I[NK1oCU[k:6Qcq^jT'^+Q3*qQtQ$QLVskj;H*NTZcD%Tl;$o&'Y#e' + $O#6)(%ZhGX(0']l(6SVV[D6aIZOX*7:Catqk/glQ7_DShFI=_:X1aECp>$.5=gA&U9HnuI + 9slTSN:?3f<5udUeB7)Z4./1X2d*`FST&Hgl'#N_:M]+4T"h((/L`!OerS"&%nso=n8m5\/ + 0i&Jo?g0H2crEVMHVJ4gRZ7Q0Z0TZP9ncKa!'HNJ`"QG[d%b+5NtWZbW6<kO]&U=UNrB_?. + RJBbg6`TANS[O7(P)H.\doN^fQg5>HdA:fnk8?AuRA+tG1=\TrgP,2J,m1jc%SFkp&HS-!o + .YWsW/<\[C!IcqlZj!`_Be"EpVH@YoQ"n"]cJP_0_AuD:"ClW`^h7HjpaIobkHBe=e"n"]c + JP]IO@\.LcA"7cch5e/rb3YnU#2N%'U&oP5YWsW7To+-pi"$$LpX+kMm?7qc>G\sT:K67I' + G^t.VcCqsDHrKP*3H_qBT>Ae0Bb^m',A"jK`sg%AYn+][SM3q>'9L!nNONc<OB];Yk`UPr' + U_V6t(YN(ntK2S=Isp:38>DXu6))[SD%.+0%RV$4DO+C_cR>gV:uIn"UVOY>7&)lkS>LI]* + =M-nGoFlVu+"c#8UYO/!GVN]goLfMXk#I]*=M-nGoFJ#$PF:ObDC[M(`?>Zbl?fK;;TU=82 + d.aWda!b(Vs.csmEZB'5MX_=_AQb1B#8Tlu&Zi"&3>#8<D/7):1cficI`T(W)d9G'.$<s5$ + aNmkZ"bd+H,YPOng9jRhC't"?s/=,=jr5#C8.UoVX$@%"$\V%j?e?e[ITS^m<n*A;0IUb?* + nRLBj[Ui<WENrbkg"=^@tS[VUbghUXA<8U&=K8%Si>P3-ltl/R[_mkDDq;=p4huZ5,]&_=* + ;gor7X';5`[t,7hk9_-$i+]*dgfq.+eDIFRMiXo:#)j?$EF%?#"M[HJP:bc7W$t+@I!GR-0 + 5hS08qD>>!bA@8PTL\tAc!7d)g[F@p<;HFpAngJK$jrU-;?*uY.=Zr+e)YIp#,:Y9B$-$Q' + !E-&0>`5aaPV+G;\=/iY!g?L?'Ip%56!/T*6.d$QF-\dGDd?^8'=.2jl7\(tlZk4&cSQ;hI + >0e^Q"[_@t<6V[\9jdEG=qfSV[q10-A@n_NM9g$l7ChjP7:%Do&2ITm1!c@M4lje"chX)6# + *\GK*[!YU&ILI=(Q\,Z@=do^VqO<Z7O6=.#tJRc@Y;d'TLXj"D?O=!DP*iI:fm_4dS7,t\o + u=4c_<l$f2nFN[sHk:I"3H_,!,\(*oUC2.4c#o"'!KC=1;MKN#(MnT4fq6.Wl9l)3,iOW!@ + X;<sf=gcU\fB>e%"14Gst\3&KAt\=M6(`+M%2bP;=clb$+t+FGN:R-3,,A`?k"kZ[LSKAi- + "a5#ZGG.=06\td7+&el*P*ck?*o>V^W`3X,Sj3=uDo?A/Kikla%e"ec,ogg1q8n!;?=fPr& + TDir@GS]Zrgbmbm^0T."`90.4VGn)r-a+4"#bSLSk5##NVi!F\Y-MPY%H^lO*[3eo&L`ug+ + 5cW]@=don7)_:Gr8r7o-JEV&ic9\IQE/';IJOeD8@=f-,q(=+$pL\#T!*NQN-H$'C2-k;]? + 0,*Fu?k;pg?T'2!B,YH8L<Zd$B`nR-.+L)C=6.ld!1$eR6=$epYJL42aR0>*0loF'^:H&3c + /UR-/O_)^-7jlcN#J1Dk+#HC4JPLU`7gJBM!UD4TTUoIj)j/.aRdU10]ASerdq7-eS?Y:uH + *brS4>_F%.bmd;j6"ktC^hH\h+3c&\=n,0rdDlgZU\^GathRKf&WbBN)JjgDe(6kG]=*A]R + q#drqpWb==BDT0p;u_%#?cZ"O!:frfMKtBL&[AG^bo:[^RsYos6['+anrQbI41JNJiEWimQ + Y2f%DQDhG#(ZJs:;o=;rpV'#+F9_lcO>F4GtI`DTCWWACh(#oebhig?F1C^#aN`:R-0T%#) + LmX$Wlm7)GJ5YHA)'lLPShkfO\C8kKIu@U8>(ZW-hI]4<$3N'<e)GDH<nsS!/gm;gd<:B,/ + "ebIeVYRbZ]^nhF,Y('p2g<6V[`<F>87H6TXLDsIOY;0bl['-I#=;iU5319Yu,9t4?6de/N + a_?-G%'c$<k?.qrcL>Fo)J!RpX]Vl'kc[>Mb;.mII/oe"(WJst1K`sg),o-$qTANR0Kc[3U + ]@^Lp(?eWT@it]+/sdF;19[%)5@j!n94<BJq3m1dk0E?;SjJLfhcO_R1[B11n_k!#Pj/0"o + 31e[Zq0cm$4EZ(YH!t&n`$AC>@L+=N_'FbZVpN/+9(c`2;QMg?LtX#CoCWLn)[/MJP^Vu`B + 4Yqgdf#0hRRlUNksd=Y6Tp1Is@tgGK=j=>b\*CL"2M?K`sg)9.K(,[k9\UXjc95a\mcMRA\ + *p,eG>QXOGuYQ`.u2@/K%X@=_7#7`@L)pNt#mEM>n^c*_0To;:q(*WgTI]H6,hYGM,.7O#9 + )I\j863;o8&Gs:kojP63VlKfHg$qBFqh+Kj5n:L7Men&.qG"ueP?g#7@Q,3Trnt_.g*d]FE + 2uhe"dd`)$VJ(f-.c(5/kC0s0mcO$tQ:k%V+T.g-1!ca^SV0eB]@2atb=r2?*ZNMki^JAdN + B4D]ol>nhU*ZDE<[fR2.\BTncVmUci=jl4eC:]Td:ZmsE3=E'UB"LB3iuKpFd^jeUN=+rX\ + r7D<'I!bShGJ"P^!>E<qQ)BK5l3?pCZiqCq6A=\]jBM2lAPm\_QRJ@=]]p0bs;mnA8l/!da + 8)qst7DC69Pah?@#$?$CFZf=\4!)JUfUQ_:QJpcYWdSl]59-XK'AeQcEh2HQAiL3O`s;S?t + ?VoQ:um#?qH]ml_R=<LSoX-i'graq%4!PK7_hN7K#acl(/kcWorJ/c`orN%(!19VF*X=op5 + YX%tpX-i(j5Fs<15Tc6WR:.dQ0BmrFNIVraoK\agF^@);,6#5I.4c#[o2Nr?IJZ.sr;#8Ch + ElkZl<O=E2Zh"%lCKX">.AXZ2p3Kq/.d8/<QoORTQf;^$]qs"<G"%q6+7L\"UroG::]e9qk + )OumcIN1Q:k%V+T06XR&?nH@Ia9k+gNh@X3!l:f5u6,=<LI8\!KaHEd7[iH#Bn%Y>P]8KZY + DPo2Jfgp6T1(cL7B:0P3!'!TLdX6ED`)\9M\Imk7NF$\V+_eb87[0jQnh^8X6,fO3.ild=_ + 65XNV9?^H%$]6fFUb9\Pf&:PX!gLp$6NoK$h9geRlZ[#cQ4,?r?EOqjU\BJaFQ3m4C<_L(n + .4c#O?W/]*o]b2M_rmqLSWaIODPcbM*Y--+c>naL4tN%nYX$9X;8kZNftGA*kGPU1Et(TVW + ?*VI%`B'dZ!?;Zqt&oUT+i%HO2k8EPOsoC^WZ;uAL;nDW5h;JRWq-F[YoH^bIj.RkM("`$4 + DOB#?B">r:A%FpA[l^FmI7`DlrFQ?4aK;;YP-uf7NCRS<o#pl]]0ei=X,Q`:&+mWd+2aG&I + %RKCO:WpD/eq*os3dk^L'1m1o.EL/V1s4D(U\B?QU*=IFE3ne:U'-?-42.c(cm=-LpK^Kfc + 5i?Ien-A;W?A;#hchLAnt[Ri4(A_@8$fXXD-k]H?`i*N7+Ls*G;3&k.?AP$<]OGUA_+tZO> + e>15RVcM'%ld'B&RD[Q99=uU]b@TMMAR<]s0u\E0LqbJi/.a.8="7L`I0L2J+?`V5'YcH[? + kesn^>_GpSXeS_>imn^bCmImX2JA,'G^tBc`<FG_1J9,,=P)@klh:?pm`BXhA!>3d-^C00: + 01tI[Tu3Ohq1Yo*H0'r6ZSqQ6%J1C+C>`)ot`76bFt[(#A7aUkcS+C\c)Fh<%49JWTY4(%Z + hGX(.qqMMt*tL>:D#Rp>OJY2XH;/K;kZMVjii]F;_cMSG.f![4g6`B=1m:Xc+0MO9R?1CV9 + DRI2^L(KBYe0(W8NI8]+M[GijVHVdfe,Y"i%kOmF1=0N%DR_QpO1)K5<idFC<Fh34KjV#+n + `n+I%+oVh]*srC/7$`^U/mSh0?'KfM=gc[o4u_\Kig!)<9fg2f--,*Nm$7L&i\/%OTWgZu4 + KDq_Pl7UWMb%AGrjIXfo=7J;(Cs6_.b0/Wk4O,I/Fh?KK2G_n$m&>%cg'&/V<<]>o*8kFN9 + CXqTQk-J;haZ,19ZDD-3n.n`-kKb+:M;OR-3.8;sUDDpSp?bfO.>7ld=^o8O55FZcg#D]f+ + h]eOo@5?(35n&-apibk%SOc&eME_Wn1'S'C4Zh*J\5.A]mS3ks=W/F9d-V;a/===>^3"p7l + LF80_D#EIsS?_;-gX0:f[imC=<dH)"Y>it_-nV>%iCiQ,P5i@&rWHP</PF7h^o4F(KORbur + dCBJA\l91UmnW-re,<S7[HR!l_-8O3?PF7]][*REB@<TYd_d=AY*CUsR+Q\1N,rDRSt8o#9 + m:ZHf=\4!)J[iZ^XD+/@=c5k4VdR9pqq`[LIiUFeu^g!gU4VVG^Y`]SaMU&I^qjl0UGGf(P + N"oDjH9+ro,RX8.UoW34jNp_<A&K]u:)<gmWAsqrJG*\I6>_@#:P\5iD<81!aX=L#U)_5Eq + e1B/$oTohb/_-+EJlONY;.c^>N)K];%D<YQ;T[MP0#;f/0!oX)c`Y^A4f\`ui@-@buma#Or + =iYb?h=*-*^GqIZ/WMt?;po>o2'G^t_5>j5^Zt\?l-V8hF2m,BOa^g--lR_Q=,pi</-#tr* + YH&#jc><mr"P[B#o/uj0E9Tq,/B.'Q2]1T:]!$@;P)l0q'#c$mXuD%<Jo-m4H2dJDB1bs_@ + &Z,l^gN+ne&0.OP[kt!X]Q*VRFea>F2_K`VC3u,?sei*CVi)Ec\CZ\$\#%fo!$e$G:pDDX- + ?:1l$b8VHLB%Wbt[/&V*\UA!;i"<Gm4`C-p:$$-doXNDp&99H%'%C'sCN`E;hOsju$,]-16 + ].!Wa(W,BY&UFJ/7C$)5jr1JRj8;YLt<;f[[HQPea0YIU.B='s)cIj)?i@=\CtULKh`IWr* + i(^Zq;"cEedHD)B/hPMRFXOGM\&M>_E/'`f`\\rnn=<OPKN9`j`!sb,_O-(Qb]=,juYW(ch + ie7`O$a,ghPjFfX.jG!CEfIp;61n(io5s5[g"7.E/N<YXfKRDb[TD_]ie7`IX0.d^'^hJ2_ + W;F)7:Cb?R\sVdN>qafc]I(rE,`8%Ge]mVMFT//C3?FZQb32TO2"i.;Z+LD$&&P7WgATgrq + :9.8C*CUW[_1]0]DWrB^niO<0PTYd%aiP^fI%2/H3esLVa+DoQ_1taj9.>YRf5cC\T0e3o* + *7<hX#7\\s1hZc-90<`)sAOOgJ"BAC!JklDE=Ks+91R.FC%:[qhH::]fY19Y>7:C6W5M>O$ + O5Tl%d1!f#Is4FGXVpL/W^Abg\SbT+>dM"iaCSF/n$7:cgpiF0u5L0)AeUi"a?SJoGa\NNL + GBlcZp+#4XZ=V32:7LFb^Roa>]oo>/:bO`+bZd[_*Yk^L?`L:Hr&OdHg+0*#l]h%"`KMN29 + E<l0@k-X*e>ZA`D6<I.#l:O&W;T3^2dT('k+>Qs`6/l&or@uJWM^1(K^Z;>.m'S7.:+%j@0 + 5@>ZW,/TG3rJti=V+Ar>FLB-1RD<94a%%.hmH05%sH+H`%rts00&==o)^hebT4G@3)gQ~> +Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.pdf b/testfiles/cli_tests/testcases/export-area-drawing_expected.pdf Binary files differnew file mode 100644 index 0000000..17e19ec --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-drawing_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.png b/testfiles/cli_tests/testcases/export-area-drawing_expected.png Binary files differnew file mode 100644 index 0000000..8c8ef62 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-drawing_expected.png diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.ps b/testfiles/cli_tests/testcases/export-area-drawing_expected.ps new file mode 100644 index 0000000..130815e --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-drawing_expected.ps @@ -0,0 +1,480 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Thu Feb 27 23:52:48 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%DocumentMedia: 87x72mm 248 206 0 () () +%%BoundingBox: 0 0 248 206 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +3 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 3 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 87x72mm +%%PageBoundingBox: 0 0 248 206 +248 206 cairo_set_page_size +%%EndPageSetup +q 0 0 248 206 rectclip +1 0 0 -1 0 206 cm q +0.254902 0.411765 0.882353 rg +14.172 0 m 127.559 0 l 135.41 0 141.73 6.32 141.73 14.172 c 141.73 70.867 + l 141.73 78.719 135.41 85.039 127.559 85.039 c 14.172 85.039 l 6.32 85.039 + 0 78.719 0 70.867 c 0 14.172 l 0 6.32 6.32 0 14.172 0 c h +14.172 0 m f +1 0 0 rg +243.668 152.23 m 184.707 148.898 l 148.539 195.559 l 133.488 138.473 l +77.918 118.504 l 127.578 86.559 l 129.402 27.555 l 175.141 64.895 l 231.84 + 48.395 l 210.449 103.418 l h +243.668 152.23 m f +0.501961 0 0.501961 rg +4.251969 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 1 0 0 cm +243.668 152.23 m 184.707 148.898 l 148.539 195.559 l 133.488 138.473 l +77.918 118.504 l 127.578 86.559 l 129.402 27.555 l 175.141 64.895 l 231.84 + 48.395 l 210.449 103.418 l h +243.668 152.23 m S Q +0 0.501961 0 rg +116.219 153.07 m 116.219 181.25 93.375 204.094 65.195 204.094 c 37.016 +204.094 14.172 181.25 14.172 153.07 c 14.172 124.891 37.016 102.047 65.195 + 102.047 c 93.375 102.047 116.219 124.891 116.219 153.07 c h +116.219 153.07 m f +0 g +2.834646 w +q 1 0 0 1 0 0 cm +116.219 153.07 m 116.219 181.25 93.375 204.094 65.195 204.094 c 37.016 +204.094 14.172 181.25 14.172 153.07 c 14.172 124.891 37.016 102.047 65.195 + 102.047 c 93.375 102.047 116.219 124.891 116.219 153.07 c h +116.219 153.07 m S Q +Q q +39 17 151 151 re W n +q +39 17 151 151 re W n +% Fallback Image: x=39 y=17 w=151 h=151 res=300ppi size=1190700 +[ 151.2 0 0 -151.2 39 168.2 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 630 + /Height 630 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 630 0 0 -630 0 630 ] +>> +cairo_image + Gb"0WGFVoNIH^]DMs@>:hKuG,0.X(r,f,<D":W*XK,nD0\,\G>]L#qUH]rg8Q\:I]joW(", + UT5GOfW;#Y*)i!>1t<?OgJ;oZn#j7[<;+'RY=2/m*%TT3Tkb7bia8bs1$/s0@o^<pTmA2k' + OD+/BWFIk]aa_D"kaT!0Cru<WE'#>E8h,\<brKfOp8ZGO/`<82]"7f&+'H&b&%#Ka!R\-nI + JJ@0*/\$4G0V=9'e0_SS)C(-kKeYj`'T"d%.\/3H:.!MhOZ$dVXO!%EoE_D;lA5Y@fUn-k! + SOO>O.4@<NXUbiDdcVR^D.?23]1DCTi8u&W[%#"kHdO6Y/6X^"k1^XW::fm]HNP`Og'G`r+ + UTj4rKa!Rd-nIJJ@0*/\$4G0V=9'e0_SS)C(-kKeYj`'T"d%.\/3H:.!MhOZ$dVXO!%EoE_ + D;lAJ2M\6XUtLM&k-6f)%$beR`"SVj:M>G&jg$c)%$beRNlaq3MXV8gH@>\(UFekStW@gX? + $.>Co=LtPM<#'4hP%tkD9FtKkDeb!,IV_T%-_@a8<&7bW2mqr'uX$_SS)C(4\9_G0atVltr + 63+5F1fr249KKnX.f/-'IGmJ?4e7NHbiNqa.9"ptaa:fm_K*.NCV]nLU!fK!g;d=C*N6t,$ + l$4FY<j0)7nDdaZa[SG\'BUSWkGV9C3cVR^Dei;9]%k=[@o]?JWEu'W4OE[D&n-k!S@*Qe6 + ;qi^:MkI2JTWmnoK`tl/amE#9(=mJQf8MkDq,is"_D;lAJ2O75`DtRS8r>%u=\1nfi>Dt1^ + m\2+-c]BBi2i`IYj`'T"^oUP>:.?sfTqd:L\ArYrL#)c4@<NX=EF>H":H/kFSG,bE^)@6Kk + Deb!,G>JSmYCI?`g+`OtH5\;cn:!_?-t(bbjoBKtY0_@`tR;K*!PP-nIJJ@0'J?SC\OS2iU + &+DkYKA1PLNq-nG?[p)IAsZEPp.?:dFki>Dt1^lH)uZE4i7N5$kl-nIJJ@0,#cp[E3-Klrp + @k0lp0$4G0V=9*O241*4@@F%>C;XE;Uf]sWK_SS)C(4[Dc#;$bc[S>cm^$"cT$470e:fm^@ + j;_9:^T^SUG0f_s,mB!VB.,;248/,Mi_a,)-['aBP(LQf1DCUT*W'mnHWSiU^KO46eG>5#@ + Gr(2$c%c)q\FH\fJC!<;G9'SfCDN@$4G0V=9*M(mIRon/WRJ$a5W.S@Gr(2$c%dTHPZBT=N + Bs`Xf\ClYj`'T"^oBEpZD?R=N@CXPP6*'n>$$k$dVXO!-T?.GFkF\Fe%<)@3l)2KkDeb!': + \(qiK-X]ku5CVsJ;MC^LQr:fm^@*.DP'5[gGCXJDMnn-k!S@)nD=k"$6<EH:qUZ]u4=(7q5 + (!:2Zp>$/iB>:/JP=H_m/9juuu$4FY0UMnGD/aSnh8rA6-Y,%_pn-k!S@)oP.ZOE:I;%Knf + fctF]NW7%rYj`'T"^oBU2eEuXYYf%>f3S"?(qYnn^2nUj.k)kt4@<NXfPu;j%"f6Pl&8hMe + `dQtHDKB<`jq7a_SS)C(4[FG?_;5__2(j-$L;Y/>G?o*NU5oS'DCV-=@keei>Dt1^lB'iV\ + qnleuoJIE,&U[qq6tqR8)]P^[k8@5;n4LB.,;24&5.0RV;\@p"7j.[]7d3Sc?CZc5t_'F3h + ,gIk46$i>Dt1^lFW5V^*1p4?_i`_E)FSVgLY]DIairP(LQf1DCUT*N-=l>Z`AKpFWJA;.g[ + /@<NlBhj"li(7q5(!:2\QF`O4u/'t%4<7pETZK^QF+M3b!ZYB?R4U^]UYph4d6X^#JEGE[m + 7!j,YO(b;m/[";DQ6WHN*I2Eql]4bKi>Dt1^lJ.rS![mRcKX:B$gXbB=k6YPSCfi=Dfd9/K + nX.f/-%b,Dk<&(k)/f8GREce8rBa[=&MjsG_X':YiGAQnVK0,=:^CtYhlLX\6Q=EH4D0&;- + 3gA(^/,5B)I@"=\3U9pTY[jgeHh4jtDl=`CNT8(4ZR8Nik(7>H&[6:gq%A8TE_9m,fYo\eo + Tf=9'-'2(Iqr4ij;#/Lr7WCp0W_IV3t*h)aegN+>7`!EcT#8@Ch60'WILL%T+*7DY!U2_.s + %O(BRG$4FY$I>=+-'Wk('2_Jpia0O8<i1@Q+r3_]adZYQjJ\hJm@,IYh#!';kqme.l$SPOY + Pb4=e.j@0L&U"j(J-@q<Q^WS$pN9iq>LA]Mq6j@&PjFsgeA0,1E.c"/YTW,E&qc'AkWW#Sl + _rG&cfu*c,?qZnErD!JdSh(C7:?4!Y^c[^K7mOX]keG7dB(eiojGCoc.b"I\h%'3:a;ba/- + $(Ok:ACPf2^YU@UZ$68V,fmYQ-46Y]$4$]IJ%7gP*?.]'a<_-,i/N;BSgN(4ZPnpF\/@<gE + +@7:C+'T+k+p8(il<d9G'<C=bueD1i1K"^o0_4nB,OF\R)OW3EbD=\4ajI:DToLSa/l_LfW + +Yi*lTo*g4n?$GtEYd_8L8Q!]($H.S6!jLV0]-`66eleR[[RKg[!B)1g-p'JVPn]%._?-t" + n2h-uFK.fSp7\^NRbK>A/3bSVFRRH9#4?n+)^m6;$]_k_f-!u!\s#@4FYr<*p/b/)5.UYR. + k0s1'Gc3&8)B\E:oKkpUMkk"'jXCN?4X=\ft8mMDHpF!4in:0'Gc3&8)KhROJb.q_9^!,W6 + i6F7b1FcC7b&O7fZCg!#?R14j+sA%D'7QKtS4,8Wh%c$@%TJ!jLV8)`%r'e>P/l$@=;7P+k + d6Zl@\>Dbb/J@3l(\;-3f6*8<?g+A#9g6`R@#kJ+]4&%*A0r,!*_.p,Ao().O7"ijuBDU>. + jSM"$s>LA]MA_'p\C`6Z+G-U[U7hAL!!#?R33R&[9:>fXjgEO4l_XbaQXJ>iM"^o<+*@?IT + DelCWh9#LcMW/iX2qG*r*qBk1@0'JLEr4?S"-f_(LkkXu%D(@UlROE-:;0l=;L6VU$AAXk_ + 9$Om'!749bpZoK]<IG"<`)s!(7a)>3RRI5kY^>2]rrrtQef`SM6<Y16oIRHI/&Z;!jLV4Q: + VD_%B:Hu*n(@NY+unE2mVUfAi2NQOs6`!=9',Ls4YCZMfVp[&2.`:=@iPF-nG?+:2c_cBPr + _"E:JmqX\!/ikTP*oS%ifLc/f\gP99dsYQ-46]d_pW(@,Dg%?2g2dk9m6FsEKgC&HNZ7FK' + q5+o+[/3'tMI%m<S/e>o')CLSH;FHtapF3XM=9*7+3OZdI0r93#GWOmJd7T:n\olF9J9NCm + !4VYA2(@m;4\35T$#.nW7=(?Wa;4-0<*-J"3X"pXKa$DchBU\XEOi"QMFTI"&J%o?jDH#g] + l]Za$fD0q$c&mXLR/sEV+_C20;]Uf;BS.;(4]Wd%P9JMasGk>]TpL:FdD]c'W(\=ZB?EB:f + m^8jW%N?En.&aMMKUh031sbm[@C1A$pCp?jhYli)\-S,mH6;XS[fTdNpPI;WM\c^e0Jp6"' + f([=A3cK9T@!hVsB60;?pc?PVosQB`0+K#.S.COaVRK8s3a]u9e]M\dlm/f^>9gr.7=TgiG + k\922O8RX,l:[p2DjN1#OG?@EKC(qG6>6jmT1rtGnh'\d_]0'7gEO0\^F=CUP_?+]Bi1:)V + mC9%*M)WhnLebR\#M>#PmcO&k8sW)i!X:&(!4NHO2r>_tf6(0b+F:tiPnYV.h27"9!st[*! + 8KX-mQ?,4gsB?F;s55T<`51KS^Gs&a0HjT@0*l\pmm0KH;UHD`&m1^HJSS%*aq"5XJ?+:$4 + FYO,B(mcLdeH6/07*\21)Tk@`sGiZ>AcK+<D44J6PP#RU]0OS%>A>!I_dVMNgP<!P!:Ec.N + ;hW7)c_gZP3p\uYdp'F.c4&TAF"J6PNfcS>bo]l#JE5!M'Zlih^"h8gAF26EQqNH@\[+;>T + A>K:p51oNcoDC8aRT<XP'`DBY:DB7JC;HP;*ilUea=">_W=\02j'Gc4'a'YHId"Q)&0&AZ= + d3f+MN3&f@kZh.d":Ttfi7@GMV]->d\XF0bSY0_gQ#D!q7HrZsbmiJ*'H@f&J6OCE:,BtBG + iQ_"k]YNY;OlQ#V>`M+.0>+<!c[JdNi@ki+BOU=%pTZ&lh'dpYhdC_D4,A'ic=:n?mC@/i8 + 2TC;\H2t^)eM*\)=43^$S;?;/p3!FC.:A!P!8e>Jc(Gd%eRl(+@dWf0!)3,T@'u^o^O>-RU + tQ$h['\W!,ndmSISD-,mDRV`*,/Pn$O2U9FXQH@O,V6mr";4[Qep!S!o$MY0fXOj2cAZ*rY + #l.2XW$4FYOe#t'&fQ2AKGg:miU=77I=@l@iZpZr6.>YhBE9m/Y$&Qt*,!AW4AO.);8R_F) + =]SEs=9,%9B%-NCVgYfk.UKB1X3mL0ok:t"/_MqTWICC[G>\[""lP]_W%Z\R`=j#7?EBqNg + c>1B'i,10YQ.!tcd<I3F8ifn,i5_$Lp!NjA2gfqUnFpl6=K>FCkEm\5n=Zj=,:,/^$J5>;1 + <7d,dK_I6-5,'!cV`>iT1:(rLt>USulsgY,&<"Uk&%sZ^Mh98O6bc"Ot.Qb7&!0RI2`bXO) + g,U_mf)ZKL)7g/,+F\jXYt_?+[&kFbCTbB71^@"hIAc7%(-lp`m_gVfQ(/#6[>PUJ'_=)nd + %243ZqFW^-WKiCI<?./]<7Q,J>poF4KUjJ>R-nG@"p?u?t0[_InDt-e\RR\kW,0ep?6t$*! + `VuCH#/g@rmNipRYcH<FXKSEJIWp*:*@iQe/:]uFY]#Z?,ep@+MAI`K2!W:/4j7eS$[,4DX + '-h*VW:!N!P!/Xmm;X]?E&:-k:&E9Z'$;ToD%XJbG=`o"=Pf$<t=Y$?nfL!FEd75,nj<W"; + 6Cli6%bfjr7"_laj-AQ'+hKcEb0IU3,9d<`2ar!)a<?43q;Vhp>ZIPE^I-=@mN+N@FNZ<_K + >?UaRbo<t;q@OMT^q0"AiHPa&g_8WgK)!\5]J/-,\jIV5h"d&tce`FG.6,!,+smUJ2]XJDM + n!;q'%XZ6S!]2j+g02Zc]@O9!I6aN8OpfNj!!q=</UVbUH%cRpiHHr]K"kHaQ]Yd>K$4FWs + 8)KhR0W=;[Hgq*4!fpA[goOa0*Nr;4YQ.og[X4=VP]"k8`9WU2,!,+c*agq4\XUWH.p4@XY + Mc1[!*hPX`_;!sm9EkPV^J<cZBF4c]NZ!<M?OlO"lRPn>r)nDF-Fl\O%u_F@O4IbhAK#sHn + 7p!!I3W!ldH:iF$up_(FKC:lh4ua#eQ3NgbkLb'GM=5(Ja=eAh]Nh;-5!5XJFK(Tt2dZ3bJ + I]@0*lY@`Qtd#BHsg.it//`_$RF$QoRIDP**]-'')lSJ\<k\uYLh'Gh;)@3l)2"^oNqD$_" + :?]Puk$QM*J`r\EHDIe[^Rat<I7QPAe6"'f(Ebaq$7#/!&e]$R#(1+)<aPT1dp?KQDFUJ6X + $c&$+>:(XWJ^<TniakD+Y?"O8Z]]pW!c[9"f-Vh*Ia@9;i`X*'.WnP!O`cm/SX\=`.4?_I= + &*\*OQbUSd_j"UJpZ&3XF/bQ.8'?[Ci2esH_2];!*;p6)P?6C/_3;.CP)Fud-[p<Uc>u%9) + \G4>Y.4i!OuSmE_H$9nW_rtRWWqU*c*d@[oZI48thLa9b$EkT3nH[ql^\LJ?_7-=.&p1TcP + cA&[][Z8d\)-R0DU;o2J*%R``Ld-$s7bDSH&c4+Gr^b7k_BZ+WV\]q>U%(Bh!Kf3RuaYGA[ + IE-@DHUi?<QC+c\<5;B?LkM8)I;cj$;logMK0P3!'!TNo?4R.$D6JF">cFl6GZ$*6o)-q88 + =0%4ES3J\XDp&7OoV8Vjgt6ga\\X4Ve,@8?JN,OON++s"DIi@J9rtH&iC]!K`nDpRQ_0^jm + ]F!BEDos>DX9Hlb[A4mdf%,%JbVZU>+#UG.@b0=q.RdAZ#8s:P,3#&Y#8@%f&[lVC+rr:F^ + OZR+Al.M]CdNT"El([,dO,HC=Ul47E+_a4T:_b!cTgU^_2:A;ka)EpAtP6Ff0UMg2:GlKK0 + j*i^n"7gp$dtL#l)($aqFq$^AL0Y\X:<`<MOhMXDc3$^gHn,t6eYP@[fn3</Bkj_Do/).tk + \r9'fY!8Q5!ZcHPF>h)!V9*&PI3rQ]4A2gf>>:/.8\D5]ZeR*gLVJp1b%u6m`!.8`nha2t; + ;lP,"B*'\kdClV/WVk8Y87[@N@K"`cCiX-q/;<R-Ka$DS_7^3b-;Top/fk;.kK->R"1'4HQ + 6R>_hJi@4p!gWq]AraR%>=rs":+\F2jc_ZF>r_N^l%>JMNN)"FRIDQcBY:(YVt%61]*IIK` + r"jLYeM50R91(+7V2'Q6r/"ik\4okGluVXHAKb<N@Up/;S?r"GI!j=GP`j.;ZE;'(5lQMWh + E?\t@e@j_bud21JK9Q`KfFDHp:mnaN']XYQ6D'Gc4ALYmBu@.Mh2cJh]OFWRZ\Lbq?cA(fF + Og#OLZOCAP)+Q/9m4kF*4eETfg3Iho.>"R+@\*c2a/N%CD0$CuB'OliOV%==V5[YUXCQ?6l + \Z%ZJ[f@I`d-]-CiHA."Y]E_8V<ls'X7$5aEg=KCYjU_EZOJ6WSaIUA!dMbDPn[[!ceUfS@ + 0%3,\pKaZjD!!.`@Cql<Tr<!NUpMK*om0A;5Ll`lHEJg'nlg!m+<75%AqM>i?LMciI`)\Mc + 1VclM9A>*a,ZCf'(BkSbAO;!=B4MKk%`,(lY4:SKU2pi=@SB;?TCj*`oFu?I?IO*ct`iKa$ + DOn^gL,T%U3o`@!lt'4"0a6p-:6jQk20omlA>C[@BBKa$DOnX\,;B%1bt9c?o[o5FQ4mNWc + C2i@73$JkT1Q`KjL@0*lW@Y[N``<SRpGd3FK;pOLi"[2?V[k/Kq,?%\E/tC^gnFkHr4[shK + 6])[1.BGV37lXT*GMfi>JAMA,iT.Er#1j%<Euoq'lbOc.9K]*Er8KZD<"Cn%>eMct$c%Hp> + :1dZapRbhnKAEGcF)U74]&ek/XNO4q3I!l'Gc3,Vm[k`)n&S('VFk#Jh+F!86'a(fFg?cq/ + <J2HLhGs"lR8pY>$j`C(R$)#`*5djkEB7k?#8Nh*8&\g"8W"!P!)pF2EV_d_j$/4+bA\OE> + s9nh.!jhm0M@_?+]8oVR9`G[7D+M,/6sMY35K/`3kEVRm0'2PI>T>W@rBUVr[*.R)8m4;Ls + q[!^%D5YiK!YQ.Aa3OZe4%$p1pntQ_HFBs)`F<sAI*b54S2RZFa!2fH02(@m;4\1%o+fK;D + :'GrCbZ@[#m:Y,EoBKO<[SU'+VY2(Q2CRo\4]$V"+i#/+P+q&B2O1jdUM_IY6cOhs!\h%Vn + 8a/uQK\G@UCY3'>a\pJ"'R?ZrVi+B/JJtNWI9Pf)&2e-mO(6q&-b(8(XJF7G`'?>0U6]uWB + jt9F^Osl#P`hd!\fm\@#70X0C(gmUCZhpK`tk!s8KtAKrr_8j[UEN!t#FOeG^GO_HtX'j@: + <M!t#FOe:E%+$jp4<HchC5^]tPhJ>n0J(E+!r8p?UDI=MhV/-&TRpFJ!Hlo!TnIe3Y)TWeD + i*I;Y<6"-t_Y4A=un,\4H@-Z+No*btQ6[+Y7I=MhV/-&V(hg*;9YVeI7Ie3Y)TWeDi*I3"7 + 6"+POBDKp[pjg3_0QlHY3<k2NWB87`5/7C;(4`BZDpC6hCn9u:5Pb@%:fm^pNp`KM:tT_O/ + HpqPK`tlLf^>.3Kl%+=j0JcQ-nG?sa**jb[S^\[O$:>a'Gc4uj0-c_-u?4bQQLX+%k&t/;o + `7;DG\uA:6QcJJ.F%Z!)k7g:,=<"r7hDP6"'e]3k8a8U3Y#6A*)kpi"$/&^spKn;\CZu^)e + L`pAf\>=9,3nD+hCC"a[QRg]RI?@0)`V[<6MaKe:e!jl[]C%gi][eGEGs-<f'.HA)4O"8kG + n!LPqH>/GtVVh`IA4hr-R(4`C5RjTIbfHNIPIdR79TWeDiS_5h`dD?[bU%378n-=XN?n0R: + 3_K'Qq7-b*K>I[DZKLEYK>O53KB22:i"$/&^rY@Wf`m/DTEiWc4hr-R(4_O\LR/qop7`TN5 + PG/-:fm]ep)R=K:tRPZ?[hDDrh-IqN8ts8.;ZQ_.mNb.Io'5I7WJti2(7g&h+)q^!WJar!0 + $:%^VleL'tUmPg]RI?@0%4uT<m1CYZGp"q7-b*K>I[DEa[cKK>LsF4ltiJi"$/&^rV)?$Om + GIWI)_44hr-R(4_O"HPRG4[Rtb1T6l)Q-nG?CLYeM=:tY*FX8L`Tr'=`l(ch6V4G1N-cs>_ + q*oIP9$c'iWG98RgCphQOT6l)Q-nG?CLYnM8:tQ]B=aoc>rh-IqN#[+YN^7)hFXR!q#P`qg + !\eZEW3CEUKDaL,r'=`l(chHTCkKUUlh9mj&+BgX"^pEDmTBaJD:%\2k8rOl$4FYjYr?85' + XgkOb0N5d*u#K@OlO&c(_jDMB?8C^^`O7+J<Alq:H'\<7&S5S4hr-R(4_M\4/Wr1p6JI;T6 + l)Q-nG?C-[&0X1p=H9XSgEIHp_<C(cf-T8tq$adpqHo*oItE$c'j*D$_":?]UKpH@To^/-$ + om[SBT)YQ]?;r6POn6X^!43ONErU4kb28&u3(^c)rCJ<BS5S![ktcfsEZ6P&YqK`tlFo]?I + :(:HaEP95+$D^[.:,H!J[:UI@FHDpbg"+3IE!>nBbYDs5Y7"4>#^7hb2'"@&f$A63]lG<$Y + &+C$^"d$7-7YSOK#K[K>^c)rC5iVJYaYkR676NnbkQ/DkYQ,<Fp[E3U_NsHcnj<rW%>=tI\ + :'-u)&2e-mO(6k!8gUT!/\lZ\C@1UjgqYnci\Y_@0%W+kJ.^__H,kanj<rW%>=tI\Gc:@)\ + i"'mNk*i!8gUT!/]I&ZcJfD=*7=7Ta1@I_?*9`JUIn8$<sKVa:CGL2\[#miXYB^?r5K*h-G + Kn!PY83!"sKpc[:A^?IR`kLE>@m$4@trLYag9luh,aIcpgHl)t$^hl\s<mQ^:N8ll*[4Rru + O'Xh1XaU^PM2r3#d?_&^VDJ]N,G[/KP\X0fqGEs=sJ8ZheJ-8l=AJa^#A5Lo^h+<(Z!PY83 + !92R/\*h+af`l;1EDq(G+*rHU-nKoD>UrsG^MT]b?6+1"KDa'uHp_<C`6qJgVI\!]2f3EZT + \IX#4hruj(-if_[r6$(HYnB3]K-sRVYndCHp_<C4@%`1<CLh%ZdRD?9fbXjkQ/DkYQ4+=gp + FfTb_"Wpj"9EDdB(gYLE>@m$4Ge$eR!Orll/mi[^AOlVo]H4^c)rC^ooUSXtN!o06`WA9@m + 58'+aRGK`r$1j5TY-mB40^e$_A%7Xj=tI\O&3b%n"]GOb/Bn(R%dVh`m/D??el_?-^]r>pg + (jm'*PFK\nr!fIa\@=_BhCQCk&MY5>B[S.fT;-4qE75e0^0$\miX#laiq0G`"mOg``!'q;7 + 828]i8DL7F%q^5'5[f5n&S^+[`?'jt($JLRFBA:["p=s\"]BtsHR)d#e-"?]#lFm\"d5G.H + R'SbH=W$'/3hL35bYDI;S,f7]Q!%En(O52a-Gt>X@!-YK>I[]MEMT&0FA15UDk#8ZUY'.7U + ^l/dSR9IFRMn!04!6U!Q9]/!_FWJ7j;lp"Rk'e*XNqi'Ga4Hm#_8LLVa*9kK=p'dF[%r!@3 + Q>!b'(i#p?`+/.bSCOT9un_?(l[I4<p;4VI#M1C=C@$4DNE5C4YnZ:=t8O2:tWiPQ^n$Jh0 + dLk$K[('k$98-%U9@=_gE6oJ!Z/b*qD6lp\#!&%/N+Md9GY@`gu&69J\#c>\_X8.\+,6<H7 + Ka!'`4VC"8TWg\CYX\ac*Y]@q%/*3l8VP"_!ROrXQ9>jGZD"LQ2"jH?abdk9EnDT;,Voc88 + FU8Q7&B<#5@f;/7:?5SYt"jd#o"0EP:q8.Y3BipZNU>_"oNE4lH41[Vg<[RarUj35U\2A^# + l3bjep`U!MgP>$[@Un&jV>KY^gAT)qL>rSa5NI$aW>)#VHGlG_8-l5cUT`J8G`QCJ+<GnFY + .o4VC!c:ftLSp.,2Y%13JF;La+;nN52_]l[hH":umo(3%Us4VISWOT7_'_?00#YXd])*loB + /+FGRg@#@)[!89bJ!@(q>O`6QLrlsel!5aZ2!XW=s"G"!Y=<J4BOT5qG$4FeMn`JQsqe(2# + l,k%R+K81>+:db#!0AlA$abaR&c`>;=PuKt,6>Rh$4GW"HR&U$7:Cc)`Z>EdG#6gn)B(M=] + XXu7@)[s9b75Loin1YS_2]Q-[r.c2lDq635PicdJ,"e5NdpuIBeB@S?i4Ano,hr<fsAcqcQ + >9Z`;)V^GOFE/2qEldj.L6HjXU[]:@e&*Ps#aFW^uNo2E,P&.9ZK?gC&N-e(NXUhUFdioC: + -h1\.fkL9+b>Dr/,JUITOreh'g'4WQSZ%iWr;lI;u[QhULXh]MXHcOPHp`NfI?Io$'1J!mQ + eo0Z9kCMMFWs08@Hp.,1f/7f08p$*IYEmhM6r78>(54QRqN>qc@T%uO[/&Q6iXdktGgGqLQ + UQ5n4qWX-f:[@r&c;2aYYGZd#,B6l\@?1PQ>*?7sV55]OCmk%bDbp;p7gDhZeu`H&FQmVQ4 + _\VFaH2Etf(=CY\^CHGs33ZHA8-JjHLX5_,etH-!+&6S_E+eZEFRU^IPg)=(IgJ&Vu?L:OR + Aea-SmPqe>U[<5OZcKO)qIFSNhZr7/l(4\?JI)J;6Hqf^n9-3a$b)l&gl>okN)29fdKL38M + /WY$BZ#$1<foo5ELH$F_SreS@e6S)NV..siOl<#;.C2E#I*^OO@L^,,RP*uZt\E(B/]"oWQ + 0R-sn?nbi!RJ,.9uQS5NXs48&0m#_;+O'id4WG08A4c>hgZL$r7_7V9I/8)hQ/rr4\oZ'1f + =](=0[B7.=Yh+4I0'WK(OT9?)+:DC[^A?A]B0Yq)YQ4i(iY,<V:O7?@m+L3%G[^6)*V13h2 + i.LGp'l?o!;J-"Klo"L%ie^BX`$p=[&B<i!U1/l`9H*irM,D`r.fchG5hD3nH+#o4V@_t8/ + J_GHJMAG1<Z*W4aOK!%Sl:1k?"*4F*`5o)roe)J%9e5mIFhL`!H'-!4WQ5_VVr9rkJJ[mUM + :el-dQAdNjjr1MKb=QX:eXqK+Kgp;VgJ"ku2QFCgL9J@>5W==:17s7r/qIs=dL_O@/t=/Ga + B2+":!8ki?$G18lO/WO#.eB4^#7'6F\s0s?Ns1@dPs7tp,s4aeN%9BL,;BbjPH.K(bhu<>f + _SR&ITet+m];B]-9M[<IfcpM?#%%_ld'1?s@f=s"#$YI+lh4jXX68P^O](M0H:4`n.J5&\4 + epM.P^:;)?W65mV4LTMO-TRZBUuK#Ua\/nWF!uX#O+AC:liBfX%=T`iV9K4'%p*,G-Udg,^ + RPHGl\&<a+_d_c$oZfdIKqrS7W4d?AC.hQLp64Fo/2*%<^]BV7rVP-^FO9[(J2i(XZBOs%! + bc)&[/SfD#0qcfR4%08X?660bLP(V_obdn<d98-"I42heB7>Q<uhZWF<rP9tENE$qK:.5`a + sW@*pV8NN;@]V*d7dD(U2*W;lL\i"<>J.=6F0KLj?>J-lK-*m&5mR",O86jbPjkmBE_SUJ) + :S(hbbVLJjpMTHoh!Z2qelrshHe0(0;s9:G8$Bl2+SqMp.&Hk?,BnT\>-XgJ:OY(Bq/&_dY + ;`L_(;2TMdnA:#H6@P[!$oQ^@;k"-s+;Ce?b!><Ij7-UWSu77HpjssV.1;E:2iE2r>fC*;V + _u]PB;#=hkn-WKi(bB*rE?8,"qp;$6XFq(\[F]e_g/A\:4C(q4ol@W<l2!<pEW2RtY1bK7- + %bhiHXf4M\McN8r78h+:C<qnNI5n(tancb.h04C#C3ZDX%lm#_9Uc:)15o2e'QoZ5=K4hgM + F?)^-;CXpJ#[fF*n`&ZHEO%)@ImFoQ%[%0!oB(mDGBSP.9(n2GpYt"j\cl!Sl^k!em4Z4Q1 + _ok]JXQZ!a5+")IWqtc;k^?egUS$:eq4#cf&Y6]0Xbi=.CV7`(F]in(%e`En#eWP4gXNUhe + Q6D0S(GQqd6(C-LSLIhEk1JCkG*5m9on.TmEOnCUYQ;2N%Q]ip-m]4\om31cgp_V[7Cg<Ns + #GEi[_+ZefXm1`otg@]pco-PZeb!kjT>^mVC3'#Wo$Yk+TESgS[:+`3A7\LL'&MWb@70HR- + U;dCjF;kmG4l=G:U0^4"fuIXDr-L2UFqQ7MW@dYU8JQ_HEN:\SD'@nUIZY%R^e,LK9cr<OO + 64LhVXaN"8VY;oOYG]7`JJEU>D5:mli4NNH.?&hkM0=C#n.H?=n*-LMoWd++Rfm#B(Ok4q* + WcWI\G9VRuo74^GfJ.mLm-^1[CWGZ+XIkX##NGKCkg&6tb3mBob'<dIO_&)Y3a6fFe[`/dH + @"hu*XMff\u2de[`u..0@R/h?,80dpB&@)hi$W#rh-](\'11G*`l@Lp-,*CGeZbC5``LM]? + %_f!@4p3$@DXAo(D>Gfpn`f(TgJ*f)`=m'`DA*-tVr@lIG;ahjJlTpLe9FYX\a[;MZ*sU8$ + XCs7B6XRJ+AP3[4DpOQ>''O*a$de9m`E6qs6+Fm%'G54"CkX%1\)cLUEc!3)X'qX/RBgT+C + /4+f:OH@*jLddnR[pi:J/V7hrU="ijIiu^d;e5l96!:ZJ[n^p&%W46K9B0Q7fEqDFW6^3k" + R@3d=&+hjNmpk_H27c;PKDaI55Y?$'fIkS?['JEtO"3(_=ZJXVB"[mdI8Bgi6<i+f!C2U5_ + Y.'r&Y<uphtC%A6+o1B*`!j+n`SdMmO#.(OT6NGXK[,JhnENA0HT9_dG)akQ-5AREVhDKO8 + Lin^GKP`"9<_((:Ijt"i8fe#<5'/)*=B03hY:>rd797H"E$>J3\q*Yha"DN;RC3f<Ms5VPU + 9Lc0i%/a.qC,.siNA"@tY/mAAB:^>''>Sr,`$fA5]?,NINc)"=32Z:=s]Yd@]g:=4j>d8no + jKMo^QbHl5<Qa_H$lHZi0eK\h],68p#*`Ue!khk_i-U!QRPWf`Y5i9QFR[*m(cOFEG"FrbL + Ddc/A9GeiJ>4eQpGC(,Jaj-p].=3<?"P$e3m1ipo/j=`H,/+c)g"=8-lk03G49%\E9`tIje + QUW!dFCp<j9koMiT_#^R2P;OO/Sp_9#$Vki%?U8SYjoCdUO&lm,dF@PKq>G/=ETbrNl..#l + sDS'_\<MdhQQd>kF@Ge'gHQrV/D;2\Z8!l7P5!J\*nVo(>i!kHSi'qd7ci.fdp1(4l+P;N& + fO5g:4LcLNp6!5q`:"P.4M)Q:kTT5JE@T1cr0!2MR]M]hnc;V?fN_TU/"s5T:mo&%l60`WY + \_BScHE%XbJg%h1aWp8K<hdldc'88k']Vs=BATl'&<[[lAqMb\%"]8BTa<)=LB=;#Woui\t + heN3i%>@6\4KHt6AT0EQeT[XII_,VO.23Pko5aK&!L_*g4T,<S.g#2JKgeO\<iOrui;E"*< + V)j2mlLNKJANMC^7s+&AT4N-<2DgDId7#*H5%-gp9IRH9t!7qm]DNIJ(!dL!6L5;+piW`W@ + X=ul.S^GGt%Q=#U"t$=<r[JS#f_.T?6,<!-j78,&+]ce1?mK8P`:boOlTj6NB]7_BR+':\\ + GQZo#KH$buiY(<Pb"8p+*iSeqAkqTT9ga\Z(bV5KPu?J>c-+q)15$B&Hf-'N\JSm8IfH/K\ + C.jus3fN4=VV\2-7b>sV;OFC[@8-0J@amJCdbu'=hO"=jj0`]fR/5j;fV:&=0kHSk&\eorZ + 'G`.WObCKgo@/($+gM*,;-9WSO!OYI]4ZRoqAfnc]I5=/asWEgY7`nRpo*hS'L52d=JVB]. + b-g2FM@^oddL*7@74OdJt>f=Z\ndYV5`oH.K*9N&3:L@WTbk.\uPOd'A<EW[.LsF5e'WmUo + _lkeP4#41,IFWY=lW=!JC`474NXFYq+MQ*Rqg<Q@@-]#R^ut'_bR9T?.T0V2G8Uo\1-H-r= + %(ZV#@<nXiB?<TUtg^N0DY+,'k<T1\HsZHK/GqO^EqGl\$fK`tY-4L'lAO0=^qo)]1W$4F6 + ;Lf,*?rq"CTUu/oeJrIPJGPY,;%gY^!;ucDWl*i?s^nS'K>rJYV:PX+@Ig<ak:fuX^$W[+; + BHMB]?_uZ$!!7tn!r%"DWMqBHP<DVtr^-Ip$m943/9"rL3`i4/rq"niddL`I5so(3#C0XTh + C?g7QDXZA"mNKPJ3]g45T?:q.SIa+\o^n!r_E;1%3RVY/C:h$-Er>9ggF.$6:Cl+-nGqY,: + `]aa?gX;Ds@!RJ0:Mh5Wf\Trm(Ok>l&jX+:'AH&<F"F2-RtEg1@:Ss!@Wp"sArC!c`N]WGX + 321NB@nq+p7!2ZQtp(5UkG'=dAman=*ND?-sj/<GsQ.fT%_Q_`Ns!!H/$+AoIES>T.AFl>j + =mr8>*-nLIYQ]rDii]O8So&Ul7<Dcl6^b\T*;K8;sr/((#*.S;%$^c3=`HaMQ=3(;0qOJ,3 + IhWYP2FGH/VN4[c5F6i*"7R1^"cRjeJVW]Aqi@T2li;E&@0&=d7&^S0cfrqcjo(tHq]13Z- + nO<)EY[b?5*c#&JQ+sE!LI+nC4qK9r:ACcDg;>sTs0&oT3&%FMW]*-;Wl_!!Mfu.$Wupb($ + BjaZ1PXLJ3PG5@*<d0kP=q3dVjL55+o-1/^Giq?H$sipK#oF6i+J,^hXW"Y\:.ro/un9l1[ + @AY>JE;U6h,`Wo?&+1Y%o^9>CE+G`'?>G!-`3%Z9/3-iN`Di$f!@=LV8KH+&/hH3+*9%YY( + fHV(3N.\8G1W+u6aoFM#\&IJnjiKGb:o63u&%flYOTs0&;VQ4r:YHFnba3o#/J/9Ubi/q[4 + ?)@>g#GgM_!&%/N^cN(-GYYkEFm=>%UB#ge'Gg2`91nkTnXL+@aGf=>q1/O]+pn^&l9d%mP + Er(pp:l?Hl2J*%PPeM_?j25f]J`*qF-b.s3hs_U$MDK`\kdrr00^NY\3XO(YC0HNF;<-tO1 + uUa'%n$hH<@$3fq^Fb#6b)0'Gg2SC_b9!1o'Z5Kl'haLKr<a,!'"Y@K;3+K`ukn>eJtLq:E + A$HJce)o(8<-H9en+_ECa]3)E_m+3RVGB@b!r%k;Cr!^3PgpZ%hn+Qt4)i/]NAeOd`$IdlM + f@RdfF=ZrKGpMS@Fj<k7aHVmn\2_.iiBBn-0VuJi]_R:rF6b+QO#TO0ZpuX)!F]S%&s7=Ck + KF6HX=-"r`K<OUDHr(1R!eggUZqA;Yk"iVh9uV+pf:t"a!B%Hpr.G)K)2/7loMqa!W-HV6^ + ,+P=A6\MZ\ubeYZb->N6"'edX]=n]%kR23^9Dh<'6Qb<C=J[B1C$Gk'Gg2k91j>*0i(8.g) + L'9Pf:_Ph@inc]/R(/!q65E"oPi9`H*+#?r-*BD7q=^Jf`#($G]j[(@^4>ESXTaeL>qH^Q7 + n5Z7YY?BHH@>G_O!9,2uhso\:hkH<Sr_5H&.="^i4%"[kJN<'(ido^A>rioahMM/3P@kQ=p + S@0%hI4`KS6IW9n1Kl,5C]H[2;+$QV,9MnnWb3,!];_cV*E?5!2Co`j,qQRU60L9+J6/ts- + k83$`Y^OBbQ3[99kmm8_$O@+I$OHT=(!l^.`ZF,nD8eY85eJKr+DZdjH+IUa+8J]>mrsWob + :A)[-nHM,%ob[Sn,I.hff,da=7ol^cj+e<$4FrORSm9<k#o:&f<&6rl`[KE5;fWPq]t^9hM + ^J1^tgCi+E!m1kF=T@gki*W'%p*.jl*M?F7Zh6&.e*?$MDK`\k`D=oDp?k+R[QT4QkC18%0 + 2@<HHXc)]+g4c^AofPC-L$`UXA33XQ5t_/L.\o]ai=Y&=2DO_rKF^TOSM8b'FA`N+;l-$i+ + (Gm3q1+iR8[+:'#cnXNZfSUKD4[]7*I]&LqcZb$9b:D=?36#**t5S1T(<$rFPCu![XmD?<3 + X'/MP@UB&BM;hsW=3L.AmYO:$UTd!KbYp5l]67miY,mI9ZFB:ZC>McmQ@8;mS@mI*GY]$s/ + !/g?/.`@gWd)f"IP<qa_Z&\hW5eM^8sZ'pR?bBu]QdQI<NLsr:DAs'Ka!&QNr;`=f(CgICo + bRFCF]c/(VM\#]W1^8Gm0??Ka!'<K8Os.[7dR!=R@H@^UbfXqX&X($=BDV*nG]"o0=BC#7: + hAa)akLX-i(Brb7hu_VPX;nqmK3lE]hVcghEr'SQ\lAX&'t<itY&X0?g('6X:>5aPQBeK_6 + \?B%!EIV&ZOUTd"VHpGY5)&[.T0!2E#fbR<TlRL45/p]UH+4Q<$eUtE.7;,M"+AeYR$E@R, + ^]421*Yl+`A*r!Nq25T("n%#s$Jep8EWYd(YX$Qo;)(jiG&OPlgT"h17;s=3;lkbs:JN#R' + G^tChc2C,7Y[HqMA$QS=EAc,`PZb;?PEE.D6=r#A)@k.'G^tC0?<`%`BX1?/7/e^CTS->&R + 8X>Xg@)D-P-rF"TiA-MKqDbnKB*1D:Pr)6KE\]jgqYnn-!3pYWr3eSr.gip[?Ja]KnH]/aB + LBnp,N"3B^VrGQKTs=<N-c="6q`49lBL&^P6ngWM)sr**LD&n?RpKa!'BOG\=tq9AHh@D,H + OJ%`K=GI*&He6^a4jl\#<2@9fpdkV[0/7.+)]VfU[DHL7gDM^k*e<]@uo(*N.)heHIku0(o + aiI$>ENrC[C=cE#/jB$l</ZG^e0F)<-dXaY$O"r1Q0PG[Sl]9i/KW:6eR)ZhI`gC8$6J#`T + VJ_V?qjKQcf:&s(%5b/Cd$.C8p?UDTg0PF/.bp'HtR*]i/Zg91tK7N_X)h;(\Bug&IPmr_? + ,;]XGZ0T'W_jaV+[*:()mrG?]UKpTg0PF/.c=o<Qt%fs"Zr(OY/N@X>0U1i]>m]IYn1;6=G + Ef>HD;*c[9?7GTts">7#FPpQV;E^k5Hc+NQaH@\,#I\r-70]s=DS%16=>#Kon?i'AbB&7f. + .]fn/&9nhS2Z#.+%I[NK1oCU[k:6Qcq^jT'^+Q3*qQtQ$QLVskj;H*NTZcD%Tl;$o&'Y#e' + $O#6)(%ZhGX(0']l(6SVV[D6aIZOX*7:Catqk/glQ7_DShFI=_:X1aECp>$.5=gA&U9HnuI + 9slTSN:?3f<5udUeB7)Z4./1X2d*`FST&Hgl'#N_:M]+4T"h((/L`!OerS"&%nso=n8m5\/ + 0i&Jo?g0H2crEVMHVJ4gRZ7Q0Z0TZP9ncKa!'HNJ`"QG[d%b+5NtWZbW6<kO]&U=UNrB_?. + RJBbg6`TANS[O7(P)H.\doN^fQg5>HdA:fnk8?AuRA+tG1=\TrgP,2J,m1jc%SFkp&HS-!o + .YWsW/<\[C!IcqlZj!`_Be"EpVH@YoQ"n"]cJP_0_AuD:"ClW`^h7HjpaIobkHBe=e"n"]c + JP]IO@\.LcA"7cch5e/rb3YnU#2N%'U&oP5YWsW7To+-pi"$$LpX+kMm?7qc>G\sT:K67I' + G^t.VcCqsDHrKP*3H_qBT>Ae0Bb^m',A"jK`sg%AYn+][SM3q>'9L!nNONc<OB];Yk`UPr' + U_V6t(YN(ntK2S=Isp:38>DXu6))[SD%.+0%RV$4DO+C_cR>gV:uIn"UVOY>7&)lkS>LI]* + =M-nGoFlVu+"c#8UYO/!GVN]goLfMXk#I]*=M-nGoFJ#$PF:ObDC[M(`?>Zbl?fK;;TU=82 + d.aWda!b(Vs.csmEZB'5MX_=_AQb1B#8Tlu&Zi"&3>#8<D/7):1cficI`T(W)d9G'.$<s5$ + aNmkZ"bd+H,YPOng9jRhC't"?s/=,=jr5#C8.UoVX$@%"$\V%j?e?e[ITS^m<n*A;0IUb?* + nRLBj[Ui<WENrbkg"=^@tS[VUbghUXA<8U&=K8%Si>P3-ltl/R[_mkDDq;=p4huZ5,]&_=* + ;gor7X';5`[t,7hk9_-$i+]*dgfq.+eDIFRMiXo:#)j?$EF%?#"M[HJP:bc7W$t+@I!GR-0 + 5hS08qD>>!bA@8PTL\tAc!7d)g[F@p<;HFpAngJK$jrU-;?*uY.=Zr+e)YIp#,:Y9B$-$Q' + !E-&0>`5aaPV+G;\=/iY!g?L?'Ip%56!/T*6.d$QF-\dGDd?^8'=.2jl7\(tlZk4&cSQ;hI + >0e^Q"[_@t<6V[\9jdEG=qfSV[q10-A@n_NM9g$l7ChjP7:%Do&2ITm1!c@M4lje"chX)6# + *\GK*[!YU&ILI=(Q\,Z@=do^VqO<Z7O6=.#tJRc@Y;d'TLXj"D?O=!DP*iI:fm_4dS7,t\o + u=4c_<l$f2nFN[sHk:I"3H_,!,\(*oUC2.4c#o"'!KC=1;MKN#(MnT4fq6.Wl9l)3,iOW!@ + X;<sf=gcU\fB>e%"14Gst\3&KAt\=M6(`+M%2bP;=clb$+t+FGN:R-3,,A`?k"kZ[LSKAi- + "a5#ZGG.=06\td7+&el*P*ck?*o>V^W`3X,Sj3=uDo?A/Kikla%e"ec,ogg1q8n!;?=fPr& + TDir@GS]Zrgbmbm^0T."`90.4VGn)r-a+4"#bSLSk5##NVi!F\Y-MPY%H^lO*[3eo&L`ug+ + 5cW]@=don7)_:Gr8r7o-JEV&ic9\IQE/';IJOeD8@=f-,q(=+$pL\#T!*NQN-H$'C2-k;]? + 0,*Fu?k;pg?T'2!B,YH8L<Zd$B`nR-.+L)C=6.ld!1$eR6=$epYJL42aR0>*0loF'^:H&3c + /UR-/O_)^-7jlcN#J1Dk+#HC4JPLU`7gJBM!UD4TTUoIj)j/.aRdU10]ASerdq7-eS?Y:uH + *brS4>_F%.bmd;j6"ktC^hH\h+3c&\=n,0rdDlgZU\^GathRKf&WbBN)JjgDe(6kG]=*A]R + q#drqpWb==BDT0p;u_%#?cZ"O!:frfMKtBL&[AG^bo:[^RsYos6['+anrQbI41JNJiEWimQ + Y2f%DQDhG#(ZJs:;o=;rpV'#+F9_lcO>F4GtI`DTCWWACh(#oebhig?F1C^#aN`:R-0T%#) + LmX$Wlm7)GJ5YHA)'lLPShkfO\C8kKIu@U8>(ZW-hI]4<$3N'<e)GDH<nsS!/gm;gd<:B,/ + "ebIeVYRbZ]^nhF,Y('p2g<6V[`<F>87H6TXLDsIOY;0bl['-I#=;iU5319Yu,9t4?6de/N + a_?-G%'c$<k?.qrcL>Fo)J!RpX]Vl'kc[>Mb;.mII/oe"(WJst1K`sg),o-$qTANR0Kc[3U + ]@^Lp(?eWT@it]+/sdF;19[%)5@j!n94<BJq3m1dk0E?;SjJLfhcO_R1[B11n_k!#Pj/0"o + 31e[Zq0cm$4EZ(YH!t&n`$AC>@L+=N_'FbZVpN/+9(c`2;QMg?LtX#CoCWLn)[/MJP^Vu`B + 4Yqgdf#0hRRlUNksd=Y6Tp1Is@tgGK=j=>b\*CL"2M?K`sg)9.K(,[k9\UXjc95a\mcMRA\ + *p,eG>QXOGuYQ`.u2@/K%X@=_7#7`@L)pNt#mEM>n^c*_0To;:q(*WgTI]H6,hYGM,.7O#9 + )I\j863;o8&Gs:kojP63VlKfHg$qBFqh+Kj5n:L7Men&.qG"ueP?g#7@Q,3Trnt_.g*d]FE + 2uhe"dd`)$VJ(f-.c(5/kC0s0mcO$tQ:k%V+T.g-1!ca^SV0eB]@2atb=r2?*ZNMki^JAdN + B4D]ol>nhU*ZDE<[fR2.\BTncVmUci=jl4eC:]Td:ZmsE3=E'UB"LB3iuKpFd^jeUN=+rX\ + r7D<'I!bShGJ"P^!>E<qQ)BK5l3?pCZiqCq6A=\]jBM2lAPm\_QRJ@=]]p0bs;mnA8l/!da + 8)qst7DC69Pah?@#$?$CFZf=\4!)JUfUQ_:QJpcYWdSl]59-XK'AeQcEh2HQAiL3O`s;S?t + ?VoQ:um#?qH]ml_R=<LSoX-i'graq%4!PK7_hN7K#acl(/kcWorJ/c`orN%(!19VF*X=op5 + YX%tpX-i(j5Fs<15Tc6WR:.dQ0BmrFNIVraoK\agF^@);,6#5I.4c#[o2Nr?IJZ.sr;#8Ch + ElkZl<O=E2Zh"%lCKX">.AXZ2p3Kq/.d8/<QoORTQf;^$]qs"<G"%q6+7L\"UroG::]e9qk + )OumcIN1Q:k%V+T06XR&?nH@Ia9k+gNh@X3!l:f5u6,=<LI8\!KaHEd7[iH#Bn%Y>P]8KZY + DPo2Jfgp6T1(cL7B:0P3!'!TLdX6ED`)\9M\Imk7NF$\V+_eb87[0jQnh^8X6,fO3.ild=_ + 65XNV9?^H%$]6fFUb9\Pf&:PX!gLp$6NoK$h9geRlZ[#cQ4,?r?EOqjU\BJaFQ3m4C<_L(n + .4c#O?W/]*o]b2M_rmqLSWaIODPcbM*Y--+c>naL4tN%nYX$9X;8kZNftGA*kGPU1Et(TVW + ?*VI%`B'dZ!?;Zqt&oUT+i%HO2k8EPOsoC^WZ;uAL;nDW5h;JRWq-F[YoH^bIj.RkM("`$4 + DOB#?B">r:A%FpA[l^FmI7`DlrFQ?4aK;;YP-uf7NCRS<o#pl]]0ei=X,Q`:&+mWd+2aG&I + %RKCO:WpD/eq*os3dk^L'1m1o.EL/V1s4D(U\B?QU*=IFE3ne:U'-?-42.c(cm=-LpK^Kfc + 5i?Ien-A;W?A;#hchLAnt[Ri4(A_@8$fXXD-k]H?`i*N7+Ls*G;3&k.?AP$<]OGUA_+tZO> + e>15RVcM'%ld'B&RD[Q99=uU]b@TMMAR<]s0u\E0LqbJi/.a.8="7L`I0L2J+?`V5'YcH[? + kesn^>_GpSXeS_>imn^bCmImX2JA,'G^tBc`<FG_1J9,,=P)@klh:?pm`BXhA!>3d-^C00: + 01tI[Tu3Ohq1Yo*H0'r6ZSqQ6%J1C+C>`)ot`76bFt[(#A7aUkcS+C\c)Fh<%49JWTY4(%Z + hGX(.qqMMt*tL>:D#Rp>OJY2XH;/K;kZMVjii]F;_cMSG.f![4g6`B=1m:Xc+0MO9R?1CV9 + DRI2^L(KBYe0(W8NI8]+M[GijVHVdfe,Y"i%kOmF1=0N%DR_QpO1)K5<idFC<Fh34KjV#+n + `n+I%+oVh]*srC/7$`^U/mSh0?'KfM=gc[o4u_\Kig!)<9fg2f--,*Nm$7L&i\/%OTWgZu4 + KDq_Pl7UWMb%AGrjIXfo=7J;(Cs6_.b0/Wk4O,I/Fh?KK2G_n$m&>%cg'&/V<<]>o*8kFN9 + CXqTQk-J;haZ,19ZDD-3n.n`-kKb+:M;OR-3.8;sUDDpSp?bfO.>7ld=^o8O55FZcg#D]f+ + h]eOo@5?(35n&-apibk%SOc&eME_Wn1'S'C4Zh*J\5.A]mS3ks=W/F9d-V;a/===>^3"p7l + LF80_D#EIsS?_;-gX0:f[imC=<dH)"Y>it_-nV>%iCiQ,P5i@&rWHP</PF7h^o4F(KORbur + dCBJA\l91UmnW-re,<S7[HR!l_-8O3?PF7]][*REB@<TYd_d=AY*CUsR+Q\1N,rDRSt8o#9 + m:ZHf=\4!)J[iZ^XD+/@=c5k4VdR9pqq`[LIiUFeu^g!gU4VVG^Y`]SaMU&I^qjl0UGGf(P + N"oDjH9+ro,RX8.UoW34jNp_<A&K]u:)<gmWAsqrJG*\I6>_@#:P\5iD<81!aX=L#U)_5Eq + e1B/$oTohb/_-+EJlONY;.c^>N)K];%D<YQ;T[MP0#;f/0!oX)c`Y^A4f\`ui@-@buma#Or + =iYb?h=*-*^GqIZ/WMt?;po>o2'G^t_5>j5^Zt\?l-V8hF2m,BOa^g--lR_Q=,pi</-#tr* + YH&#jc><mr"P[B#o/uj0E9Tq,/B.'Q2]1T:]!$@;P)l0q'#c$mXuD%<Jo-m4H2dJDB1bs_@ + &Z,l^gN+ne&0.OP[kt!X]Q*VRFea>F2_K`VC3u,?sei*CVi)Ec\CZ\$\#%fo!$e$G:pDDX- + ?:1l$b8VHLB%Wbt[/&V*\UA!;i"<Gm4`C-p:$$-doXNDp&99H%'%C'sCN`E;hOsju$,]-16 + ].!Wa(W,BY&UFJ/7C$)5jr1JRj8;YLt<;f[[HQPea0YIU.B='s)cIj)?i@=\CtULKh`IWr* + i(^Zq;"cEedHD)B/hPMRFXOGM\&M>_E/'`f`\\rnn=<OPKN9`j`!sb,_O-(Qb]=,juYW(ch + ie7`O$a,ghPjFfX.jG!CEfIp;61n(io5s5[g"7.E/N<YXfKRDb[TD_]ie7`IX0.d^'^hJ2_ + W;F)7:Cb?R\sVdN>qafc]I(rE,`8%Ge]mVMFT//C3?FZQb32TO2"i.;Z+LD$&&P7WgATgrq + :9.8C*CUW[_1]0]DWrB^niO<0PTYd%aiP^fI%2/H3esLVa+DoQ_1taj9.>YRf5cC\T0e3o* + *7<hX#7\\s1hZc-90<`)sAOOgJ"BAC!JklDE=Ks+91R.FC%:[qhH::]fY19Y>7:C6W5M>O$ + O5Tl%d1!f#Is4FGXVpL/W^Abg\SbT+>dM"iaCSF/n$7:cgpiF0u5L0)AeUi"a?SJoGa\NNL + GBlcZp+#4XZ=V32:7LFb^Roa>]oo>/:bO`+bZd[_*Yk^L?`L:Hr&OdHg+0*#l]h%"`KMN29 + E<l0@k-X*e>ZA`D6<I.#l:O&W;T3^2dT('k+>Qs`6/l&or@uJWM^1(K^Z;>.m'S7.:+%j@0 + 5@>ZW,/TG3rJti=V+Ar>FLB-1RD<94a%%.hmH05%sH+H`%rts00&==o)^hebT4G@3)gQ~> +Q +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.svg b/testfiles/cli_tests/testcases/export-area-drawing_expected.svg new file mode 100644 index 0000000..639e72b --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-drawing_expected.svg @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="87.435127mm" + height="72.5mm" + version="1.1" + viewBox="0 0 87.435127 72.5" + id="svg10" + sodipodi:docname="areas.svg"> + <metadata + id="metadata16"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs14" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="640" + inkscape:window-height="480" + id="namedview12" /> + <rect + x="-1.7763568e-15" + y="-1.7763568e-15" + width="50" + height="30" + rx="5" + fill="#4169e1" + id="rect2" /> + <path + id="MyStar" + d="m 85.96,53.703 -20.799,-1.1756 -12.76,16.461 -5.3089,-20.138 -19.604,-7.0445 17.518,-11.27 0.64404,-20.815 16.136,13.172 20.002,-5.8198 -7.5458,19.411 z" + fill="#ff0000" + stroke-width="1.5" + stroke="#800080" /> + <rect + x="14" + y="6" + width="53" + height="53" + fill="#ffff00" + fill-opacity="0.7" + id="rect5" /> + <path + d="M 41,54 A 18,18 0 0 1 23,72 18,18 0 0 1 5,54 18,18 0 0 1 23,36 18,18 0 0 1 41,54 Z" + fill="#008000" + stroke-width="1" + stroke="#000000" + id="path7" /> + <rect + id="MyRect" + x="9.5" + y="3.5" + width="70" + height="60" + fill="none" + inkscape:export-ydpi="600" + inkscape:export-xdpi="600" + inkscape:export-filename="export-use-hints.png" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.wmf b/testfiles/cli_tests/testcases/export-area-drawing_expected.wmf Binary files differnew file mode 100644 index 0000000..07f7e13 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-drawing_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.emf b/testfiles/cli_tests/testcases/export-area-page_expected.emf Binary files differnew file mode 100644 index 0000000..1a8b98c --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_expected.emf diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.eps b/testfiles/cli_tests/testcases/export-area-page_expected.eps new file mode 100644 index 0000000..acb7604 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_expected.eps @@ -0,0 +1,443 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Mon Mar 2 08:39:48 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%BoundingBox: 0 0 340 298 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 340 298 +%%EndPageSetup +q 42 49 249 207 rectclip +1 0 0 -1 0 298 cm q +0.254902 0.411765 0.882353 rg +56.691 42.52 m 170.078 42.52 l 177.93 42.52 184.254 48.84 184.254 56.691 + c 184.254 113.387 l 184.254 121.238 177.93 127.559 170.078 127.559 c 56.691 + 127.559 l 48.84 127.559 42.52 121.238 42.52 113.387 c 42.52 56.691 l 42.52 + 48.84 48.84 42.52 56.691 42.52 c h +56.691 42.52 m f +1 0 0 rg +286.188 194.75 m 227.227 191.418 l 191.059 238.078 l 176.008 180.992 l +120.438 161.023 l 170.098 129.078 l 171.922 70.074 l 217.66 107.414 l 274.359 + 90.914 l 252.969 145.938 l h +286.188 194.75 m f +0.501961 0 0.501961 rg +4.251969 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 1 0 0 cm +286.188 194.75 m 227.227 191.418 l 191.059 238.078 l 176.008 180.992 l +120.438 161.023 l 170.098 129.078 l 171.922 70.074 l 217.66 107.414 l 274.359 + 90.914 l 252.969 145.938 l h +286.188 194.75 m S Q +0 0.501961 0 rg +158.738 195.59 m 158.738 223.77 135.895 246.613 107.715 246.613 c 79.535 + 246.613 56.691 223.77 56.691 195.59 c 56.691 167.41 79.535 144.566 107.715 + 144.566 c 135.895 144.566 158.738 167.41 158.738 195.59 c f +0 g +2.834646 w +q 1 0 0 1 0 0 cm +158.738 195.59 m 158.738 223.77 135.895 246.613 107.715 246.613 c 79.535 + 246.613 56.691 223.77 56.691 195.59 c 56.691 167.41 79.535 144.566 107.715 + 144.566 c 135.895 144.566 158.738 167.41 158.738 195.59 c S Q +Q q +82 59 151 151 re W n +q +82 59 151 151 re W n +% Fallback Image: x=82 y=59 w=151 h=151 res=300ppi size=1190700 +[ 151.2 0 0 -151.2 82 210.2 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 630 + /Height 630 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 630 0 0 -630 0 630 ] +>> +cairo_image + Gb"0W#BX56H/SW;NF2j8'mgT%fW-Fo?>[`Kjj-sYf3!(&ekM#QR6&W*m:?0DCN%d!log@ng + IYG3j4uA7=i;XaU*TF6OePBG!['c?"A'.-5h*V/*(Vb8Js_u#^@shccMZSk4#tuX3"&?"T0 + Fu@k.*"V<4i84P0\\XFfcXDRn*BF%KI\$/B@.ak%je-g\s&182_86Sn`+j#&qE/[_f3IqRJ + QB=p4oJk'H^?f%/)r$d'kKJ7M,Xi>N%2+K84?\;%j%888hSY+`'"OrB%.CFC`aUdeeO)@?i + pWDQd-L;F!_C(qGdTs+N[)MNl\-nKnE7Ub6o$4@uU;-:>__?*8C'GdjFYQ0h)KnX:j/:aNc + @Gr+3$QuEG=La+&!_@&?(9X@8!0S7SKki(fJ>>YCi>N%2+K84?\;%j%888hSY+`'"OrB%.C + FC`aUdeeO)@?ipWDQd-L;F!_C(qGdTs+N[)MNl\-nG@6NZD5HjR?XK+!WBP(9X@8!3A3NqY + YD=-\hZ%peMMa$4GH^=9-pBfK\hp^-CtdIBsEr[8QqcM$8TeCFC_6CJMT%\#llCDss-<nAK + A;+"8ZH$eJ3W!7p5D3iBZq@IJ$)I/)n<nXlh&'GdjFYQ1cHff/fR_VV_DiirRn`IG*e:ft5 + ^_?-t(X]K,J^T\:t?^iSFZeZ"CKki(f!,LG;\`:P]S_c1$@#c<nqa=lO)@?kfRT"QGhQ*kh + B3r_EFF9MO&,AC'(9X@8!3A2gB1=8&%6M1=dZMG*`.-&o;-:>__?-t(o^:t7(Uf=,<`2ar\ + ;%j%Yib=YdpabBfVt3M*q75)Z4n(WTs+NuH$e/m(^h9c8MSa+.k)kt>XMp#=EA(eG3jqUa[ + umI$eJ3W!7m[n0dX!>[]Q>broO<75;S"ICFC_6CYm`!3UXbuqkSbq;GRXmY](&*"^oS:gC4 + PfmRiA#/%knM.4e^k@0'JOG3_QV_M4W71$-ceV&oZ\'GdjFYQ1abkH(oN+tG+&*qFD!"bhY + G-nG?[%YP5U/?eHRHr9ruKki(f!':\OXL)![EuqK[TWiAEK`tl)_36B#(A@IVZ9,a%8O6eD + )@?kfNc5Hp(A;!D-,kukMd?:d.4e^k@0,##kkHq!KtYamPnXoJY+`'"lo9*'W@N[^LodCkj + i=7&E".L)@)q6$/f$A3oPR`2;G^K*L;F"rj2d?/Xqp_9A0o3'gFF^$/6kPN!SDDQn7&j7)g + 6DjUn\/:[.n-0=La+&!jL_KTg^":[Z/7k'GM=cTs+O`#iAg3<nOWTHgRo1TWiAEK`tl)Ylb + BI/F9q%.k.b7*FIsua/6([%>=sna72)1n@5^cDEfRXnr^hM<`2ar\;%j%YiGKt$bS.ZD-JB + Bs1^JkYph5/6X^#JET6Ze151]A?:dFki>N%2^lB**k6Vn^m-S*-$s$8&=La+&!jL_GCNF%p + )tqR;abPp0M<i3ZY](&*"^m*g@F+7:Fs@sp8dYn5f2,QLG3$:s`up0I]$"+0chbn&lmjM5/ + 6kPN!SEO@Dmhq=)g+WN<n05]:QMt(fi*6pa0Lk[_SS/E(4[ED]e[d(K2"Bi>hH9,SQVo3fS + s\u.k)kt>XMp#fQ$3<R0F7>d:mHO%;XO/V0]Z-aI_3GWUlAh'GdjFYQ4#L[<I?k!CJoE]s( + r(s(@$,A2ggW[SAsTqYY^=fG#+(Ts+O`35&t962p;rCV)(P4',4^gY'(0brY>p#B.d`=La+ + &!jL_WmV22l0:^E"$QE-E]B/?uFsD?\-,k`&n,'@=/6kPN!SHr9Y,Uq<02IYD=(0"8FF(25 + BfE?dCk)IW$470m:fm^@SCnd(@Dd;gSJ4!Q[VT]H^<^\-cY]4tm(gL3+.L-a2&$gV*G8^$N + ]2-8H>MbuD<'nR$470m:fm^@]X)*?]U::uULP`h=H2`WI3lks4jsr(XJE(>%>=sna#i$'a4 + n,qH;oiW%;X<r_F:mPg$jFaQ1EJREu9ak_?-t%m']LU#-M'hN4lGJXea$bBlZqe$L(EHKLB + 5LfPtfp`-CTKU.<.%fSGbBH@Xhmk&-`7/UroT1e-JuYQ4#D8D=;24T<4SG!l#0^67L(n[U6 + r]I+)F-nG?+%cj]J.dSjq_R?SB.'UCJU?(tbc1N$Oa"e83K`tl#_36AXMH6U0)Afj4SWslm + ];OGqc=`bW"bd+f_8-f.9n"gtLH$`!CZJ%fiVt-G,Fc;^@TCM_l/@R(5[a[qE9Of'@E\=OL + P9Sd?2(`Gfs$@_$X,pW,8u,&@0'JLkkHocMI"ecX;&*#ZB?Ehp.C4jK/8u9H!;'(-nG?+%N + eniEhB98g+$o@UC/S$MI)n.E-&/RTLM1D=9'*V3O6Sr?^84;`PRA;kgTudR,,jGm?gjOc:S + E\TWeDI3-&Q76+jAcIWc)<@=KTBmCs(">:;Y;&NCI?J-AFR0/CW"2;Ql<_VS=qZ`L@+-p'> + BPn]#ZK`tl#d=VrJ2!_a@j&0='l?-^4*c!^?`NN!SXBR&8[h0;g(4ZS/%PBRD<gE+??=@'o + =\4ajF)p*e<RRW]JO!WE=E+2R!sZ05f"G<?Co_>%.;kA$Q(Hk%57.e6K&^c%0M'_gS`P$'g + OsL2F0.niX?:,:.k/go$4FY$'5s6P[RU#\VQaL:[oZJ[IT!s#1R]7b8V)5^YQ-46nbRWc6I + kAhSe\^,p.C2NlROCkpLZ?`Z]YA1U9FVK34XO16([@`2_PQn)HfXO;;Z"FZ?\MYh7U+"HC2 + U*-nG?+:;/X<TM;n;=-!aDVGd/t)qhHQ1CL#A3W+WK!jEg1eN!h6Wn3X_Kl)gNUr]mUP2bK + KfrV!b*@NH=$Zbsc2Fp`@cB'MllanYr`n6:;q,aIOf!:G?D($q8$f62@Q9gS#FLkjg_jY^O + M&p(aZF<n5<3hYgRjflg.o*c?di_-=^r[A#26rC>>S"7^g"`\CY88dV*q'Y1@0'JLC@;R`' + "-q&n\V_kXJE)u[O`pXOrf;\@);(jdg[30^4-i8CV)X`c&Iu&:%dhKk<,P:=9',,hJH.mnZ + '<!UWti;I3lk(m/!_>d\@j--nG?+hVL+AhXomnn`!-RRp.Blb#h5tKIAAO$dS+/)K0ijof2 + K5hTJpTcYd:>793<>6CXc`5.j9l!Ea='V<iGb;kV0gQa@EgPn`9G7eYj#fe#q"UduO@(4ZR + $G"d`O2hcR:GXadX`_),_I8a9?OYeI;!"7Z:4ur&^kgAB!NN--ZQ0R=O,FcGhEp]-Wd_d.J + TWeDI34j$*]V-e*,K0a'Mi^]5d"C[S2L"K*C\`mak<I`k@0'JLG3d(k.oW04Lt=G+0!1oT[ + IDkI"@cf#=CBLB;E\9tRrNF^,t2nR#3c]7,nq,F;[86gHU//UO(Q%nFF(25BfE=$];Mlr,! + f(.!)=QY=_U]uMu#X-@N#O:e2#c/.<;ml]MZ7>3X;mL_?+]Ai5l]<=h1>`M!*2'.k)#3$4F + YK6RS0="Jn6%Kak*14fki_\8Z*s.k)):Ka$DaU#X<)C3!Gf'!J)uDQKW^Ho\gtk$%"+^^:D + V^o>5lQC@_L<"B[=UiUFTUr[ms;GG+;krQU?$4FYK_ag%1FQA<#+PoU=696FjB<`CY<`11G + $4FYK,=`Lg7&3`T(QY=[Y,nEYa\%FUUTa`g3c]J-5sDI:Ic=M;X%mjhYeH:[F]MBC(PN%Ne + BpVo)RSP9mN^RVlWdUbEU3I9kub_$Ka$DaZ%FBWXjXo%KBS&O::[0UfSqF4.>!Dn!c[GWJV + =<Y\=n8+f?c\4F^MbC%BDJ%TJ\!$%E+:D!c[H"Rh$A.U0;2dGL0>I\jsL%Pn^&"B/V^>[VS + c:=9)):Iq+$q/8jaEiXp9:KC2X58)'"S.k-(&_?+]A`9["(8l;Y$M\j_B/NWQV*bI@:GrmA + 'Pd?Ois!TDuVbZTNB97t]j="gI.k-VpKa$Daak,Yn1uahh.NL]K<U24%.k/W$c"UnS8HHOo + @0&?QoBI<J3n3Ihn`kBNr0N9B4k=L]Mt^"c]!Yj*-0Pno"lNA*^=`^)B[C&'PNP(f<`8#IS + 6U8\Q#o`>2[Tr.WOMTG1?_&gc4KH8#e*i4Pd$=fD^[.:VquaQUp/*)>s*:^,#8QM);27bS9 + _33n.Q-:^o:7ZB,]j(7Al#U:6lhL.4uU1e^DNOT6u7-!c[GShAHML#jE&n`eeK\)>7-0m*0 + FHAgN-Q:fm]mS_cNc+9^\Ho82tMr'c%+h8naGQuqrJEp:;g_?+]Am9S3#9gGkQ+J(JuWRUn + 67Q.@-bQ@%I,WQ2>^o=ee9oXAlkNd-I;=g8lSX%5fMM+<)!B>46B6LqO^OX1EUg@[Ll7mH, + HiDQ0NOA)J>EbR*/-)Tnm$JFSfFN0o4D4ZCXOBf6#eQ54]oo+QPnXoJ5k)Fm@rf4<^IXD$D + jbNtF@s(bCcAZ1>:3`1=tEsLA4'c+3-BCkgk@np7u<#FkH=,7elPaS4uJst'GM<JJ=PFR.G + dp/X@J-qbl?sM[sU?aDIcDsR*emZP6*-`J7(@GF^i")^/U.)moLVglAY>c=&SD,^/_RE\j" + 5d_?+]!@)u^%_o1RM'Q1%K-t=P,Ka$CM#BEi`9_`Q^`6/lH=*6a>OZaL`8J);HP0Ql*UTa_ + <3I#Ru_/(dR6cGN030BI?QCek1naPn2-<=#@=9*elnAK@"_1"rd&J%nR\Zq<lB\uci;G^Hq + 5'6#`14uQT=Uu:O<BrG-Zr0'BDIi?_:9M:9;S#ATLVa+3jNt0."s^fJ%hqf>E.rC+KcXb`Z + FO0e?HZ\$SYQBU@0&?.pui?CH%&0m&FWTF<U&AN[\"71Shi%L_IoJh/-'$:El=cXQ+F_TTb + ;lK.k-qQ2b:D,0i1sPNZ:'lfO0YFec!GXPSfj2HEeN*2mNV!VpneMOj6l,TWeD93I5A$_$n + )Uqhhj3@>%lf8WgW%@eGFddY/#h$4FY3UB_kt(uSE*O*I$)$nEe)LVa+3jOf$;#,D'MmOb$ + +`)EFX=C4X>iQs,V;G^Hq,*'G6JAL$Delguq8k<j$UaUUN]A_mUkun6&Ka$DUnM_4#%.0Oq + Vg+.5PoD5&nm7ba;mAYM=FihJ!B>,Zp%\e*]12N+02VcYl'*]EJDJ;PP(LOPnCWTro*iW]X + mRg5TnMUK8rBq7F'>#X>F*,-nA<<!jr+Zn>Ip;KJ<E3hmT*_D-,o2OUnFpl]O4dmHCZKkT- + WCD8r?j)=%i;2s!TDu7rhq,@kaVrF;OK>,`e$^\YP#5NGS$kM)S%n8ghjG-nG?gEq[a9R*U + aQ6bGM&k.9tr2mQj,V\c^p`'`Zk'Gc3DDnRpL?ns\*FRe?9Tc2`3htB["dXs?F)gPYR_?-t + 1eB9WW`cAC\'@0BnC=$7DoOtk!AL.M6"lP,6HY42>jH*+KDb\YpdA[rS0Y<IlgG,\)S<Xd& + (4],WpImL_aK6.W(b7$`/-*FH]mEr<UKC<RmL*p5elh]J;B00m"bd+fa4n5'`r-iF4^L6'B + N))j$hRQ5OY)$!H=Pbll+6ZkKa$DUR@S=62IDLY0+6LEZ'$;\fAsMYX/#hFNktj:jNL9MnW + )Kn4]XZq\<C,I.8#bN,mAu+i5duAVSkQCMtC]QVVl?S-O&.]Cfku.]HgfT6"'dRo$6sNnP7 + p3HB`YKclk>K;Hu1@X/.O25PoQ7Yg!X%'Gc4eZeHhG4*$8P8F_r&?5ds@rKS(DZQ#p.CF)D + JrVFtrm!dpP(Ok$6LD1MSR<)R[`]J*3oEauITG&n<oqK1HDIi?^9Y,L`\TmmS'aefXY?H!! + Io4<,\(@k^Gj)W.;pU.p=9)qAL2En2/fkTm<N5lMNGM_9R0DRj['$rJ_p,LKjZ2o>G5^*,& + h#:2-P#4=1`3P8oJ#f_+;WKg/!#r0pWuaM2LN,?H=5mGXW@F5.4bHH%N6(j9FhkV#@^Z91C + Njm]9,8VlEnRb5d$mgs4s@Ab0#Uj$OV&Irs1cA"lR>8P:I%Glm4e_4<0/_ZVE$u,O@lXJ*5 + n(b.t*S#lf=GWd)Y)_m=En`UTo0$4FY+6cYN49\4;J=M,Q.91YtF>@0t,FlN(g`T$R'QVbl + &gUF4r()4FppXV),$c';?a-RZ;T$)GAGVWYLZBE)qgTl948^UeXiC<([MaqFCm>1XTBG;54 + 7>HpU24-K@HD#L6@&?\CbLbe@7^hB;),9ei-,UYT>[On9o%_+RYJpI5-jg?t,tEtH0pk(g] + "`J=@'!4<S@?4q@Sc^"WmtG5Y"$-:F6UWu]U,/FY#8@%ef?cVfO48Tec!EB!@QZ+8Q"Wh8r + C&qfn=:6F5pVn6=Bn>k31bm#*\5=mOR-"3#DR`P4^;)S66C1D6dKu;"LQQneJX#6H&@F)[Z + tg%uq]YcsZELf6tU'!%T6D.4d\4i8W_K/PUCh;Dct-]3`"WoYA\\^1BZ?!VjL9K*r,8:R1? + "Sd*j,`_),_I8c,,;Z(5X`#eAb=",[#l]*!1^gQ`gd(RB0!/m:g>,`Q\2c'62-\k&,fBqkj + V%>Q!AOBl,pqcJZ(Doi;C7QXl"kXR<.2@/jh*U4@STl`9;.j;HD6CL^WoD5(]AKofYQ4UZp + _tQ6XjK;MMZ>]G[#uW_nn4SCC2U8a'S=1'n?!A-cSq4R[CWtp$fDZ,<`7^VJ*3S."+e;jE8 + osXGm9H[4G:[@!;Al^;N.nc/%<:*lA#=ckVrNEI;Zf'9ORr=3;M95K?81-G87:]>iistMP( + 74_I(_YWc_A@d&sKCKi(qP#'+%@@k`N"Ff'BbhuPc;;YX:T*dpHfW7B]k3p#1I!^d]V"^il + ohe[pJe>P1ALHiFKUO-*M8`:cM5M?9(X@i5)dcheMnL6!h#Msc<QGHhkGT7km\Zq;a<qq_S + Xp<SBSq"=Wm1=sTi4u=YB,V2WAt:84p>I;V<`4/n=&0,%&[(DJ%D#36IrG`&^k#F29ti[9U + /T$D5!0Uph7KBdLkd`lD7?Rr3m6SQ947i\E,*^@K;fUIGAB`SDQKXQ6a7\8WVb:/r6RNZ"l + R2\h'RgjTCWUnVn3\r?:eQo^)g@QLYgCkXSn05_?+]7m9O`#K?_jY`.pHc2<jaBgFF]mhQF + H\*Gl,k^k&t=:,TO[&>/G'(Xab!oFS"%7er@0/JJtN"(tr_Nd%uJkcs.-*BrHP8r>quVEtg + iZ_\59U9FV;33sjtLKoV4SG6KIJ%31TU?u/Cf6(GODdcRH!"QZJI<)t6Y=O]iTBbp2#2LU' + Wj$ra)UhRi=&E'"%\2>jpB*I7ognV8%_l`*W>G1\a1&,DQfo#_F[)e]ZE],#!c[(6r6H'-T + s3aJiC]"$BA*&tP6lpHi./X+/ChZ"7j%XY*6K+";V5+Zi@50B^siC[_HtU,j@:;>XBoNTkc + sln>qOMm?2p4M/JJtNW<5.2%17GZh^:Ybi,=aC'I2@>1EAT(2%V/e!)j+uXtV8?p`;hPoYL + :USeMa'gXQd2=9,3.Slfl,fQ',CIe3X^TWeDi*BLpYTWjdU+SjCiG_!X40Qm0C;M2hek^i< + "&+BRQ"^pWbd3T!N]qPbQO$:>]'Gc4u,=`Lg'Xgp6QQLX+#:M,';b%<N1+;Khh+rLl!?Ro< + !)+CroUnKYYNnCCUCZhoK`tlLfKk_<<pAK3UCZhoK`tlLfR\_\KtX1,acAX$!u)N$WT.n\? + r5KjSL$Ms!"Vn.!2bdkZ,!$:2g%pld0FoH_?)E6iq<*OKrrlgj@:<M!=B4MeB.[\$jp4:]? + ?7!^]P8dJ>na9br$p9/O)HT)mG.8!\fo2l5YGnf'?$*d0FoH_?)EVZZ!9<@2j;)q9]FlJAM + @Ap"$i[#)-pB)=jO5n,S.G@-Xk\9a]XVe)a(AhuO/m^so?s1CX]GU/U/D+5d/,$c(8k]e^' + ()q$2+UCZhoK`tlLo^:rJKpA9WJ2\l-!)mh)RMKgJF7f\3\HdA3_?)Fap9(Cb(,fN\Q_/VT + 2^g3W;eL9n?.]3A:4DU3hOq(Q9V$GX45Rgil7qjN&+BdW"^pVd*L#M8Clobj5PG.r:fm^pc + >J]TYik[-q7-`TK>I[DF`uN8GRI`W8'9.@^`*t'J>mTo-cTBC;E[?qmK)1;YQ.A9S(FkPHC + 4Wc"2$p.!>mhYZdPMN(\N4IEt@aEK`tlFi5l]<Ke:b@jl[]C%13KYaMAP5%17GR&!<K2J2\ + l-!$d8Z0/G"m\K3:dpAf,.=9(f#+#>?^KcVX,pAf,.=9(f#+'iVXfIM8ur7hCe6"'d23HAY + e6")9dJ,-V[G_<j70QQ7D@Y;O(ec"Rl*oIJ7$c'j26]2?[HVO7"T6l)I-nG?C7h7ds:tR8R + 7t0k,hOq(QN#Xp`d%IU%FDpuc#C(m<!\eZmbm+Xa>HP6mk8rOj$4FYjnM_4#'_\El.6mP,D + bsO97S^T[hk722\qg4="2$p.!>mieqE0DIf';\oEt@aEK`tlFjD/fG$<sF?aj3,c)\a'<OW + :.5f'?$*\HdA3_?)ESoBI<J_D^U1noG?2#)*4gjK3j:%1:jg1Z[^?i!g#$^rT``bVCS_P>7 + I:H[n%'/-$om?Ckk-fOg[$5PG.r:fm]e:@4T\:tUk)Oe6uN2^g3W,H(902^iJmKgkR*YQ0W + PhE<II]]SJcnj<rW%#"jmjR$5Oj"5)=*\TbM!7+JD!(P9#N4Z=iHCXo["$AqZ!>mig;Kf^, + /^S"hLE>@k$4FYjR2o5c/SpOj/O/k-cVR^D7c)f^3SqWEf;%D^*oInC$c'j:D3Ns2Cp>$15 + P+s%:fm]ec>K0iDdc<2#l1/!G_X':0G8;1_b0T@q4S%<L;F"Jhgq;_#)0a`LWL&i^bZZ?5l + ;*1't-dHPok=&B.,<]p`2K-_P"-"oFUhl#C)!?!f5a-j3%l=>HS4S%m@]a'G`t3%NSng:tW + s;OSmH-4@<NX`:*3#V$;XUci`Bb*oInC$QsnRO"N.8Co&0q5P+s%:fm_f4*"l:6"-t^Ie#i + :n-k!S&AKHF(E!q\RdM[joDm36=9.kQHK[YI_HtiBjG+f7)%$`oI`Dqe'XgX.Q61F'BAP0* + =9!&5:>QlhLrJ,h9F?,6pQ?VEJ7m^hChmflC[5R4Ldb=Ka_-I2FdDsP"$AqZ!Q:t:DLKVG1 + COUpUO1,o4hrif(-k"!GHZ9RidUTIRp+WRIcpg(Ts+N+do`rZoZ`e9D/E4L]?(RH^bZZ?5Z + FH%fCBa>DO]i8Y@4n^=8ANpG_X':kgZ_MX3^7(k-1t)l?0!%ciZBt@0,.N9@Ln<dgL3*3k] + ZQf;Q=&%m@]a'G`r(C+E=#m$V=`X_jMK])9nW4@<NXr4/-5NTE1lm'a;rZVH]+H@TWV/:]h + ;/6e^\F0Za1%;X@jnj<rW%#"ird<'1&`?V]pC29<#:6?WEJ7g8]ORtl5:"P:=)t/oF7@kRH + K6<8t-nLJ8)J[hag`mE]"[.gj3$B/:=<M<\g*>"%Hp*MQkob7K=<K'KW`i^+g2pD7?-Dk:5 + !4e"7U^ine'bn6if),F&pGkU@qp,sq=t69U9Hm<WN09(pi<gD\$"h=0]1"RDPOF$Ec>rX7( + `&:1qW^;5G>;H'"D)Q]O7)f'o7(VeJ#+L!IW]<pbNU"88-9@)r09p;5-Q=YgOW')heG.=&n + c'QhO$E\>oG6EpF'SLr'4MW1dg?adY(k]ldnI":t`j"VQbAHR,V5Du&o,p`+tk&dWh0!$@o + =5XOsJO$nO?HW0['T3=KV:fnk8fHUFl&VUC?XLW>'gNt3'fHUEaTs-dieWd6cfZbHD^oo.; + &3q<'OXRrW7j:l\7KL=o@=b)^;7\UQ-2'k0^.2U_i+T2t=*e8OX1,6o4VAY'UBsHk'G^rWp + .,176X^#QX1tq%r+jbd]ldnI"CN=*"al7l&jUtE=MV-*Y-LP!#Vl_ppl@@\,\hIGq%3`T0F + A3_%!s7M"@6Gshe91M:j-r@X1,7uOT<$]@0(jcNs(PX-nHL#4VC"hU9K0@d,sYJMfZA67fl + 4L'G_7s*XNt*;-:VTm#_:2!egfj<HiRcd48.$]ldnI"Q0Y%(@[2/HR-V87fr/f$4D*14VC$ + .Ts0'j4P1lu?B;+!Ns+B"'GbX$HR+.&7:?4@Gd']47#u$2?0'$3J.>FY^cF.B8;q2B"Q4J< + (9iZZ&cgcW@0'#)RQ"9=>Bk%dMf!$d":ugm(9i?Q&cgdL_?/#i1i9<RmHt<Lp.,176t$*$g + ts>r5C4Z+TVAZ@OllKL(QZjbp".(IOT9um_?08>;7\T6k@?Mi?.gG'"<W=$io/-'M$EZE!" + "1m!\n/F"G"!Y=<Ih@2qA]3TC2!HlNKGQ8Z0bX"9>l,=J/TdQ;*Y-(?TLUn^`sg&jTp#Ye[ + qtYXd]9*l87P+>H_qTHbNEOXOb$"H_7a/9$rFjic=%!Pg,k)o#3_o<iB"_TL'R'GRVWbK3n + 5o]VIEB:"DRqng48D?&)=g(!%+.cSu`^Z!Ut\ZYp833l&KX8K@9^hjdoF`Tpf`mW;c-VlAN + ]D$m>T:c(gT2#:#%jlbc)e2)-a^H,H%%9Dqc^6HCqtA8?bK*4OnXlnao^I?RnDMM>;mM]?l + 1Z!D1$%qu+8ODbj+%!e.DPlTN#,ikpVn/1_KES=Fe/:lMBmDPCcQhf!*GFqKalpCL2StWG[ + \mYIPgl*a%!4<4^dX/mV-A^h/q[fAu:<4T(#Mjrn5.Q@JK!os0NRqXqq'#QLNNO!PlFf/Sn + G;qYg:5r;"[:4oY5TjidO^*o/tBh(L(6p[mmE5%@'c%tAiF1XA`#B/b4UgYBG5r1@q[M!U8 + FgG-g`[^&C)85b:BfPkg;$<Fn9ik-jImXP#jTi7h!V5=I)Vm2bNN0Nh(n^0j^LMq=QJ*K[n + eqj>V#U8t5!,tes$[_mNWdji2=^V1!kW*^1GO:hK*Bi@;FD0gVNJ%5mD^Oo,[u_,'7HN&@M + (JI<*.X8='t1)UdubkJIe&]hO+$B/@DfZK2pK)bI"se5I\/!Z)"WMIbUG(&p@eI;,6>Rf^+ + \iT>8qeR>4Cmb'3;3uhkN]1FLqU"`f00]kbH&qnK4[jk,o9q(FlJ^Bk)G64BL9@Uds&$DXs + ,P!-*H>Cgl;F?i4C0_[d:FeLOod:^M9aNpZhu@j>?*@EsiOlc&lUHgGA?o"mQCm^4oRhd<& + ^Klj?mFUc+sr)D=[\dc8q5Od`tj6"SM/KLS(5O%D]M\c!_d>oUr4h=&Z?bP4,fctKp4V@b_ + jFb=8PcX`G:UAZV+5!\7^BBi_UITP.iYP+%gGZg?@AA&VXn-.c"=k#a]UrG;Y?Y6-MdK-gh + aSpcf4on[qXhmSo[2VN^,W=$0bM-<gK;)U_SKBXhR^!_!l-sE?J+i>2*^uke>5e?("RK'ZB + XXT<.Cb4M\rGCfSCtKALfW4WEGA`-LCa+r^XjMs-lA"s1tpWdXR.!:B1<!*d__aSimSeFgX + YOo<j0=H.uW\,;G3A&cauQ<FNdhXT.ogdoNUki1Ca<n"0$0djn>?E$aZt[9T[?8j0!"-^B! + OW@*pV>,g[9fqQu?Pkp88T2Y%88ps702+fHXe9RcdK9aUOm#N1Q))Nc5b?l=(Dr8EtQGB<) + rl1DuY>'*2f!S3/`uYNe;7Kl`n/[VAo02rc_7nQ((qpM$&LlrWV*:R%UIor/WFtT%e;E]ab + 5O,lejbN=^*=\p</(e\1u^X8L37q<fa1)9/&_VE#uC7cN2pQO"FsUa<nIcr<r_ARP=L]%/s + _17a=h7?.(*B\:IWG!>`a@anu#S3q%MR#q8Kb[8PMo^]m@I%0?itFB;.N@,>kTK\+!rK!&: + cbfZ(p*J,J?^p$2hi]ZiK&WMrLl;X0CcDg.gHB[9(aFoOe-Kou+W4^W.cBMdi8^,,343FAk + lBPH1&EI'q=<Yo[[$h]ljh-L#3"V;gM$CdBk@`t)77uZs,"$L@\]=A);4WJ`so=<rU%Ac7i + e/Y:h`q9kil'X?*pFgtM?#UHtc/f],OT=<02@@'Gs+:hH4Og-e0_L7727Yj?/(8.,UZPe<< + pC>j/WP41.m92JXA7)l!F;:EEh(12Z=T("!+0eDfVYN?s7UB;]\'u`U"&kY>EE3W/lrU40C + l[;#9poOGPQ@JRekZH,L;remQk/BfHX7mqm/coJ2sCA<`cL)a\T34NH4h2_L3ZDo6aZ>^Qs + mZ_Y?U]6e'fWIOuro7BKlZi5HMq\^X[R8,rpM3"&qo])"MG):uKE\m*WDI(MF*WJsMu>rkH + 3m?u&!fcP>1:"ssbqY^?eZRtUH#_b0:'ed\`iSko84?`\TmONcq!_<;G(H*pb`MYmW4<qb7 + 2d=2=SugF3Xfck5N4opM?e`!<NZR$T+9->Lo5F@[<3In15Majof*cmAHR&Sn'162dMcW(8f + LT(E7\iO<[e+!W&*sg6Nhk6s[qeKom.Q?E9Q+Z$\t9FK^6ZNi4V@_rVUNDJQEL5`f>i"#RV + I-%VFEc0\j#mn+;0rTW=@b2L-$@+mu;6k>OD,*M+`.cZVH_!(]bnLHPH2%V)>E_F`?D)egI + :%Jf&nZnmO?/+,cRC-0p7$k!WKs*,=>0EJ?Uh!!;Jh_H'^?h6Q/AXK6N5,;hXTq:/84pB"r + uM0u%EXKm2YZYt%G'^@Z]m#_8ZG]skqeuar3q*.[Afe_IH(`aCfH3eGq-AF0B*_'O[6f\+? + IGT?md@G,kWaF'n#loh?]u%MQ_S=aYdN9OIo9B*GF:mGcmmTF12H&3h.4OPE7u!:phVJLV* + XMh'j1W<54'@[VaZLkT!I3O\OU(i\.4_<CpTuT'C@I'EN-?qYm#_;+.>rm#'"PF?gZ)>n[V + nV6:1\.SfAQYmJ+oRiS:/e*>M15%5_,-:NfECnIh#':Y9RDhZF$BQg4ZWTs4<CAo#`![!&C + &Y2EgV2%^to&h6T_%7&cm&q+4:X&$>8BkhjB?BktF(G=2+f^WHO%-aU[e7G@Sil$3crqGcP + ']oGnWXL''sA[#<DbOeX)8-"_cDdh*=+)^n/oDhB(I*0b5m'=/b?MWchZ+#u]&cd;&p;3[p + [RTc-)oQ;\A6XcJ"cV7m;ni4p!GDBV8mC'D8@5Tk!e;B2;V8FdnpW*J[<8pmEd21jlFQY$U + [OILp.,2QQ`,V/'\NRA31Q*bSlP'.O`*oT3#Us0?[JUKl2NQucYm+B,6>T03[sE'2@78):F + igunj.@&kPiksqB&237fn4EF]d:6Omb2W?[<D2JUK?FOZ<XoZV/Gb52H8(MsQQ+i)f@tCtm + Q\G\enCnQ/<l=&.'+RHidMUb<nlkg5lS*QqZinD'>NZH\u`p^HMkro4m\lNdLYem@!)8l&V + 9Z_s$kW)TcP4"2WD9,gmu^Iqp.!-"k0_MZZAi/<UR5tr9#Nr;BBJc^IG'GeFRXAZ+C5AAn! + ?2_\$dao05[%X_nTs$sM'ju>/=f,s5+FRf%!/6+k[=&+V].uH(`i/fB8mbg'OrT10T7'A3a + i`uBmA[O2OhSO0,Voc8s*H`2"XX/3P+nQGW+pTTqC2T/S1#oii<c>M.C6@#Y.F>AUb=P)8V + k5-.))n7El7@iNZY8rr=A..%7%4mYR$OJ.+M*2S=X$:f'c7=D?,h,KgjqtF_#iBr$O'rrVT + =:<ucbO6"(@%+'#>A1,r'Z9SN9.'*&P>=9R7-,#9qRs*SpNWr&R`V$A.%;-3tTdn3>7#%um + ?<Uh`j=!)t27U_DZ4qN"HEL^[s:j)K(Ub=t5$&l_F0mlHi*\-#&YdZ[gA*Ib?5bb!W8/U5` + C4qK=o]W;us,HY^#Tt9f=<s&B9YSTsXc(p4SFi'P+Rr91,bF[$V5Un!QZVnUVkbt8!""Cs+ + sDA>W=0Nn8P<'uIR<mW"HZ/&//$JLPj57-3[lNC^HX&n8HMF"'G_#A$)Ij+\5##h5Q72F<= + 'd&:fo!O-^>UPi]TO$9Bcft5Q[U_89iH12+,?0rq94RCD/t[;-5)r/P7TlnXcBDSh'jh-nL + P%C),>l8Q!7tMY%Vj+LigNP00Zs^+,V@UAji?dMF?_J>08=2BN6\;oO46;Ul.N8meIrJr%8 + f$%4YEBCU(8B<<A.peb-=ValtD=0\CcR;1UiV6<o"_*VRmZlT\6SZ:=<YO:]N:Sf^H!!,Dp + Oj$!&htl@0qPfWb94,"*JqCi`aZUR"YD]_WWp@u(?a]q9J\hI1O71Q:/#KA%s!)sR!q8D]$ + To7$$;WeAPPs8TkpmR#s%umkc%f8'kJ)C:qVh\:EtfC'[m@u^;Gu$5^+"L/!q7uQ$f#HMMZ + %Wg="jTUoHap][jWfs4ptBWVgk!^pn,u90`Z]tYe^-P;/3CorCe<8CB%T963c@8'Ge45pQQ + Si@R#o)PJ3+Zp^i,_3qQ^SqQ&8ps7i>\[1'ih-nK<j?WX8>MXb5QX4MeGI5qE!'ab=jij3X + k<#j=f?2T]S'b.rC-nN`UO/gjYK9KH:#iIi[(5Q_%MZ#[-+mFn'J59!D+K@"c9i80fkJ&Nq + >m'Qu$4Ff3Br)$5(f0TAWp!O4QSnh`'GcMPf9GR#@Q]PqX60GD^:F?dU9HoL5+uFMJ+H7rW + uHR?$4Fd`M2Li!Vl9b_QG1-8#bnOg>dc%<?H%0/%T1b0871BWUek/9?;E'$=2fDJ]3>%L#9 + \`;!X9^(A(T0;:J,!V!(9Xc^s"hSj6>#[(&tW4Pn(TV'G`C/7B(8V`j99S$G@j9YljJ4Ka! + E`>H+2D`q03o+apTtn/-i_SG9UOnat"&jhI"nh>qkX_?(4l;)+Y</=!s+!I0I<!Y0WSW<"K + go,l:L?h+1Z6X^#Y*`jgc`H(D4VlH>T^?P`DK>I[jXB%'IYATZ?l2c-^_?*bc5CA*`@QCD: + CB*0_?haU`5[a[t^(fo%MC/m4\,Ie(m/q;HK`s#bq8k]_r3Z+(&&<#r(9m!?V$<r%:=$)Cl + o3@Z56+b^=MV)cW#-&+h#S-.Ka"Q9D$NLEME:\885B3cm\-k8F\aI:9>toe:?%*15iSNBJ/ + ^\L@Q_td=*b,PE!_4%>]RT:jbt1XlM0KOOH:kAi0(8oQ*+RV5PRn93<6i('GbZ665@].ejU + >RZh,XG?laq)h"-b.4]Euqe#QF/VZ?e0-nO;Vbpo$CQE"9eVkI,%GDdfU5bapUJ?-,sqF#i + E/FR^Vhk-qs>gUBgF]M&2aNk(k:/G'.D4a\1SCA8Gi]iA/8%).+*`oKLfBI2D;Z_Ie$4D)d + ZARbF>EmZEfQMspbS<:6;0S-E(BEG]@0$md,GoDIUnjshn#)rKNbk1o4n?2PgT8lck6?H=: + ftLP$WJZijas)u.Vu^p4oC'&(#h#HJBq(p^`203.RV0q?MO'3W0(ro9N7E$>,-H8R4,kK-n + O;E#?<<fadaEW'Xh:u*a><CnX1f@G:5$#RI;QS7E';=s8*CJ7CGpQ*aPcB2sLhI_#cl#=MS + -6<%MZ^%.D2ZU-t&uHmU=;I_l*,N5>X&H:k0>.dBSs;;6Rag.>gX?3/-BY^jc[X'!ZffCsG + jfQR(:r$=M%<d0lP3'^B8Y^jd2\$=ageC,]gjc//X[2%@V58.Z]tpO:3Ngi4W,?QLiX& + oXA&W4$OC$<VL9<Gm3+U$4D+IY@Dl;[Wbd+aZk`..C/-nqb.\7oE!`6@0$tF4e2J]0+W*2Y + \dKK!P!`u![>@X<18\j7bu\XSJPQbCc`^%"5$"M!@cJs/E^[']?dh#[UXRd?ibrbUcbM`3V + 0.kpV*m!hKtn+b:A,<;-6*1(_t56^4!kl[cJ6d#Q!pZ/J']F$OD&H`H(tC,CO,2gFb.b]V7 + miCaHJS<"p)ZZpgsF.dH9Q/+(jdSfjWV40cF"LlT=RZ9G3r3PYL(Z+8U9MMLkBHmT31-OL7 + &qHcig'\BH+f\F!q7d8@L"#Iosg*)b`!:NEd!HI^2e<?>i;H1$/[<6OmA)4`^Ko=9l3_d8e + GN46<^n4G*5hq]*/Eb]!-aXVs>sn;=MDGVIG"iPZlePZL!Dln6(P\ofB@sGkc-;a7(YQ#hB + N*a;<TQ74nod\>&*r$Yp"1d@5_JJK5OJN4;-:UE5+l@F>0jgmYjGV_2r6)iIdupoF'IbDHF + L<fqD@e/+!_@($i%Qe8p+!.cU/3PmA-t98o<V.Wo><NDp/crC55FSn/JqTT8>noUTf8EbZ7 + S:f<2)3DQJmFZL>M)HZO&c\V3I*:DL(uh0>S'&g)f2I,YM`QLh<[3\0p@[]?T8;fR+Lrm&X + F@D,n"nd7PoK`jeP!WO"2U7MmEE3MW:h\FjMHY)<8'6EcRqscI>/?_=5Ts0&sXB/7pAnGdX + <?/b%meDdqVN!N,QX2d:4*R_IpI(;1&NnDFM1EGErp_S:;H20;S);G3=P.dk\(4n>>[73\F + RcBfN<f;&n0fjG/#-(nZY@l2>D<%)B;2DEIjV17Dmjmmn!5&@TMM]X/jD%@\56;C=#R(W-R + 0ktlIC%.,Pu+leG=94`L'7\TS[U:+t+iji%*\c.TJo#^\ZIh<snhr:s5`)neDt%cM$3!I4B + Ahq8ir]K#.S<1IaerldcMe[BT%G\@eP(O-$!(5V+<7i&@-*e<?JqEp];W^F6gO`k$<EneW% + T/H81VY+EEm-j0X+"oRMp1&[jApV3?fARX?hiIO0M\qg4Q"JVWpJ.IW<;9rl>4$oaImh5Rm + <.uAA5<OLq-nO:D+&l+`d%Ql$OBc5Oe,DTS0:,b1f;%D^-P.#H"aoOg.[G/HjAPNb[VNI^r + `[.4o<1p\-F.H863'ha^n6@]W98q#S0T0,]@BudnR-W2[Ear-T0VQf/Ds;s<7J6j=b#t5hF + f9(WNL8AH-X)#QX"g/:UqMt5<j_E;-:W+5,Y-Ho^ij\:B>Dt[?9PcefX*SW5m!*:S;bC(@\ + 6j/(I?_4b*Ci>k*QgW4?ocNRFZ"#A2\I/C1kZhbdLk\#-+&k6kW6.A"h02:enA?F\Y`B;2D + JDtstPFFq@2^@`Waoo'a89tZk5g6Ph$mkT9c[S.3s+/(qI-nO:\hbp_LJqB9IX`Phq\anNB + K>Qd:EUk=gkQHSCr+rTpH@G`qCCasBdTF-,lo):YB?F"Ii*If_i+IsJeFWIqUVmi1SD!XLY + N`dl;\Z_X$4HX^?`L&;lI7BT4uuc:1XD_u(\BEW.14i<Ka%D@.A]pAk9hQE?+oOfPO.(Dj2 + +]H_WL+Q+e9fA8:_7J=MX)(WMjIa[e\p>FJu0f^"HVpFh4(?+9aeo@0*!iX.l2`T,oYW8E\ + 42+^:rCb7@LD6PL=*\IYa>a3P-N@or3o!e\@UkRmB<'^-*^"ao_W.dH9L/Zk^TUNdt'Wk#d + ZTWl!'rYD%S5>-R>;-:X6Z;f=pkg3f/6oriG[.2pPPIG":F:\1M$J^WX!ra"RK&WF#,[3Bn + cBZ$s_k=4KHD(0e"n"ig!WQB%U7T\\5'W+g\=;1J`:J;>r%&$>7UZ>tqgs]Ok0<3:hFHboY + -'PWc;'QuQQN-@qbUD1s.3(;<HWc%F\?LfhB\[`Va?mEG*kCj]io'jO&Otb-nGo8"'!ckmb + A0F6ooMMcn'gdQKuBXitQ_[$4?u'[YfD1n:s$`I<=m\_'4NK(@&0qitQ_[$4@!R8eq#Hs82 + PKpX-PJ)f*[SMJ^i\ne2bJ'86SkiSuEQq='/pM"f;SJmD:`$<s?Rb>2*q:)"HLKGZU/N>pJ + T4H<I,*LgP8fJ5ThI\HmfU9Hm*Cf)Z\Fad4d<-@k[nNK!8<P68CYk`U8r'U_V6t(Y>(nm[q + !s]TupX-OK3l<>uea#p)TaJ0%YWu%'n//cEs*BEE+0?sHRr)!SCV$/9:^,QM=<K"MWMjIQQ + :1L-EEIM34G1LWd)4q".aX3m!^Z@TML%Jbl/CWA[%dEV15!I+km8N(,!T.[2A?o4MQa(ZBB + dinic2?"\R@kneqjTnXju7hk:4i5_?*$nXAULIo.siD2t8l]ErOU'#)02/"6AVpd"]C=!Ra + V`ISs*C)B(Mka3fbpB-&`TCp>$15?ECo'G^t9;(CkQcX/+B7k8=)<Z2Z1=5Vo0;rpM"JuMn + NfmN`p=<Kk@W2OA'mK^\jBLPSc`nYDXDoLS_4iIX`JuDFgbLI9_qlAG(!^3t_O"T!.9D"#J + HIsN,Ud>TleGZT:^/_c=%Ge'SpC.'l)K]ST:2eNo*W4fjYX!^i;c1joIlUdsNjb1d3RaY*i + @u`EWt@>M8qrOEn9V_,pEpXFosd=O-62,F4oD%gDu7ljgXO5+C6e_\!"d\9<7LO3e)SEjBM + 7HtKa*/^I,?)2Xq<3.SJ&Y6Fct>drHRP8Sl<shac?o3;11o&4c_]\9Y?=mgq'rJCpJc`8&U + 0@!i/-n[%:>+$O"Ze.dC0FXM8utXU/jigG-fXZJEm@`.p7&ihl/.7U@Mp&2<!C;,;@YQ@'S + ;\TiA-_.:0RLPX8n"@@b/P,H?!=9,gQ<Loa*6ScWeB[QLi`<MO.5`ZX%h=/1@:+anh?-4[O + "bNYElMP1'UkD)*A[J;-HEGk>$f@G0%rh=!,sB2[]M_iSG_W8tVlD3YT#9D;J(J4`iDufPL + _"J"flc,ke\"d^+F*<U;,9JDJuj*0F6WI)KAguNh^:V*iENd5fCn;='GeKr@T_r<kg3f//6 + [.jA?!CabLbcYH'01/d]Cn;/si685[moqU7Uc,kDO!#U;jceB(IU%T-?JCiBnFRE"DM3@=d + ?>V4sR=rcY/`(@<T!3SRrU?.JnlLH5:pMB:\M?7@E:4I]@#oABOO[WiJQ]):-,KDAQJLPsK + "pe$P6iE9J9/.aoc;c1jscV+mgU0T_$Q5e&W>Wj7K>HrEKUX$r)D7Ke'"VSYL<RgWJYDj<9 + U0T@1)frKW4NXa,G8D@fn:U5f[>OW*0CqeEJ`->S(%j]gpaGYZ>'KtRBa,gMMB3m(gYiBT0 + :/?95U(GX76R:Alj3,(>'K)P!sU!Q=H=/gm1<?qH[DAd$4@!_=&d\58.Vq?=&ZB@Cs'0L<: + L8*6-bfijDLMj;nf!2AmKi8RbB8BDdHUR<O1[hiM+KML#KfAQ06@A4#X#/i67A9B:Rj<X^K + J>]U'sB=<N^>Y+hMC*Z?LL7-e$F2s,!6Gq8TcmO:?\+f/>>($[L`Dagkk0/@gl2Jp*0Q<Wm + &7HoA$q7-MK(B6rp4WjI7@.>ANU#aH9#356Z*[Er4+m":sjtNtT&'oFgU+L/?*;R,G+;Wj3 + ;:!t("3#'>L<A;*"r":5Nu"AZ&5fG(43VL!bLtiY;$m[VMl0P(Z[@%JnJ]!4mb0.s3SC4W` + MYj]k'X^-hY'MMeSC_hBIPJD.,Rs#cbbBa`G=[pd,t7m9V,d=6h_38q!_2Vmo9+/SAW5#-s + c-578%'?5hVm+SiLk<bLb)](QZcu(mUH[&Fl/!cU='lN-(H=bGVF(5(g]R6'J<05?"IlM5S + ]Hf8CC`9ZmK#<da8O1Z`qe_n6cRT,qb#6t(XWPcd&3P:#r::SCGHX4N``bQcllI.G/W2fp^ + .H-L\M;If)T9<VG)$Ns1]lMO>JhFftbmO?dO`F*Lgf6tSm5MT;C1G(/EW*!Ksj[rs45l&-O + HKNN?,Mk`\>WOUk?ufT'pPI4G\>huq3aXL:RCgi2bE]pGJb$1*H58*t-f./`gaHHC0KJatp + f<tsQdEU!M/o!8Mhbr#6<;rlV6E3=4fP0I'e9pgqljq+DQPjeT=8oDnI!&X=*6`_GqIZ)V7 + C#em?]>W"Tmf?.dC0O4u%7B[4?Q7WkerM%q4u>^^[]_]>M;DDOXa8[DmpP.YS$--&0+O+8X + =qnHc_knu;Eh;m]L7(N0>UZa3o2`;+E[$4@!of2U8knA>S-Cn3ZD]X6JT5"/6QnQ'I8$3(A + bd3BXn[6/)nCTg_F$O"V=<RgW^:F>#k@IM_$\06'sacl(+Fa*@(^nT"uOMe`&Is"pfZ]j5E + 'Ga4^O/o5BF.XBp*^R7Mn"4JO:9Wj^i_b4XeN1l^?EGiHTWg]NI9o?*?i&2!nH-;hau^+N9 + [mN7;S3CAU0_Kpl1%O>H@*3@AW+_X-nGpWO/f/AM'p<!(XR$,=&td7eRk@!?3`I>U/R!BBS + SONQ07KdQ_:QJn3*SASfdl<U3H^p(2DNe[saFU>eR+`M?a1mPrW/';0lV^CWM,E.YS$-AV5 + kdIeL+IiW\s>GXra3f#rB$GTbq_293ld$MS)CYZuds!l;?N76Ss]5?g7"*k7[5TYY_%d\Fc + #!Fp8`S($3mgEtdg^=oVh.>7p,A\O%Jp?[&i4F\CXcUkG\gS?XD9*#.>3k[e>Fa+"8rVU+8 + ?_nGP#aD;<l8`k$V$/_?'AAuNP0$q52fp_C=<LpNQ:kID51eOj.>7p,AXnX(8kV>E-((op7 + qS6L=Zo0c(Pl.H*p>;]7Jisn\Qja'!l6fp76Pd9hL(2JhY!V^#*UrPNt^scic7ulFI:[m*K + qCZY4_]=8n!99l)d!2h7KSALX.d8R;"Qt)g%s%2%ZMeh8S>nM6NJ9Q:nkY.4c#Y>u^!"jN) + 5uiU]t+Sns%)HX6@X%gQPUZE[Zoau`LnrM-S^E-tGM4YpaE'!Imn/tJAF0QJi3@H-Z>/2$0 + 1%eElpjpY%O92J_5i4c4cT%0kHLf_nq2bKDT9\hfoSgW4ehf[c,@9s=b9kgaHr)a#S"bPbf + <Rd3@&(\9iG^c++hHRR\GX9]5>IplQjV$abhHtJLQ0@Ot_?.QY8OYeaYa"p2MI)]c0Rg4jI + c:sU]eo%3$d0iR]Nd'T@=`r5UnXI<rGIqn<:S](;tCI<DlFd$h@\O18uWm"0X#'.k(pc-.4 + c#Ufdc:?^]-UaWT(=TQ^/Rai*8DgUf4*gJdu&5"!$I2k`r,!9cbsSTWg\sh5@!=$Q"t;Ti8 + Sm/C!!3d9mI9l5nqB_>Da7=>!HX]ghp28R[1#l)m'3?+Qi?Zttns.KYM%:H'-0'mcNt:iN= + %SWWAg\O;k,EX<'\"PI._W+Wu#*mu9%7ci<W#,A\1NtQ@<g4aXkGs0;Y?7Xl=+T?,OYX%]* + 8OYdXf++#d.5L0<=.'NYAt:8T(::?N>iPDo+b0G#LVa)nnHfs'4SIDul&d/74BHU5S%KJ?X + g>shK!6`\a'i9^G"l\^[9id-pua%V&.kmBeFUR":6HYI@P/XjAMBFnojI="_"i#-goV7U.V + 4r>FGRd8!ARkK4jQ>W>C**$\X("O?nrP_1#dUQEm6YI:lfU@"+..XOn^H2,8:n!LqtS+3H] + ))oLKQm?a[mi3&g+2n]E,`$[S2X]O!_[gV6ig=<Im@<@U^cI_'VmD.rFV\*R[Z6C[Oi:,\K + c<P#YaAWg)jmdDj5KeI*9A%>!_-nGo40mo(-`f/u)DVa-kNm9?rd:IX&G\E7=XmYU2YIWC8 + 2H6jpJ)T3&Ka!(d,:_u(o[2XGo0c^2q'?5D3a[p]DbUjZ]"M?XSAW5#-s\>%Wp:@Q"bL-eM + L,:$mjCcS'4HkXlc]QU^!7<F:/VD_P[Zf(@9tUZRP4Z'Mh](M5qkSn4Zdi^C7C3A_S+V,Zh + g-Y.it7W;Q^6db\QbJkrr<(d3/i)"@4[Uoj#.sF?BNk<do(\_774PLP\MKH/-c[*9K,.kN' + Y:FlG'_(f4>MpRY>]:VV>rd_j!>W\5nZR+Q\1Hq:/kV^EA3lc_K3b9^mQ<f"N=@RFQ)hg8< + k4j02dQQ@Kfcs4?%Ci7khDW:=\GV(h>93f^LckDKi/Dtlu<RgW"DiBf"-@Tr`h_]tr?)d^Z + #:SP:eFtuIlc$cU>qXMJ$4HXc3#2,al;od;LP]AC5!@e2FI22'iW2Yf=*6`_GqIg@h;#5#q + umiH$4HX`pQ`m#;:!q%rd!e9YaY+t#1GY8:MA.TiYb?f(7%U0Rs:t`E1c6eY^jJOY+hKg"1 + j.Pikr\f>+.@@gM/L]CNL*W&ga>#SShlH7#B6V96?!,!rfVo76Mahck,G5i\)U]cS1aF'mc + NtN"SoWVj-BW%eEkq1Jdp;AV@o%r\dbF4`#1cT.=Or0Grj5odK>O-(`;+OMe`&Is"pfZYt' + bGE0NArYEDSM)X;\kJK$ne5`Y,)s5C+>s(]8UfqCkb\Q'.P6/$pU-fV1n?F??e<?;gHL"Ts + s+^!.:s5`km1TrkH+4.><D"*jjV$UEjRr4eM9A1f0$tgL$i&@A.dC0L\=`C1nY=Nb1CZg"\ + K3:CVSpiU;iC9]LGuH&k8&riOIW#KJ<.rP;9sI$4&1*\psIXi#7X.KTcPH8VSqD?\O>\5RB + ;&?KKOqlI&sf7H<ttRTHCL^f<)('AqRcoB8G_"kU\9OfFtdV&fm^NJ7!_-76N(KWhNt)oGI + +tr10#\Ap]g2/RGA@X4?$IS`TP<Ef'+5>;";H$4HXZ)AVqhR*eQQLA4j'YrN$K]hAqOO&U' + Ul1>$?f&7'S<Ug^l(QTjV(@\@Z.dD<EWU\Cm`4s0Ag0hSVlZ(pT$7IFJ--D7o&V&op6X^"& + H<R:i(%pqJ(\A5B\u;lWS_9+.f9tX+$DIkjcs^75]Nh0u'Gg27O/o3,.kA<<EKg#'n[66If + `lNsRdM\4X2&_h>U'3Ea['5cd3/i)psNC^omHPP$X-d7*M#1\o;@';d)Y/=g-\M:+&[o#og + ;m^qk9&fr1e0(_FOX0$O;/2rdqDWL;F"@e5o(%^\m1H></7G;uc15F6^;\rN1CW=f&SWKig + 11/jE9A1&0pZVnGmpQ%$!JGlE122TA8~> +Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.pdf b/testfiles/cli_tests/testcases/export-area-page_expected.pdf Binary files differnew file mode 100644 index 0000000..4a510aa --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.png b/testfiles/cli_tests/testcases/export-area-page_expected.png Binary files differnew file mode 100644 index 0000000..8bdc9e9 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_expected.png diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.ps b/testfiles/cli_tests/testcases/export-area-page_expected.ps new file mode 100644 index 0000000..ce348be --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_expected.ps @@ -0,0 +1,482 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Thu Feb 27 23:59:28 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%DocumentMedia: 120x105mm 340 298 0 () () +%%BoundingBox: 42 49 291 256 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +3 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 3 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 120x105mm +%%PageBoundingBox: 42 49 291 256 +341 298 cairo_set_page_size +%%EndPageSetup +q 42 49 249 207 rectclip +1 0 0 -1 0 298 cm q +0.254902 0.411765 0.882353 rg +56.691 42.52 m 170.078 42.52 l 177.93 42.52 184.254 48.84 184.254 56.691 + c 184.254 113.387 l 184.254 121.238 177.93 127.559 170.078 127.559 c 56.691 + 127.559 l 48.84 127.559 42.52 121.238 42.52 113.387 c 42.52 56.691 l 42.52 + 48.84 48.84 42.52 56.691 42.52 c h +56.691 42.52 m f +1 0 0 rg +286.188 194.75 m 227.227 191.418 l 191.059 238.078 l 176.008 180.992 l +120.438 161.023 l 170.098 129.078 l 171.922 70.074 l 217.66 107.414 l 274.359 + 90.914 l 252.969 145.938 l h +286.188 194.75 m f +0.501961 0 0.501961 rg +4.251969 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 1 0 0 cm +286.188 194.75 m 227.227 191.418 l 191.059 238.078 l 176.008 180.992 l +120.438 161.023 l 170.098 129.078 l 171.922 70.074 l 217.66 107.414 l 274.359 + 90.914 l 252.969 145.938 l h +286.188 194.75 m S Q +0 0.501961 0 rg +158.738 195.59 m 158.738 223.77 135.895 246.613 107.715 246.613 c 79.535 + 246.613 56.691 223.77 56.691 195.59 c 56.691 167.41 79.535 144.566 107.715 + 144.566 c 135.895 144.566 158.738 167.41 158.738 195.59 c h +158.738 195.59 m f +0 g +2.834646 w +q 1 0 0 1 0 0 cm +158.738 195.59 m 158.738 223.77 135.895 246.613 107.715 246.613 c 79.535 + 246.613 56.691 223.77 56.691 195.59 c 56.691 167.41 79.535 144.566 107.715 + 144.566 c 135.895 144.566 158.738 167.41 158.738 195.59 c h +158.738 195.59 m S Q +Q q +82 59 151 151 re W n +q +82 59 151 151 re W n +% Fallback Image: x=82 y=59 w=151 h=151 res=300ppi size=1190700 +[ 151.2 0 0 -151.2 82 210.2 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 630 + /Height 630 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 630 0 0 -630 0 630 ] +>> +cairo_image + Gb"0W#BX56H/SW;NF2j8'mgT%fW-Fo?>[`Kjj-sYf3!(&ekM#QR6&W*m:?0DCN%d!log@ng + IYG3j4uA7=i;XaU*TF6OePBG!['c?"A'.-5h*V/*(Vb8Js_u#^@shccMZSk4#tuX3"&?"T0 + Fu@k.*"V<4i84P0\\XFfcXDRn*BF%KI\$/B@.ak%je-g\s&182_86Sn`+j#&qE/[_f3IqRJ + QB=p4oJk'H^?f%/)r$d'kKJ7M,Xi>N%2+K84?\;%j%888hSY+`'"OrB%.CFC`aUdeeO)@?i + pWDQd-L;F!_C(qGdTs+N[)MNl\-nKnE7Ub6o$4@uU;-:>__?*8C'GdjFYQ0h)KnX:j/:aNc + @Gr+3$QuEG=La+&!_@&?(9X@8!0S7SKki(fJ>>YCi>N%2+K84?\;%j%888hSY+`'"OrB%.C + FC`aUdeeO)@?ipWDQd-L;F!_C(qGdTs+N[)MNl\-nG@6NZD5HjR?XK+!WBP(9X@8!3A3NqY + YD=-\hZ%peMMa$4GH^=9-pBfK\hp^-CtdIBsEr[8QqcM$8TeCFC_6CJMT%\#llCDss-<nAK + A;+"8ZH$eJ3W!7p5D3iBZq@IJ$)I/)n<nXlh&'GdjFYQ1cHff/fR_VV_DiirRn`IG*e:ft5 + ^_?-t(X]K,J^T\:t?^iSFZeZ"CKki(f!,LG;\`:P]S_c1$@#c<nqa=lO)@?kfRT"QGhQ*kh + B3r_EFF9MO&,AC'(9X@8!3A2gB1=8&%6M1=dZMG*`.-&o;-:>__?-t(o^:t7(Uf=,<`2ar\ + ;%j%Yib=YdpabBfVt3M*q75)Z4n(WTs+NuH$e/m(^h9c8MSa+.k)kt>XMp#=EA(eG3jqUa[ + umI$eJ3W!7m[n0dX!>[]Q>broO<75;S"ICFC_6CYm`!3UXbuqkSbq;GRXmY](&*"^oS:gC4 + PfmRiA#/%knM.4e^k@0'JOG3_QV_M4W71$-ceV&oZ\'GdjFYQ1abkH(oN+tG+&*qFD!"bhY + G-nG?[%YP5U/?eHRHr9ruKki(f!':\OXL)![EuqK[TWiAEK`tl)_36B#(A@IVZ9,a%8O6eD + )@?kfNc5Hp(A;!D-,kukMd?:d.4e^k@0,##kkHq!KtYamPnXoJY+`'"lo9*'W@N[^LodCkj + i=7&E".L)@)q6$/f$A3oPR`2;G^K*L;F"rj2d?/Xqp_9A0o3'gFF^$/6kPN!SDDQn7&j7)g + 6DjUn\/:[.n-0=La+&!jL_KTg^":[Z/7k'GM=cTs+O`#iAg3<nOWTHgRo1TWiAEK`tl)Ylb + BI/F9q%.k.b7*FIsua/6([%>=sna72)1n@5^cDEfRXnr^hM<`2ar\;%j%YiGKt$bS.ZD-JB + Bs1^JkYph5/6X^#JET6Ze151]A?:dFki>N%2^lB**k6Vn^m-S*-$s$8&=La+&!jL_GCNF%p + )tqR;abPp0M<i3ZY](&*"^m*g@F+7:Fs@sp8dYn5f2,QLG3$:s`up0I]$"+0chbn&lmjM5/ + 6kPN!SEO@Dmhq=)g+WN<n05]:QMt(fi*6pa0Lk[_SS/E(4[ED]e[d(K2"Bi>hH9,SQVo3fS + s\u.k)kt>XMp#fQ$3<R0F7>d:mHO%;XO/V0]Z-aI_3GWUlAh'GdjFYQ4#L[<I?k!CJoE]s( + r(s(@$,A2ggW[SAsTqYY^=fG#+(Ts+O`35&t962p;rCV)(P4',4^gY'(0brY>p#B.d`=La+ + &!jL_WmV22l0:^E"$QE-E]B/?uFsD?\-,k`&n,'@=/6kPN!SHr9Y,Uq<02IYD=(0"8FF(25 + BfE?dCk)IW$470m:fm^@SCnd(@Dd;gSJ4!Q[VT]H^<^\-cY]4tm(gL3+.L-a2&$gV*G8^$N + ]2-8H>MbuD<'nR$470m:fm^@]X)*?]U::uULP`h=H2`WI3lks4jsr(XJE(>%>=sna#i$'a4 + n,qH;oiW%;X<r_F:mPg$jFaQ1EJREu9ak_?-t%m']LU#-M'hN4lGJXea$bBlZqe$L(EHKLB + 5LfPtfp`-CTKU.<.%fSGbBH@Xhmk&-`7/UroT1e-JuYQ4#D8D=;24T<4SG!l#0^67L(n[U6 + r]I+)F-nG?+%cj]J.dSjq_R?SB.'UCJU?(tbc1N$Oa"e83K`tl#_36AXMH6U0)Afj4SWslm + ];OGqc=`bW"bd+f_8-f.9n"gtLH$`!CZJ%fiVt-G,Fc;^@TCM_l/@R(5[a[qE9Of'@E\=OL + P9Sd?2(`Gfs$@_$X,pW,8u,&@0'JLkkHocMI"ecX;&*#ZB?Ehp.C4jK/8u9H!;'(-nG?+%N + eniEhB98g+$o@UC/S$MI)n.E-&/RTLM1D=9'*V3O6Sr?^84;`PRA;kgTudR,,jGm?gjOc:S + E\TWeDI3-&Q76+jAcIWc)<@=KTBmCs(">:;Y;&NCI?J-AFR0/CW"2;Ql<_VS=qZ`L@+-p'> + BPn]#ZK`tl#d=VrJ2!_a@j&0='l?-^4*c!^?`NN!SXBR&8[h0;g(4ZS/%PBRD<gE+??=@'o + =\4ajF)p*e<RRW]JO!WE=E+2R!sZ05f"G<?Co_>%.;kA$Q(Hk%57.e6K&^c%0M'_gS`P$'g + OsL2F0.niX?:,:.k/go$4FY$'5s6P[RU#\VQaL:[oZJ[IT!s#1R]7b8V)5^YQ-46nbRWc6I + kAhSe\^,p.C2NlROCkpLZ?`Z]YA1U9FVK34XO16([@`2_PQn)HfXO;;Z"FZ?\MYh7U+"HC2 + U*-nG?+:;/X<TM;n;=-!aDVGd/t)qhHQ1CL#A3W+WK!jEg1eN!h6Wn3X_Kl)gNUr]mUP2bK + KfrV!b*@NH=$Zbsc2Fp`@cB'MllanYr`n6:;q,aIOf!:G?D($q8$f62@Q9gS#FLkjg_jY^O + M&p(aZF<n5<3hYgRjflg.o*c?di_-=^r[A#26rC>>S"7^g"`\CY88dV*q'Y1@0'JLC@;R`' + "-q&n\V_kXJE)u[O`pXOrf;\@);(jdg[30^4-i8CV)X`c&Iu&:%dhKk<,P:=9',,hJH.mnZ + '<!UWti;I3lk(m/!_>d\@j--nG?+hVL+AhXomnn`!-RRp.Blb#h5tKIAAO$dS+/)K0ijof2 + K5hTJpTcYd:>793<>6CXc`5.j9l!Ea='V<iGb;kV0gQa@EgPn`9G7eYj#fe#q"UduO@(4ZR + $G"d`O2hcR:GXadX`_),_I8a9?OYeI;!"7Z:4ur&^kgAB!NN--ZQ0R=O,FcGhEp]-Wd_d.J + TWeDI34j$*]V-e*,K0a'Mi^]5d"C[S2L"K*C\`mak<I`k@0'JLG3d(k.oW04Lt=G+0!1oT[ + IDkI"@cf#=CBLB;E\9tRrNF^,t2nR#3c]7,nq,F;[86gHU//UO(Q%nFF(25BfE=$];Mlr,! + f(.!)=QY=_U]uMu#X-@N#O:e2#c/.<;ml]MZ7>3X;mL_?+]Ai5l]<=h1>`M!*2'.k)#3$4F + YK6RS0="Jn6%Kak*14fki_\8Z*s.k)):Ka$DaU#X<)C3!Gf'!J)uDQKW^Ho\gtk$%"+^^:D + V^o>5lQC@_L<"B[=UiUFTUr[ms;GG+;krQU?$4FYK_ag%1FQA<#+PoU=696FjB<`CY<`11G + $4FYK,=`Lg7&3`T(QY=[Y,nEYa\%FUUTa`g3c]J-5sDI:Ic=M;X%mjhYeH:[F]MBC(PN%Ne + BpVo)RSP9mN^RVlWdUbEU3I9kub_$Ka$DaZ%FBWXjXo%KBS&O::[0UfSqF4.>!Dn!c[GWJV + =<Y\=n8+f?c\4F^MbC%BDJ%TJ\!$%E+:D!c[H"Rh$A.U0;2dGL0>I\jsL%Pn^&"B/V^>[VS + c:=9)):Iq+$q/8jaEiXp9:KC2X58)'"S.k-(&_?+]A`9["(8l;Y$M\j_B/NWQV*bI@:GrmA + 'Pd?Ois!TDuVbZTNB97t]j="gI.k-VpKa$Daak,Yn1uahh.NL]K<U24%.k/W$c"UnS8HHOo + @0&?QoBI<J3n3Ihn`kBNr0N9B4k=L]Mt^"c]!Yj*-0Pno"lNA*^=`^)B[C&'PNP(f<`8#IS + 6U8\Q#o`>2[Tr.WOMTG1?_&gc4KH8#e*i4Pd$=fD^[.:VquaQUp/*)>s*:^,#8QM);27bS9 + _33n.Q-:^o:7ZB,]j(7Al#U:6lhL.4uU1e^DNOT6u7-!c[GShAHML#jE&n`eeK\)>7-0m*0 + FHAgN-Q:fm]mS_cNc+9^\Ho82tMr'c%+h8naGQuqrJEp:;g_?+]Am9S3#9gGkQ+J(JuWRUn + 67Q.@-bQ@%I,WQ2>^o=ee9oXAlkNd-I;=g8lSX%5fMM+<)!B>46B6LqO^OX1EUg@[Ll7mH, + HiDQ0NOA)J>EbR*/-)Tnm$JFSfFN0o4D4ZCXOBf6#eQ54]oo+QPnXoJ5k)Fm@rf4<^IXD$D + jbNtF@s(bCcAZ1>:3`1=tEsLA4'c+3-BCkgk@np7u<#FkH=,7elPaS4uJst'GM<JJ=PFR.G + dp/X@J-qbl?sM[sU?aDIcDsR*emZP6*-`J7(@GF^i")^/U.)moLVglAY>c=&SD,^/_RE\j" + 5d_?+]!@)u^%_o1RM'Q1%K-t=P,Ka$CM#BEi`9_`Q^`6/lH=*6a>OZaL`8J);HP0Ql*UTa_ + <3I#Ru_/(dR6cGN030BI?QCek1naPn2-<=#@=9*elnAK@"_1"rd&J%nR\Zq<lB\uci;G^Hq + 5'6#`14uQT=Uu:O<BrG-Zr0'BDIi?_:9M:9;S#ATLVa+3jNt0."s^fJ%hqf>E.rC+KcXb`Z + FO0e?HZ\$SYQBU@0&?.pui?CH%&0m&FWTF<U&AN[\"71Shi%L_IoJh/-'$:El=cXQ+F_TTb + ;lK.k-qQ2b:D,0i1sPNZ:'lfO0YFec!GXPSfj2HEeN*2mNV!VpneMOj6l,TWeD93I5A$_$n + )Uqhhj3@>%lf8WgW%@eGFddY/#h$4FY3UB_kt(uSE*O*I$)$nEe)LVa+3jOf$;#,D'MmOb$ + +`)EFX=C4X>iQs,V;G^Hq,*'G6JAL$Delguq8k<j$UaUUN]A_mUkun6&Ka$DUnM_4#%.0Oq + Vg+.5PoD5&nm7ba;mAYM=FihJ!B>,Zp%\e*]12N+02VcYl'*]EJDJ;PP(LOPnCWTro*iW]X + mRg5TnMUK8rBq7F'>#X>F*,-nA<<!jr+Zn>Ip;KJ<E3hmT*_D-,o2OUnFpl]O4dmHCZKkT- + WCD8r?j)=%i;2s!TDu7rhq,@kaVrF;OK>,`e$^\YP#5NGS$kM)S%n8ghjG-nG?gEq[a9R*U + aQ6bGM&k.9tr2mQj,V\c^p`'`Zk'Gc3DDnRpL?ns\*FRe?9Tc2`3htB["dXs?F)gPYR_?-t + 1eB9WW`cAC\'@0BnC=$7DoOtk!AL.M6"lP,6HY42>jH*+KDb\YpdA[rS0Y<IlgG,\)S<Xd& + (4],WpImL_aK6.W(b7$`/-*FH]mEr<UKC<RmL*p5elh]J;B00m"bd+fa4n5'`r-iF4^L6'B + N))j$hRQ5OY)$!H=Pbll+6ZkKa$DUR@S=62IDLY0+6LEZ'$;\fAsMYX/#hFNktj:jNL9MnW + )Kn4]XZq\<C,I.8#bN,mAu+i5duAVSkQCMtC]QVVl?S-O&.]Cfku.]HgfT6"'dRo$6sNnP7 + p3HB`YKclk>K;Hu1@X/.O25PoQ7Yg!X%'Gc4eZeHhG4*$8P8F_r&?5ds@rKS(DZQ#p.CF)D + JrVFtrm!dpP(Ok$6LD1MSR<)R[`]J*3oEauITG&n<oqK1HDIi?^9Y,L`\TmmS'aefXY?H!! + Io4<,\(@k^Gj)W.;pU.p=9)qAL2En2/fkTm<N5lMNGM_9R0DRj['$rJ_p,LKjZ2o>G5^*,& + h#:2-P#4=1`3P8oJ#f_+;WKg/!#r0pWuaM2LN,?H=5mGXW@F5.4bHH%N6(j9FhkV#@^Z91C + Njm]9,8VlEnRb5d$mgs4s@Ab0#Uj$OV&Irs1cA"lR>8P:I%Glm4e_4<0/_ZVE$u,O@lXJ*5 + n(b.t*S#lf=GWd)Y)_m=En`UTo0$4FY+6cYN49\4;J=M,Q.91YtF>@0t,FlN(g`T$R'QVbl + &gUF4r()4FppXV),$c';?a-RZ;T$)GAGVWYLZBE)qgTl948^UeXiC<([MaqFCm>1XTBG;54 + 7>HpU24-K@HD#L6@&?\CbLbe@7^hB;),9ei-,UYT>[On9o%_+RYJpI5-jg?t,tEtH0pk(g] + "`J=@'!4<S@?4q@Sc^"WmtG5Y"$-:F6UWu]U,/FY#8@%ef?cVfO48Tec!EB!@QZ+8Q"Wh8r + C&qfn=:6F5pVn6=Bn>k31bm#*\5=mOR-"3#DR`P4^;)S66C1D6dKu;"LQQneJX#6H&@F)[Z + tg%uq]YcsZELf6tU'!%T6D.4d\4i8W_K/PUCh;Dct-]3`"WoYA\\^1BZ?!VjL9K*r,8:R1? + "Sd*j,`_),_I8c,,;Z(5X`#eAb=",[#l]*!1^gQ`gd(RB0!/m:g>,`Q\2c'62-\k&,fBqkj + V%>Q!AOBl,pqcJZ(Doi;C7QXl"kXR<.2@/jh*U4@STl`9;.j;HD6CL^WoD5(]AKofYQ4UZp + _tQ6XjK;MMZ>]G[#uW_nn4SCC2U8a'S=1'n?!A-cSq4R[CWtp$fDZ,<`7^VJ*3S."+e;jE8 + osXGm9H[4G:[@!;Al^;N.nc/%<:*lA#=ckVrNEI;Zf'9ORr=3;M95K?81-G87:]>iistMP( + 74_I(_YWc_A@d&sKCKi(qP#'+%@@k`N"Ff'BbhuPc;;YX:T*dpHfW7B]k3p#1I!^d]V"^il + ohe[pJe>P1ALHiFKUO-*M8`:cM5M?9(X@i5)dcheMnL6!h#Msc<QGHhkGT7km\Zq;a<qq_S + Xp<SBSq"=Wm1=sTi4u=YB,V2WAt:84p>I;V<`4/n=&0,%&[(DJ%D#36IrG`&^k#F29ti[9U + /T$D5!0Uph7KBdLkd`lD7?Rr3m6SQ947i\E,*^@K;fUIGAB`SDQKXQ6a7\8WVb:/r6RNZ"l + R2\h'RgjTCWUnVn3\r?:eQo^)g@QLYgCkXSn05_?+]7m9O`#K?_jY`.pHc2<jaBgFF]mhQF + H\*Gl,k^k&t=:,TO[&>/G'(Xab!oFS"%7er@0/JJtN"(tr_Nd%uJkcs.-*BrHP8r>quVEtg + iZ_\59U9FV;33sjtLKoV4SG6KIJ%31TU?u/Cf6(GODdcRH!"QZJI<)t6Y=O]iTBbp2#2LU' + Wj$ra)UhRi=&E'"%\2>jpB*I7ognV8%_l`*W>G1\a1&,DQfo#_F[)e]ZE],#!c[(6r6H'-T + s3aJiC]"$BA*&tP6lpHi./X+/ChZ"7j%XY*6K+";V5+Zi@50B^siC[_HtU,j@:;>XBoNTkc + sln>qOMm?2p4M/JJtNW<5.2%17GZh^:Ybi,=aC'I2@>1EAT(2%V/e!)j+uXtV8?p`;hPoYL + :USeMa'gXQd2=9,3.Slfl,fQ',CIe3X^TWeDi*BLpYTWjdU+SjCiG_!X40Qm0C;M2hek^i< + "&+BRQ"^pWbd3T!N]qPbQO$:>]'Gc4u,=`Lg'Xgp6QQLX+#:M,';b%<N1+;Khh+rLl!?Ro< + !)+CroUnKYYNnCCUCZhoK`tlLfKk_<<pAK3UCZhoK`tlLfR\_\KtX1,acAX$!u)N$WT.n\? + r5KjSL$Ms!"Vn.!2bdkZ,!$:2g%pld0FoH_?)E6iq<*OKrrlgj@:<M!=B4MeB.[\$jp4:]? + ?7!^]P8dJ>na9br$p9/O)HT)mG.8!\fo2l5YGnf'?$*d0FoH_?)EVZZ!9<@2j;)q9]FlJAM + @Ap"$i[#)-pB)=jO5n,S.G@-Xk\9a]XVe)a(AhuO/m^so?s1CX]GU/U/D+5d/,$c(8k]e^' + ()q$2+UCZhoK`tlLo^:rJKpA9WJ2\l-!)mh)RMKgJF7f\3\HdA3_?)Fap9(Cb(,fN\Q_/VT + 2^g3W;eL9n?.]3A:4DU3hOq(Q9V$GX45Rgil7qjN&+BdW"^pVd*L#M8Clobj5PG.r:fm^pc + >J]TYik[-q7-`TK>I[DF`uN8GRI`W8'9.@^`*t'J>mTo-cTBC;E[?qmK)1;YQ.A9S(FkPHC + 4Wc"2$p.!>mhYZdPMN(\N4IEt@aEK`tlFi5l]<Ke:b@jl[]C%13KYaMAP5%17GR&!<K2J2\ + l-!$d8Z0/G"m\K3:dpAf,.=9(f#+#>?^KcVX,pAf,.=9(f#+'iVXfIM8ur7hCe6"'d23HAY + e6")9dJ,-V[G_<j70QQ7D@Y;O(ec"Rl*oIJ7$c'j26]2?[HVO7"T6l)I-nG?C7h7ds:tR8R + 7t0k,hOq(QN#Xp`d%IU%FDpuc#C(m<!\eZmbm+Xa>HP6mk8rOj$4FYjnM_4#'_\El.6mP,D + bsO97S^T[hk722\qg4="2$p.!>mieqE0DIf';\oEt@aEK`tlFjD/fG$<sF?aj3,c)\a'<OW + :.5f'?$*\HdA3_?)ESoBI<J_D^U1noG?2#)*4gjK3j:%1:jg1Z[^?i!g#$^rT``bVCS_P>7 + I:H[n%'/-$om?Ckk-fOg[$5PG.r:fm]e:@4T\:tUk)Oe6uN2^g3W,H(902^iJmKgkR*YQ0W + PhE<II]]SJcnj<rW%#"jmjR$5Oj"5)=*\TbM!7+JD!(P9#N4Z=iHCXo["$AqZ!>mig;Kf^, + /^S"hLE>@k$4FYjR2o5c/SpOj/O/k-cVR^D7c)f^3SqWEf;%D^*oInC$c'j:D3Ns2Cp>$15 + P+s%:fm]ec>K0iDdc<2#l1/!G_X':0G8;1_b0T@q4S%<L;F"Jhgq;_#)0a`LWL&i^bZZ?5l + ;*1't-dHPok=&B.,<]p`2K-_P"-"oFUhl#C)!?!f5a-j3%l=>HS4S%m@]a'G`t3%NSng:tW + s;OSmH-4@<NX`:*3#V$;XUci`Bb*oInC$QsnRO"N.8Co&0q5P+s%:fm_f4*"l:6"-t^Ie#i + :n-k!S&AKHF(E!q\RdM[joDm36=9.kQHK[YI_HtiBjG+f7)%$`oI`Dqe'XgX.Q61F'BAP0* + =9!&5:>QlhLrJ,h9F?,6pQ?VEJ7m^hChmflC[5R4Ldb=Ka_-I2FdDsP"$AqZ!Q:t:DLKVG1 + COUpUO1,o4hrif(-k"!GHZ9RidUTIRp+WRIcpg(Ts+N+do`rZoZ`e9D/E4L]?(RH^bZZ?5Z + FH%fCBa>DO]i8Y@4n^=8ANpG_X':kgZ_MX3^7(k-1t)l?0!%ciZBt@0,.N9@Ln<dgL3*3k] + ZQf;Q=&%m@]a'G`r(C+E=#m$V=`X_jMK])9nW4@<NXr4/-5NTE1lm'a;rZVH]+H@TWV/:]h + ;/6e^\F0Za1%;X@jnj<rW%#"ird<'1&`?V]pC29<#:6?WEJ7g8]ORtl5:"P:=)t/oF7@kRH + K6<8t-nLJ8)J[hag`mE]"[.gj3$B/:=<M<\g*>"%Hp*MQkob7K=<K'KW`i^+g2pD7?-Dk:5 + !4e"7U^ine'bn6if),F&pGkU@qp,sq=t69U9Hm<WN09(pi<gD\$"h=0]1"RDPOF$Ec>rX7( + `&:1qW^;5G>;H'"D)Q]O7)f'o7(VeJ#+L!IW]<pbNU"88-9@)r09p;5-Q=YgOW')heG.=&n + c'QhO$E\>oG6EpF'SLr'4MW1dg?adY(k]ldnI":t`j"VQbAHR,V5Du&o,p`+tk&dWh0!$@o + =5XOsJO$nO?HW0['T3=KV:fnk8fHUFl&VUC?XLW>'gNt3'fHUEaTs-dieWd6cfZbHD^oo.; + &3q<'OXRrW7j:l\7KL=o@=b)^;7\UQ-2'k0^.2U_i+T2t=*e8OX1,6o4VAY'UBsHk'G^rWp + .,176X^#QX1tq%r+jbd]ldnI"CN=*"al7l&jUtE=MV-*Y-LP!#Vl_ppl@@\,\hIGq%3`T0F + A3_%!s7M"@6Gshe91M:j-r@X1,7uOT<$]@0(jcNs(PX-nHL#4VC"hU9K0@d,sYJMfZA67fl + 4L'G_7s*XNt*;-:VTm#_:2!egfj<HiRcd48.$]ldnI"Q0Y%(@[2/HR-V87fr/f$4D*14VC$ + .Ts0'j4P1lu?B;+!Ns+B"'GbX$HR+.&7:?4@Gd']47#u$2?0'$3J.>FY^cF.B8;q2B"Q4J< + (9iZZ&cgcW@0'#)RQ"9=>Bk%dMf!$d":ugm(9i?Q&cgdL_?/#i1i9<RmHt<Lp.,176t$*$g + ts>r5C4Z+TVAZ@OllKL(QZjbp".(IOT9um_?08>;7\T6k@?Mi?.gG'"<W=$io/-'M$EZE!" + "1m!\n/F"G"!Y=<Ih@2qA]3TC2!HlNKGQ8Z0bX"9>l,=J/TdQ;*Y-(?TLUn^`sg&jTp#Ye[ + qtYXd]9*l87P+>H_qTHbNEOXOb$"H_7a/9$rFjic=%!Pg,k)o#3_o<iB"_TL'R'GRVWbK3n + 5o]VIEB:"DRqng48D?&)=g(!%+.cSu`^Z!Ut\ZYp833l&KX8K@9^hjdoF`Tpf`mW;c-VlAN + ]D$m>T:c(gT2#:#%jlbc)e2)-a^H,H%%9Dqc^6HCqtA8?bK*4OnXlnao^I?RnDMM>;mM]?l + 1Z!D1$%qu+8ODbj+%!e.DPlTN#,ikpVn/1_KES=Fe/:lMBmDPCcQhf!*GFqKalpCL2StWG[ + \mYIPgl*a%!4<4^dX/mV-A^h/q[fAu:<4T(#Mjrn5.Q@JK!os0NRqXqq'#QLNNO!PlFf/Sn + G;qYg:5r;"[:4oY5TjidO^*o/tBh(L(6p[mmE5%@'c%tAiF1XA`#B/b4UgYBG5r1@q[M!U8 + FgG-g`[^&C)85b:BfPkg;$<Fn9ik-jImXP#jTi7h!V5=I)Vm2bNN0Nh(n^0j^LMq=QJ*K[n + eqj>V#U8t5!,tes$[_mNWdji2=^V1!kW*^1GO:hK*Bi@;FD0gVNJ%5mD^Oo,[u_,'7HN&@M + (JI<*.X8='t1)UdubkJIe&]hO+$B/@DfZK2pK)bI"se5I\/!Z)"WMIbUG(&p@eI;,6>Rf^+ + \iT>8qeR>4Cmb'3;3uhkN]1FLqU"`f00]kbH&qnK4[jk,o9q(FlJ^Bk)G64BL9@Uds&$DXs + ,P!-*H>Cgl;F?i4C0_[d:FeLOod:^M9aNpZhu@j>?*@EsiOlc&lUHgGA?o"mQCm^4oRhd<& + ^Klj?mFUc+sr)D=[\dc8q5Od`tj6"SM/KLS(5O%D]M\c!_d>oUr4h=&Z?bP4,fctKp4V@b_ + jFb=8PcX`G:UAZV+5!\7^BBi_UITP.iYP+%gGZg?@AA&VXn-.c"=k#a]UrG;Y?Y6-MdK-gh + aSpcf4on[qXhmSo[2VN^,W=$0bM-<gK;)U_SKBXhR^!_!l-sE?J+i>2*^uke>5e?("RK'ZB + XXT<.Cb4M\rGCfSCtKALfW4WEGA`-LCa+r^XjMs-lA"s1tpWdXR.!:B1<!*d__aSimSeFgX + YOo<j0=H.uW\,;G3A&cauQ<FNdhXT.ogdoNUki1Ca<n"0$0djn>?E$aZt[9T[?8j0!"-^B! + OW@*pV>,g[9fqQu?Pkp88T2Y%88ps702+fHXe9RcdK9aUOm#N1Q))Nc5b?l=(Dr8EtQGB<) + rl1DuY>'*2f!S3/`uYNe;7Kl`n/[VAo02rc_7nQ((qpM$&LlrWV*:R%UIor/WFtT%e;E]ab + 5O,lejbN=^*=\p</(e\1u^X8L37q<fa1)9/&_VE#uC7cN2pQO"FsUa<nIcr<r_ARP=L]%/s + _17a=h7?.(*B\:IWG!>`a@anu#S3q%MR#q8Kb[8PMo^]m@I%0?itFB;.N@,>kTK\+!rK!&: + cbfZ(p*J,J?^p$2hi]ZiK&WMrLl;X0CcDg.gHB[9(aFoOe-Kou+W4^W.cBMdi8^,,343FAk + lBPH1&EI'q=<Yo[[$h]ljh-L#3"V;gM$CdBk@`t)77uZs,"$L@\]=A);4WJ`so=<rU%Ac7i + e/Y:h`q9kil'X?*pFgtM?#UHtc/f],OT=<02@@'Gs+:hH4Og-e0_L7727Yj?/(8.,UZPe<< + pC>j/WP41.m92JXA7)l!F;:EEh(12Z=T("!+0eDfVYN?s7UB;]\'u`U"&kY>EE3W/lrU40C + l[;#9poOGPQ@JRekZH,L;remQk/BfHX7mqm/coJ2sCA<`cL)a\T34NH4h2_L3ZDo6aZ>^Qs + mZ_Y?U]6e'fWIOuro7BKlZi5HMq\^X[R8,rpM3"&qo])"MG):uKE\m*WDI(MF*WJsMu>rkH + 3m?u&!fcP>1:"ssbqY^?eZRtUH#_b0:'ed\`iSko84?`\TmONcq!_<;G(H*pb`MYmW4<qb7 + 2d=2=SugF3Xfck5N4opM?e`!<NZR$T+9->Lo5F@[<3In15Majof*cmAHR&Sn'162dMcW(8f + LT(E7\iO<[e+!W&*sg6Nhk6s[qeKom.Q?E9Q+Z$\t9FK^6ZNi4V@_rVUNDJQEL5`f>i"#RV + I-%VFEc0\j#mn+;0rTW=@b2L-$@+mu;6k>OD,*M+`.cZVH_!(]bnLHPH2%V)>E_F`?D)egI + :%Jf&nZnmO?/+,cRC-0p7$k!WKs*,=>0EJ?Uh!!;Jh_H'^?h6Q/AXK6N5,;hXTq:/84pB"r + uM0u%EXKm2YZYt%G'^@Z]m#_8ZG]skqeuar3q*.[Afe_IH(`aCfH3eGq-AF0B*_'O[6f\+? + IGT?md@G,kWaF'n#loh?]u%MQ_S=aYdN9OIo9B*GF:mGcmmTF12H&3h.4OPE7u!:phVJLV* + XMh'j1W<54'@[VaZLkT!I3O\OU(i\.4_<CpTuT'C@I'EN-?qYm#_;+.>rm#'"PF?gZ)>n[V + nV6:1\.SfAQYmJ+oRiS:/e*>M15%5_,-:NfECnIh#':Y9RDhZF$BQg4ZWTs4<CAo#`![!&C + &Y2EgV2%^to&h6T_%7&cm&q+4:X&$>8BkhjB?BktF(G=2+f^WHO%-aU[e7G@Sil$3crqGcP + ']oGnWXL''sA[#<DbOeX)8-"_cDdh*=+)^n/oDhB(I*0b5m'=/b?MWchZ+#u]&cd;&p;3[p + [RTc-)oQ;\A6XcJ"cV7m;ni4p!GDBV8mC'D8@5Tk!e;B2;V8FdnpW*J[<8pmEd21jlFQY$U + [OILp.,2QQ`,V/'\NRA31Q*bSlP'.O`*oT3#Us0?[JUKl2NQucYm+B,6>T03[sE'2@78):F + igunj.@&kPiksqB&237fn4EF]d:6Omb2W?[<D2JUK?FOZ<XoZV/Gb52H8(MsQQ+i)f@tCtm + Q\G\enCnQ/<l=&.'+RHidMUb<nlkg5lS*QqZinD'>NZH\u`p^HMkro4m\lNdLYem@!)8l&V + 9Z_s$kW)TcP4"2WD9,gmu^Iqp.!-"k0_MZZAi/<UR5tr9#Nr;BBJc^IG'GeFRXAZ+C5AAn! + ?2_\$dao05[%X_nTs$sM'ju>/=f,s5+FRf%!/6+k[=&+V].uH(`i/fB8mbg'OrT10T7'A3a + i`uBmA[O2OhSO0,Voc8s*H`2"XX/3P+nQGW+pTTqC2T/S1#oii<c>M.C6@#Y.F>AUb=P)8V + k5-.))n7El7@iNZY8rr=A..%7%4mYR$OJ.+M*2S=X$:f'c7=D?,h,KgjqtF_#iBr$O'rrVT + =:<ucbO6"(@%+'#>A1,r'Z9SN9.'*&P>=9R7-,#9qRs*SpNWr&R`V$A.%;-3tTdn3>7#%um + ?<Uh`j=!)t27U_DZ4qN"HEL^[s:j)K(Ub=t5$&l_F0mlHi*\-#&YdZ[gA*Ib?5bb!W8/U5` + C4qK=o]W;us,HY^#Tt9f=<s&B9YSTsXc(p4SFi'P+Rr91,bF[$V5Un!QZVnUVkbt8!""Cs+ + sDA>W=0Nn8P<'uIR<mW"HZ/&//$JLPj57-3[lNC^HX&n8HMF"'G_#A$)Ij+\5##h5Q72F<= + 'd&:fo!O-^>UPi]TO$9Bcft5Q[U_89iH12+,?0rq94RCD/t[;-5)r/P7TlnXcBDSh'jh-nL + P%C),>l8Q!7tMY%Vj+LigNP00Zs^+,V@UAji?dMF?_J>08=2BN6\;oO46;Ul.N8meIrJr%8 + f$%4YEBCU(8B<<A.peb-=ValtD=0\CcR;1UiV6<o"_*VRmZlT\6SZ:=<YO:]N:Sf^H!!,Dp + Oj$!&htl@0qPfWb94,"*JqCi`aZUR"YD]_WWp@u(?a]q9J\hI1O71Q:/#KA%s!)sR!q8D]$ + To7$$;WeAPPs8TkpmR#s%umkc%f8'kJ)C:qVh\:EtfC'[m@u^;Gu$5^+"L/!q7uQ$f#HMMZ + %Wg="jTUoHap][jWfs4ptBWVgk!^pn,u90`Z]tYe^-P;/3CorCe<8CB%T963c@8'Ge45pQQ + Si@R#o)PJ3+Zp^i,_3qQ^SqQ&8ps7i>\[1'ih-nK<j?WX8>MXb5QX4MeGI5qE!'ab=jij3X + k<#j=f?2T]S'b.rC-nN`UO/gjYK9KH:#iIi[(5Q_%MZ#[-+mFn'J59!D+K@"c9i80fkJ&Nq + >m'Qu$4Ff3Br)$5(f0TAWp!O4QSnh`'GcMPf9GR#@Q]PqX60GD^:F?dU9HoL5+uFMJ+H7rW + uHR?$4Fd`M2Li!Vl9b_QG1-8#bnOg>dc%<?H%0/%T1b0871BWUek/9?;E'$=2fDJ]3>%L#9 + \`;!X9^(A(T0;:J,!V!(9Xc^s"hSj6>#[(&tW4Pn(TV'G`C/7B(8V`j99S$G@j9YljJ4Ka! + E`>H+2D`q03o+apTtn/-i_SG9UOnat"&jhI"nh>qkX_?(4l;)+Y</=!s+!I0I<!Y0WSW<"K + go,l:L?h+1Z6X^#Y*`jgc`H(D4VlH>T^?P`DK>I[jXB%'IYATZ?l2c-^_?*bc5CA*`@QCD: + CB*0_?haU`5[a[t^(fo%MC/m4\,Ie(m/q;HK`s#bq8k]_r3Z+(&&<#r(9m!?V$<r%:=$)Cl + o3@Z56+b^=MV)cW#-&+h#S-.Ka"Q9D$NLEME:\885B3cm\-k8F\aI:9>toe:?%*15iSNBJ/ + ^\L@Q_td=*b,PE!_4%>]RT:jbt1XlM0KOOH:kAi0(8oQ*+RV5PRn93<6i('GbZ665@].ejU + >RZh,XG?laq)h"-b.4]Euqe#QF/VZ?e0-nO;Vbpo$CQE"9eVkI,%GDdfU5bapUJ?-,sqF#i + E/FR^Vhk-qs>gUBgF]M&2aNk(k:/G'.D4a\1SCA8Gi]iA/8%).+*`oKLfBI2D;Z_Ie$4D)d + ZARbF>EmZEfQMspbS<:6;0S-E(BEG]@0$md,GoDIUnjshn#)rKNbk1o4n?2PgT8lck6?H=: + ftLP$WJZijas)u.Vu^p4oC'&(#h#HJBq(p^`203.RV0q?MO'3W0(ro9N7E$>,-H8R4,kK-n + O;E#?<<fadaEW'Xh:u*a><CnX1f@G:5$#RI;QS7E';=s8*CJ7CGpQ*aPcB2sLhI_#cl#=MS + -6<%MZ^%.D2ZU-t&uHmU=;I_l*,N5>X&H:k0>.dBSs;;6Rag.>gX?3/-BY^jc[X'!ZffCsG + jfQR(:r$=M%<d0lP3'^B8Y^jd2\$=ageC,]gjc//X[2%@V58.Z]tpO:3Ngi4W,?QLiX& + oXA&W4$OC$<VL9<Gm3+U$4D+IY@Dl;[Wbd+aZk`..C/-nqb.\7oE!`6@0$tF4e2J]0+W*2Y + \dKK!P!`u![>@X<18\j7bu\XSJPQbCc`^%"5$"M!@cJs/E^[']?dh#[UXRd?ibrbUcbM`3V + 0.kpV*m!hKtn+b:A,<;-6*1(_t56^4!kl[cJ6d#Q!pZ/J']F$OD&H`H(tC,CO,2gFb.b]V7 + miCaHJS<"p)ZZpgsF.dH9Q/+(jdSfjWV40cF"LlT=RZ9G3r3PYL(Z+8U9MMLkBHmT31-OL7 + &qHcig'\BH+f\F!q7d8@L"#Iosg*)b`!:NEd!HI^2e<?>i;H1$/[<6OmA)4`^Ko=9l3_d8e + GN46<^n4G*5hq]*/Eb]!-aXVs>sn;=MDGVIG"iPZlePZL!Dln6(P\ofB@sGkc-;a7(YQ#hB + N*a;<TQ74nod\>&*r$Yp"1d@5_JJK5OJN4;-:UE5+l@F>0jgmYjGV_2r6)iIdupoF'IbDHF + L<fqD@e/+!_@($i%Qe8p+!.cU/3PmA-t98o<V.Wo><NDp/crC55FSn/JqTT8>noUTf8EbZ7 + S:f<2)3DQJmFZL>M)HZO&c\V3I*:DL(uh0>S'&g)f2I,YM`QLh<[3\0p@[]?T8;fR+Lrm&X + F@D,n"nd7PoK`jeP!WO"2U7MmEE3MW:h\FjMHY)<8'6EcRqscI>/?_=5Ts0&sXB/7pAnGdX + <?/b%meDdqVN!N,QX2d:4*R_IpI(;1&NnDFM1EGErp_S:;H20;S);G3=P.dk\(4n>>[73\F + RcBfN<f;&n0fjG/#-(nZY@l2>D<%)B;2DEIjV17Dmjmmn!5&@TMM]X/jD%@\56;C=#R(W-R + 0ktlIC%.,Pu+leG=94`L'7\TS[U:+t+iji%*\c.TJo#^\ZIh<snhr:s5`)neDt%cM$3!I4B + Ahq8ir]K#.S<1IaerldcMe[BT%G\@eP(O-$!(5V+<7i&@-*e<?JqEp];W^F6gO`k$<EneW% + T/H81VY+EEm-j0X+"oRMp1&[jApV3?fARX?hiIO0M\qg4Q"JVWpJ.IW<;9rl>4$oaImh5Rm + <.uAA5<OLq-nO:D+&l+`d%Ql$OBc5Oe,DTS0:,b1f;%D^-P.#H"aoOg.[G/HjAPNb[VNI^r + `[.4o<1p\-F.H863'ha^n6@]W98q#S0T0,]@BudnR-W2[Ear-T0VQf/Ds;s<7J6j=b#t5hF + f9(WNL8AH-X)#QX"g/:UqMt5<j_E;-:W+5,Y-Ho^ij\:B>Dt[?9PcefX*SW5m!*:S;bC(@\ + 6j/(I?_4b*Ci>k*QgW4?ocNRFZ"#A2\I/C1kZhbdLk\#-+&k6kW6.A"h02:enA?F\Y`B;2D + JDtstPFFq@2^@`Waoo'a89tZk5g6Ph$mkT9c[S.3s+/(qI-nO:\hbp_LJqB9IX`Phq\anNB + K>Qd:EUk=gkQHSCr+rTpH@G`qCCasBdTF-,lo):YB?F"Ii*If_i+IsJeFWIqUVmi1SD!XLY + N`dl;\Z_X$4HX^?`L&;lI7BT4uuc:1XD_u(\BEW.14i<Ka%D@.A]pAk9hQE?+oOfPO.(Dj2 + +]H_WL+Q+e9fA8:_7J=MX)(WMjIa[e\p>FJu0f^"HVpFh4(?+9aeo@0*!iX.l2`T,oYW8E\ + 42+^:rCb7@LD6PL=*\IYa>a3P-N@or3o!e\@UkRmB<'^-*^"ao_W.dH9L/Zk^TUNdt'Wk#d + ZTWl!'rYD%S5>-R>;-:X6Z;f=pkg3f/6oriG[.2pPPIG":F:\1M$J^WX!ra"RK&WF#,[3Bn + cBZ$s_k=4KHD(0e"n"ig!WQB%U7T\\5'W+g\=;1J`:J;>r%&$>7UZ>tqgs]Ok0<3:hFHboY + -'PWc;'QuQQN-@qbUD1s.3(;<HWc%F\?LfhB\[`Va?mEG*kCj]io'jO&Otb-nGo8"'!ckmb + A0F6ooMMcn'gdQKuBXitQ_[$4?u'[YfD1n:s$`I<=m\_'4NK(@&0qitQ_[$4@!R8eq#Hs82 + PKpX-PJ)f*[SMJ^i\ne2bJ'86SkiSuEQq='/pM"f;SJmD:`$<s?Rb>2*q:)"HLKGZU/N>pJ + T4H<I,*LgP8fJ5ThI\HmfU9Hm*Cf)Z\Fad4d<-@k[nNK!8<P68CYk`U8r'U_V6t(Y>(nm[q + !s]TupX-OK3l<>uea#p)TaJ0%YWu%'n//cEs*BEE+0?sHRr)!SCV$/9:^,QM=<K"MWMjIQQ + :1L-EEIM34G1LWd)4q".aX3m!^Z@TML%Jbl/CWA[%dEV15!I+km8N(,!T.[2A?o4MQa(ZBB + dinic2?"\R@kneqjTnXju7hk:4i5_?*$nXAULIo.siD2t8l]ErOU'#)02/"6AVpd"]C=!Ra + V`ISs*C)B(Mka3fbpB-&`TCp>$15?ECo'G^t9;(CkQcX/+B7k8=)<Z2Z1=5Vo0;rpM"JuMn + NfmN`p=<Kk@W2OA'mK^\jBLPSc`nYDXDoLS_4iIX`JuDFgbLI9_qlAG(!^3t_O"T!.9D"#J + HIsN,Ud>TleGZT:^/_c=%Ge'SpC.'l)K]ST:2eNo*W4fjYX!^i;c1joIlUdsNjb1d3RaY*i + @u`EWt@>M8qrOEn9V_,pEpXFosd=O-62,F4oD%gDu7ljgXO5+C6e_\!"d\9<7LO3e)SEjBM + 7HtKa*/^I,?)2Xq<3.SJ&Y6Fct>drHRP8Sl<shac?o3;11o&4c_]\9Y?=mgq'rJCpJc`8&U + 0@!i/-n[%:>+$O"Ze.dC0FXM8utXU/jigG-fXZJEm@`.p7&ihl/.7U@Mp&2<!C;,;@YQ@'S + ;\TiA-_.:0RLPX8n"@@b/P,H?!=9,gQ<Loa*6ScWeB[QLi`<MO.5`ZX%h=/1@:+anh?-4[O + "bNYElMP1'UkD)*A[J;-HEGk>$f@G0%rh=!,sB2[]M_iSG_W8tVlD3YT#9D;J(J4`iDufPL + _"J"flc,ke\"d^+F*<U;,9JDJuj*0F6WI)KAguNh^:V*iENd5fCn;='GeKr@T_r<kg3f//6 + [.jA?!CabLbcYH'01/d]Cn;/si685[moqU7Uc,kDO!#U;jceB(IU%T-?JCiBnFRE"DM3@=d + ?>V4sR=rcY/`(@<T!3SRrU?.JnlLH5:pMB:\M?7@E:4I]@#oABOO[WiJQ]):-,KDAQJLPsK + "pe$P6iE9J9/.aoc;c1jscV+mgU0T_$Q5e&W>Wj7K>HrEKUX$r)D7Ke'"VSYL<RgWJYDj<9 + U0T@1)frKW4NXa,G8D@fn:U5f[>OW*0CqeEJ`->S(%j]gpaGYZ>'KtRBa,gMMB3m(gYiBT0 + :/?95U(GX76R:Alj3,(>'K)P!sU!Q=H=/gm1<?qH[DAd$4@!_=&d\58.Vq?=&ZB@Cs'0L<: + L8*6-bfijDLMj;nf!2AmKi8RbB8BDdHUR<O1[hiM+KML#KfAQ06@A4#X#/i67A9B:Rj<X^K + J>]U'sB=<N^>Y+hMC*Z?LL7-e$F2s,!6Gq8TcmO:?\+f/>>($[L`Dagkk0/@gl2Jp*0Q<Wm + &7HoA$q7-MK(B6rp4WjI7@.>ANU#aH9#356Z*[Er4+m":sjtNtT&'oFgU+L/?*;R,G+;Wj3 + ;:!t("3#'>L<A;*"r":5Nu"AZ&5fG(43VL!bLtiY;$m[VMl0P(Z[@%JnJ]!4mb0.s3SC4W` + MYj]k'X^-hY'MMeSC_hBIPJD.,Rs#cbbBa`G=[pd,t7m9V,d=6h_38q!_2Vmo9+/SAW5#-s + c-578%'?5hVm+SiLk<bLb)](QZcu(mUH[&Fl/!cU='lN-(H=bGVF(5(g]R6'J<05?"IlM5S + ]Hf8CC`9ZmK#<da8O1Z`qe_n6cRT,qb#6t(XWPcd&3P:#r::SCGHX4N``bQcllI.G/W2fp^ + .H-L\M;If)T9<VG)$Ns1]lMO>JhFftbmO?dO`F*Lgf6tSm5MT;C1G(/EW*!Ksj[rs45l&-O + HKNN?,Mk`\>WOUk?ufT'pPI4G\>huq3aXL:RCgi2bE]pGJb$1*H58*t-f./`gaHHC0KJatp + f<tsQdEU!M/o!8Mhbr#6<;rlV6E3=4fP0I'e9pgqljq+DQPjeT=8oDnI!&X=*6`_GqIZ)V7 + C#em?]>W"Tmf?.dC0O4u%7B[4?Q7WkerM%q4u>^^[]_]>M;DDOXa8[DmpP.YS$--&0+O+8X + =qnHc_knu;Eh;m]L7(N0>UZa3o2`;+E[$4@!of2U8knA>S-Cn3ZD]X6JT5"/6QnQ'I8$3(A + bd3BXn[6/)nCTg_F$O"V=<RgW^:F>#k@IM_$\06'sacl(+Fa*@(^nT"uOMe`&Is"pfZ]j5E + 'Ga4^O/o5BF.XBp*^R7Mn"4JO:9Wj^i_b4XeN1l^?EGiHTWg]NI9o?*?i&2!nH-;hau^+N9 + [mN7;S3CAU0_Kpl1%O>H@*3@AW+_X-nGpWO/f/AM'p<!(XR$,=&td7eRk@!?3`I>U/R!BBS + SONQ07KdQ_:QJn3*SASfdl<U3H^p(2DNe[saFU>eR+`M?a1mPrW/';0lV^CWM,E.YS$-AV5 + kdIeL+IiW\s>GXra3f#rB$GTbq_293ld$MS)CYZuds!l;?N76Ss]5?g7"*k7[5TYY_%d\Fc + #!Fp8`S($3mgEtdg^=oVh.>7p,A\O%Jp?[&i4F\CXcUkG\gS?XD9*#.>3k[e>Fa+"8rVU+8 + ?_nGP#aD;<l8`k$V$/_?'AAuNP0$q52fp_C=<LpNQ:kID51eOj.>7p,AXnX(8kV>E-((op7 + qS6L=Zo0c(Pl.H*p>;]7Jisn\Qja'!l6fp76Pd9hL(2JhY!V^#*UrPNt^scic7ulFI:[m*K + qCZY4_]=8n!99l)d!2h7KSALX.d8R;"Qt)g%s%2%ZMeh8S>nM6NJ9Q:nkY.4c#Y>u^!"jN) + 5uiU]t+Sns%)HX6@X%gQPUZE[Zoau`LnrM-S^E-tGM4YpaE'!Imn/tJAF0QJi3@H-Z>/2$0 + 1%eElpjpY%O92J_5i4c4cT%0kHLf_nq2bKDT9\hfoSgW4ehf[c,@9s=b9kgaHr)a#S"bPbf + <Rd3@&(\9iG^c++hHRR\GX9]5>IplQjV$abhHtJLQ0@Ot_?.QY8OYeaYa"p2MI)]c0Rg4jI + c:sU]eo%3$d0iR]Nd'T@=`r5UnXI<rGIqn<:S](;tCI<DlFd$h@\O18uWm"0X#'.k(pc-.4 + c#Ufdc:?^]-UaWT(=TQ^/Rai*8DgUf4*gJdu&5"!$I2k`r,!9cbsSTWg\sh5@!=$Q"t;Ti8 + Sm/C!!3d9mI9l5nqB_>Da7=>!HX]ghp28R[1#l)m'3?+Qi?Zttns.KYM%:H'-0'mcNt:iN= + %SWWAg\O;k,EX<'\"PI._W+Wu#*mu9%7ci<W#,A\1NtQ@<g4aXkGs0;Y?7Xl=+T?,OYX%]* + 8OYdXf++#d.5L0<=.'NYAt:8T(::?N>iPDo+b0G#LVa)nnHfs'4SIDul&d/74BHU5S%KJ?X + g>shK!6`\a'i9^G"l\^[9id-pua%V&.kmBeFUR":6HYI@P/XjAMBFnojI="_"i#-goV7U.V + 4r>FGRd8!ARkK4jQ>W>C**$\X("O?nrP_1#dUQEm6YI:lfU@"+..XOn^H2,8:n!LqtS+3H] + ))oLKQm?a[mi3&g+2n]E,`$[S2X]O!_[gV6ig=<Im@<@U^cI_'VmD.rFV\*R[Z6C[Oi:,\K + c<P#YaAWg)jmdDj5KeI*9A%>!_-nGo40mo(-`f/u)DVa-kNm9?rd:IX&G\E7=XmYU2YIWC8 + 2H6jpJ)T3&Ka!(d,:_u(o[2XGo0c^2q'?5D3a[p]DbUjZ]"M?XSAW5#-s\>%Wp:@Q"bL-eM + L,:$mjCcS'4HkXlc]QU^!7<F:/VD_P[Zf(@9tUZRP4Z'Mh](M5qkSn4Zdi^C7C3A_S+V,Zh + g-Y.it7W;Q^6db\QbJkrr<(d3/i)"@4[Uoj#.sF?BNk<do(\_774PLP\MKH/-c[*9K,.kN' + Y:FlG'_(f4>MpRY>]:VV>rd_j!>W\5nZR+Q\1Hq:/kV^EA3lc_K3b9^mQ<f"N=@RFQ)hg8< + k4j02dQQ@Kfcs4?%Ci7khDW:=\GV(h>93f^LckDKi/Dtlu<RgW"DiBf"-@Tr`h_]tr?)d^Z + #:SP:eFtuIlc$cU>qXMJ$4HXc3#2,al;od;LP]AC5!@e2FI22'iW2Yf=*6`_GqIg@h;#5#q + umiH$4HX`pQ`m#;:!q%rd!e9YaY+t#1GY8:MA.TiYb?f(7%U0Rs:t`E1c6eY^jJOY+hKg"1 + j.Pikr\f>+.@@gM/L]CNL*W&ga>#SShlH7#B6V96?!,!rfVo76Mahck,G5i\)U]cS1aF'mc + NtN"SoWVj-BW%eEkq1Jdp;AV@o%r\dbF4`#1cT.=Or0Grj5odK>O-(`;+OMe`&Is"pfZYt' + bGE0NArYEDSM)X;\kJK$ne5`Y,)s5C+>s(]8UfqCkb\Q'.P6/$pU-fV1n?F??e<?;gHL"Ts + s+^!.:s5`km1TrkH+4.><D"*jjV$UEjRr4eM9A1f0$tgL$i&@A.dC0L\=`C1nY=Nb1CZg"\ + K3:CVSpiU;iC9]LGuH&k8&riOIW#KJ<.rP;9sI$4&1*\psIXi#7X.KTcPH8VSqD?\O>\5RB + ;&?KKOqlI&sf7H<ttRTHCL^f<)('AqRcoB8G_"kU\9OfFtdV&fm^NJ7!_-76N(KWhNt)oGI + +tr10#\Ap]g2/RGA@X4?$IS`TP<Ef'+5>;";H$4HXZ)AVqhR*eQQLA4j'YrN$K]hAqOO&U' + Ul1>$?f&7'S<Ug^l(QTjV(@\@Z.dD<EWU\Cm`4s0Ag0hSVlZ(pT$7IFJ--D7o&V&op6X^"& + H<R:i(%pqJ(\A5B\u;lWS_9+.f9tX+$DIkjcs^75]Nh0u'Gg27O/o3,.kA<<EKg#'n[66If + `lNsRdM\4X2&_h>U'3Ea['5cd3/i)psNC^omHPP$X-d7*M#1\o;@';d)Y/=g-\M:+&[o#og + ;m^qk9&fr1e0(_FOX0$O;/2rdqDWL;F"@e5o(%^\m1H></7G;uc15F6^;\rN1CW=f&SWKig + 11/jE9A1&0pZVnGmpQ%$!JGlE122TA8~> +Q +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.svg b/testfiles/cli_tests/testcases/export-area-page_expected.svg new file mode 100644 index 0000000..ecdc717 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_expected.svg @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + width="120mm" + height="105mm" + version="1.1" + viewBox="0 0 120 105" + id="svg10"> + <metadata + id="metadata16"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs14" /> + <rect + x="15" + y="15" + width="50" + height="30" + rx="5" + fill="royalblue" + id="rect2" /> + <path + id="MyStar" + d="m100.96 68.703-20.799-1.1756-12.76 16.461-5.3089-20.138-19.604-7.0445 17.518-11.27 0.64404-20.815 16.136 13.172 20.002-5.8198-7.5458 19.411z" + fill="red" + stroke-width="1.5" + stroke="purple" /> + <rect + x="29" + y="21" + width="53" + height="53" + fill="yellow" + fill-opacity="0.7" + id="rect5" /> + <path + d="M 56,69 A 18,18 0 0 1 38,87 18,18 0 0 1 20,69 18,18 0 0 1 38,51 18,18 0 0 1 56,69 Z" + fill="green" + stroke-width="1" + stroke="black" + id="path7" /> + <rect + id="MyRect" + x="24.5" + y="18.5" + width="70" + height="60" + fill="none" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.wmf b/testfiles/cli_tests/testcases/export-area-page_expected.wmf Binary files differnew file mode 100644 index 0000000..92421b3 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-area-page_export-id.pdf b/testfiles/cli_tests/testcases/export-area-page_export-id.pdf new file mode 100644 index 0000000..c567930 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_export-id.pdf @@ -0,0 +1,69 @@ +%PDF-1.5 +%µí®û +4 0 obj +<< /Length 5 0 R + /Filter /FlateDecode +>> +stream +xœe=NA…{Ÿâ] ÆöüxÜÒDB¢XZDˆ”%ÅBÁõã4hdëé³ý<VH¾ƒf²pîÅ}8>n´’ÎÒ×ï‚ó7 7ÑèÿÊ—#*[Kø!ÁSÆ'½¾e‡àDÏX±í9mtÖ1 QÙn0sÎH \uà:•´€•Áâ“xg‘–„Ô„kIÔ³ÙÊlʵ‘ÄâoL9Ì°¼&0Í#;T<WMà•KB¤ñNšñvÖÆQ6—Ëÿ??b¡…îšÒ?a +endstream +endobj +5 0 obj + 197 +endobj +3 0 obj +<< + /ExtGState << + /a0 << /CA 1 /ca 1 >> + >> +>> +endobj +2 0 obj +<< /Type /Page % 1 + /Parent 1 0 R + /MediaBox [ 0 0 340.157471 297.637787 ] + /Contents 4 0 R + /Group << + /Type /Group + /S /Transparency + /I true + /CS /DeviceRGB + >> + /Resources 3 0 R +>> +endobj +1 0 obj +<< /Type /Pages + /Kids [ 2 0 R ] + /Count 1 +>> +endobj +6 0 obj +<< /Producer (cairo 1.16.0 (https://cairographics.org)) + /Creator <FEFF0049006E006B0073006300610070006500200031002E0031002D0064006500760020002800680074007400700073003A002F002F0069006E006B00730063006100700065002E006F007200670029> + /CreationDate (D:20200404202009+02'00) +>> +endobj +7 0 obj +<< /Type /Catalog + /Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000000615 00000 n +0000000383 00000 n +0000000311 00000 n +0000000015 00000 n +0000000289 00000 n +0000000680 00000 n +0000000971 00000 n +trailer +<< /Size 8 + /Root 7 0 R + /Info 6 0 R +>> +startxref +1023 +%%EOF diff --git a/testfiles/cli_tests/testcases/export-area-page_export-id.png b/testfiles/cli_tests/testcases/export-area-page_export-id.png Binary files differnew file mode 100644 index 0000000..6bf9b04 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_export-id.png diff --git a/testfiles/cli_tests/testcases/export-area-page_export-id.ps b/testfiles/cli_tests/testcases/export-area-page_export-id.ps new file mode 100644 index 0000000..6de42c9 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_export-id.ps @@ -0,0 +1,130 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Apr 04 20:20:10 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 120x105mm 340 298 0 () () +%%BoundingBox: 115 55 291 233 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 120x105mm +%%PageBoundingBox: 115 55 291 233 +341 298 cairo_set_page_size +%%EndPageSetup +q 115 55 176 178 rectclip +1 0 0 -1 0 298 cm q +1 0 0 rg +286.188 194.75 m 227.227 191.418 l 191.059 238.078 l 176.008 180.992 l +120.438 161.023 l 170.098 129.078 l 171.922 70.074 l 217.66 107.414 l 274.359 + 90.914 l 252.969 145.938 l h +286.188 194.75 m f +0.501961 0 0.501961 rg +4.251969 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 1 0 0 cm +286.188 194.75 m 227.227 191.418 l 191.059 238.078 l 176.008 180.992 l +120.438 161.023 l 170.098 129.078 l 171.922 70.074 l 217.66 107.414 l 274.359 + 90.914 l 252.969 145.938 l h +286.188 194.75 m S Q +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-area-page_export-id.svg b/testfiles/cli_tests/testcases/export-area-page_export-id.svg new file mode 100644 index 0000000..9fb1575 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-page_export-id.svg @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="areas.svg" + id="svg12" + viewBox="0 0 120 105" + version="1.1" + height="105mm" + width="120mm"> + <metadata + id="metadata18"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs16" /> + <sodipodi:namedview + id="namedview14" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <g + id="g10" + transform="scale(2)"> + <path + stroke="purple" + stroke-width="1.5" + fill="red" + d="m100.96 68.703-20.799-1.1756-12.76 16.461-5.3089-20.138-19.604-7.0445 17.518-11.27 0.64404-20.815 16.136 13.172 20.002-5.8198-7.5458 19.411z" + id="MyStar" + transform="scale(0.5)" /> + </g> +</svg> diff --git a/testfiles/cli_tests/testcases/export-area-snap_expected.png b/testfiles/cli_tests/testcases/export-area-snap_expected.png Binary files differnew file mode 100644 index 0000000..f35894b --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-snap_expected.png diff --git a/testfiles/cli_tests/testcases/export-area_expected.png b/testfiles/cli_tests/testcases/export-area_expected.png Binary files differnew file mode 100644 index 0000000..c9ded26 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area_expected.png diff --git a/testfiles/cli_tests/testcases/export-dpi_expected.eps b/testfiles/cli_tests/testcases/export-dpi_expected.eps new file mode 100644 index 0000000..b662237 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-dpi_expected.eps @@ -0,0 +1,261 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Thu Mar 5 09:46:17 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%BoundingBox: 0 0 173 90 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 173 90 +%%EndPageSetup +q 0 0 173 90 rectclip +1 0 0 -1 0 90 cm q +0.9 0.950196 0.9 rg +90 45 m 90 69.852 69.852 90 45 90 c 20.148 90 0 69.852 0 45 c 0 20.148 +20.148 0 45 0 c 69.852 0 90 20.148 90 45 c f +0 0.501961 0 rg +82.5 45 m 82.5 65.711 65.711 82.5 45 82.5 c 24.289 82.5 7.5 65.711 7.5 +45 c 7.5 24.289 24.289 7.5 45 7.5 c 65.711 7.5 82.5 24.289 82.5 45 c f +Q q +82 0 91 90 re W n +q +82 0 91 90 re W n +% Fallback Image: x=82 y=0 w=91 h=90 res=300ppi size=427500 +[ 91.2 0 0 -90 82 90 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 380 + /Height 375 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 380 0 0 -375 0 375 ] +>> +cairo_image + Gb"0WH'"9PS\T5"b>sR!5geEA>#*o-O@iO4X\%*-qcMm@A1J8n(%L39mSUBAm&DJ3@:ip8) + &VLH0Le;2,\jHDCQ=u(:dd_5R$mA&Hg^cQIr2eK@?;Q,q=WJOchCMul8"XcoqhP25Q/l$&' + n<a=Y]l$e'lpth:o&06UsLLHX2%i]jYpmGE]YOWEc85od<KkkZ$,8VKGqr2Qt7:-')?F?!= + G)ijoKk-,M'kinDa_Y#9\[mj_.*Y"H7?<B=H9>cZ;-;Q[:r[X5ERX3R;3b[Eh$MJE<8#+sH + ql'fM<%cb>QXprUk*6_gmNoJd.*6c5=-K$;T%EuX.b[CR5inD0fbeY8Gi$b`;beY:C@02JK + g;"]P_&Of[.'=$'_&U[-!fl9o^`:S7*%'SlXprUk*6_gmNoJd.*6c5=-K$;T%EuX.b[CR5i + nD0fbeY8Gi$b`;beY:C@02JKg;"]P_&Of[.'=$'_&U[-!fl9o^`:S7*%'SlXprUk*6_gmNo + Jd.*6c5=-K$;T%EuX.b[CR5inD0fbeY8Gi$bafT&-'15+NTQ)LQn)Zn(3Op67M%]:7T1a[& + Z[SCC0sPiP]C:jJe2Y+@8J=&<mBL&2KkPc(_":TKNDNfG0OW`uMS>:NYLZL5o^]q68;7GSd + NphA!N>+I^Oq2&*.=&cS.WB=7!h/-=K@W,VWf")4_-,TGS\%bupH$Akg.GUH:5tWV"$7cHh + 'e[B24b`3[f-_7Z,e=W5qmTl2p=qaUrU-66RJ4Y.-Q_1=\4TD;/l=VT.CL?Wad&[m>jX'!= + &`=5rpn1+]PI<1SMYNdlgF)i>4(:_E%g-H1oIM$a+\fHXgLS47JWPQ!`+AUq<iX@Lt:[kMp + 7;?:V_7!qm-[>0/RUmQ8t"DH1]KCbkh/A3iB@&pDCS.3j'T#jgj)D[R]13b[3ZXB246-2ru + _@&gd\)OaQ<$Fj*E08sW+8/g^,M:-^GU76;9Q2g<GM@7MX&6KOH-R(Sg]_K_@/b%H_>F-s9 + Bk$S\]@#gG'3LGFZR,d78%d%./ju>AgK/o<O3DL(H?k2=,Ng#)UR"IDdj5aSXk$S\]3'!@Y + 3LGFZ:(HDo%d%/ZPCkl_K/o=ZjBrJ[?k2<Y3LGFZR"ICo%d%./k$X45K/o<O3LJjf?k2=,% + d#`2R"IDdK/l[:k$S\]@#gG'3LGFZR,d78%d%./ju>AgK/o<O3DN?,=++8U_DaPg[Md\'kM + 'dlUU/QG8l:IN7gXkUL;atI5JQN0\M+ig=DZj,Xn1[mSLa8uVfbV[g:XgC:R!uAlo!h,VQI + kI0quZ_Im*`n=pmOL([_Gh^9&%F'p<bPhsPX3PmXoub)6/%oL"npjfeR[^>H-I\&PfRCS'A + ]m"2\^4SADHk08?bp2Bs*S):l]d$&B3Bmr8F5M)nuX.o;XR6OR>ptkQ8G*hVtGm3$KDHU.C + /QLqUp3(1&Gh[BF<W%HIWjU!um&=Zt0WMZM%[)/e2uQ!f`k`(Y%V3XH*e+(H)7_P8k0>etf + &g-+pk.3@>ShJ;okU`imr)P2RqlBEp=e%(?+'7'X&eJ\F\:))CNZ3sBkkrC=h1jI?U=^MQr + KT?I4.2Kj%T')f,p><2-I*EFnKo\Fj$RoNndUDS(o3B@Ie#prDE:biq47J2jfh1OsUFEJ+N + W&Z6i;fR:9.(mnp6_d8?[Z7#`oQHHaI\,CPpS8qi#%(j>$3.ok"Y,t[EZP/ho*mhL">?brq + (.u[+cR%AIDc+IP/a"!N-4A?mg`#Pmp0\i0,C37]T#KLIPPL#a.,sF-o'7#&sg+Odc:R4Fb + T"O7/,qq6'XEc$lNP'SfeLHD9>%sOj,[@91;:<CaM:4@W;gAQ,?1AdSASaK=d6(]U\Bhu2b + eY:C$.3,jk$S\]3'!@Y3LGFZ:(HDo%d%/ZPCkl_K/o=ZjBrJ[?k2<Y3LGFZR"ICo%d%./k$ + X45K/o<O3LJjf?k2=,%d#`2R"IDdK/l[:k$S\]@#gG'3LGFZR,d78%d%./ju>AgK/o<O3DL + (H?k2=,Ng#)UR"IDdj5aSXk$S\]3'!@Y3LGFZ:(HDo%d%/ZPG;fOia+F152IPoCb47Q;Ykr + d3QM<+4YS1/MC_rKr8qZu8(XiV7dK=\^2eI/RPQR.S<c1a2bc5\"f6mHKZoK4dgr=Fa'LPf + O)JAZQ25jMS'"MbS1JM.2=+l68[0JeQ'gW)1/&051O%u0=ng%L2/dldpebfrNK+ooSm7OaR + o3s;1a@u^3C<&57RcQ(;:=8<G>HAMV"+j^k=;EaV^*'+S!6m:,`eSJITG#r<n^Ab?>"2SE1 + q:iL2M@PI_BIZBW,^MX7)uGbhM:)4d>9I].b\o@"oZ^^5Vr,:VH_)l[N[%*N=5k?SVKL="a + OPZL=:WSX7'3kt@@LqP$;D?6"!*Vt)D7]6p$lb9u,9I.PZBr60Oc8auuSfcOd<*69h[h;n: + sBP_hmqKGg*Q.mU]$(X*6ljRd%\)"*p&`0'mGM\R+dk/\NR$McN]R=/\b%6pQXH7t-F\,p1 + _Bg"BML9jHjmRZeQ1(]bJj2j)afR#$RP-.)?/@X$,-<iL4S]&ps42+[D<Bo,S7DPXhi.k!b + !GGf]1_"DA9jR*1[!lCAC6j$3FOX4hD/&:53[ft)fA<^9k@VLk/W?>L>R%DkAGHQ%d%./k$ + S\]@*Soik$0b*q#=L_Yl0rA3LGFZB:Di^1j(]b%d$0.QugZB;pejtg!cpCfRD&\*6c6hZd% + as<4>p&p%N/@)07J:F"h7bS8OA:f[6X?AB_k0be]g#F+u]H-BH_Z=I=_$R"IC$B:q98/_,8 + t$=@4M%d%./jp[c2k"*afc/qO9*6c5=bS`BQ2+RY>]=6PaaI%T?R"IC$kH*f:2(^\?8&cOm + _&UZ:38\>.eCrH13LCIo@Eq;X:1\LCahJ+&0F)YQkIf$$9KoV33LGFZQug"(83q_])07J:F + "esIF1eV]be]gj$$._FF/4ia%a;bZ#RPQg0W2LY)KRS[6Ga]]b`Q'i>;-;'+sG18`15!4b4 + GRI/l_hSrk2pXfa.&^7[*`hiSD3;mTWS,Ol^!gk$ZJAR$2d4D(,gM8r>-Tb<1lS?BT3UfD@ + )opR8WXbrOZg_WpIQPOkkmX#7)XX[\nq,ZdmL/(p__U(fW/5Ge>-NCc(OXc?gK-/E[^Z7FR + Ck(5K]ENbcP-iR4Z;+XX^U=L-_:N<3J<TL3fYuL$Em-3mDOZDMtjkmKo?s,j"B2</aDtdZ) + lKKdt/1L'&'Y',PoG$GQkPa\R?VS_62C!!l8Md\c:=#@m@`8VTS^`D,E:I;n1s!TfXmPp2V + GE_I1WsaFqoYN#m]gto.Z+Y<6%?"BXhr@+0E6*;L,ih)kM!;MY,uU2k/\W&c^gEkc8TQhq> + LV?+.SQZBhHAZPGVqeSX_E[f^`HSGLSP+<6ucZh_H)3^Lau<mI"[kdgT=TPY>Gr^>(%'g?. + "[]^LX!SAF+JHt,p^WB#!s,j%4rq'"]`cnJ."Mr?1@@h,K9poU6:2Vo[&od["Jb]-Xmbfu9 + eAWGhgo3r3lcl$7ekff1h5t?,(k$S[i*p/.$S3c#s?k-<Sk(M5(q;2>QXq'TU<FJWnbo+_9 + YV:j6$?JON:3g>p=)So;KRKguKS2@Z2FhLqDnqmI06N/60ZO38gl63q$2[Vu#RPPl0LomGC + rRHh9/+C8F8Xd#@1En33+IsoB7`-3R,aPoeLf==6\II[R3S9q=!98QX9s$=1oJ($*coEn0Z + Qb+cMBnLbTX%(*%0!n=uokALMRHA*&a^l[0C]njtOhaEsDW@3TcE'@?/7fPRdK]/'K0;_Aq + a`nMGMFLTCr+Ji;d3Hd)\pXfLi2F,DK+rFd&00$&+s4d<!TcEo.[lf^,pBd5aaTi:3E1HfN + b\N/*1^AO2<j"e7O,PF;kWbnjQC*YfUB2<06Vf6S-hL/u49Tkm84f*KHaF.H*qF"c4YXo^r + [.]q#\1i\5V7>.$?"nN)/W.D[:S5#cMk._=iAKi&V5qRb04E]Tk'ZUqr6q*1O453WU8-S?o + c<_>g3jq>VNmsr(WIg:-CC%]8rP9Vqbd9P`^Z"0+#DcXEREg$^,5K1(GAc;m-C/c-`of`NK + +pZZIG^NHWR$XVoV;;SpU^kf\-&E"`@.BHek['4T4C^XZ\/r"C5S3V13^Lg:#_bU==>]lU2 + 0!j<,+F-ccZ=lkhW-C<Y&$6\i<."ER*m7<AHWc/5QQF_U[>jhc_aopb$W%*P*^['i0M2<SN + 18NEY]k&'jq04#`)&8MQ3r/nsg+3+7U`>f2*-kn,!1Fd.h\<q7cm&\jG,,m!4cl@NICX-S# + T4&44)!6Lp*<2@,Qp\<93FOc-7)K>T+ksl(0Ua4n?==>s(?U:t*3$NO)KX!"0IONqaQ[+C= + V^(Pf:4M,?XO@H($:2$S0PF3C>*DVL[5=g_JYCGfo8"&:RDf=F,ncm_]5s0bR(mA''>9=@8 + >J"3F$Vbfp.LVA4`.%$0K<S@LcNRk!Xe]C\-.e%TsG,7"RF7p8u.NZ6[YN&9D=O@PERR#]h + 3.S2L2q?k1j$k!Y"cX7ra9*3pa3M%F`omp;#7A4)^t+m(?1^!,uL@E0A!+MsYAc116[ULqf + ,bG+`$)jsX_qiHlA3Eg2Cm-C/cV[,+LdPRjVK_IK^Wt--rm!M_0afBbq?2E`\X7rc_)jR'0 + E+8BI-H&Uq[:YYQq[B6ofkZ=/P+ju9]k15E]6p:as7Jm'bq!W^p$Z*thAPGqW]jDC.5J!W; + sa(b(;7'<Yr<b/Y^O?N>t[kSj8@a%s),c4&Qc0Ig9@VY?A0+.iJgr"@cXPO,?GiG?h![ERf + E;gkF[+a3Q%0L>U"A(SgKNRm?lN*eR+^8ERi)^\'*9kMW-sHiNkV<SbM9Za5;2JcnJ%O,N] + DA0jMXN%s'/9'6DCT?N'>sO2(M#Lp;3f@ZqSp=<noe3ojubPrT3G3N&8i[lOoS=_M9)r805 + alq,A?8];Z63u=2Ccg6#`F,1#<k*VY0e;gF\LM2cXNk%/G^AT>>&.LD=0fS9P\":ATU-XMo + k2o4%6Suk<8&ZJDB?VM;9UMSacI4kH`Z1_hKK1OER/H.TF3(BJ0rM[`4ET^:fY.?,L^'&+k + 3P:B4*9W/IsXBA&.Kt5bXjEZ%\5U,5;'trZ7:4Fq9Sg81N_cHr2(k(OB'tDcKm-h6YDGJ2a + )?hq4!tC6WRcZ3Hq@V),bOIfb*:`H=@@ePs+8gN>W[5F+XCI%d&jQfji=SV*j'5ma.@8oLF + !WLTJW>F"Vb.'!WX&jokVp*R#\-ZHA]>8%+/tS=omO$d9cpZHA\["m\Kf:=('j`#Q'4X3CD + .&,nY4jokXf5g1CPZHA\+3u:>S3K&)5`Z2:a#W,$YOZBbWbZ<M7k*[79bhY1$hR7_/r#Z;/ + h\NKK$sAnU?8IXZHYggL-2u.uN8!O.cZ(nSe]jMR1]:_C_1M4Z_[8P\H"D9m[a+d#++EnKf + 7/4K;uW:gF10<'G4i7EY./N)MIGWVH!s7r(DY=X\mkIM_cI=L=m^7W#s5t/GGgnAFfohZnp + k\!U>^cNVjhbJqE)Wcr3C\jF10?jj_MUnh&Oh[J,\W]S?6k8I2-hEQGac.V(TlZ^6fSP7<d + lO\7L]HS0iZ*ILu5Uc24"3jug6:;9U1EG?1+VQT!t;Kf?'Vq<Ol,NB'Dcbpme1!u2&-B?kG + QpatV>SNGTMEHte41hR3Y&-^-5F7tme_]5C)At(f154N:0+UV_fRIf;*pFq@NN7hggp<U1& + cCER+bf1WsF(^t&gQ$*f*25-!RlRYoIN<Kc_O,3&Cd#'=F,7]#D<C?d*2;q7RlTpYHT-'/n + 8g+SJD"P[#:D^N*25-!RlPggpL4V0(phJW6?aU8&;;jnb`O-*cl@M<S1%37R58sL;#^G6U@ + ;c[3S1@H#'5U;RoSVKA*cEh%T.JWb+.5<hp/qH7,cB?F/EMEMn&_f[^*X_fp,S7><VPs,F\ + LS^AZ:2/T^)lRHO%DXcG'h^@6MSZt%LigY'W2/BXu@4;[EjW4?:2p1NJ>7B#bN`3q%Fpqn` + @\Tm'Cp+%MKZ>./Fs8&AfMDTB"bTX$E5]c!A%$<QtqkHMkcMTWa@h)AOX>8u3_lnj@S1!3A + &p&j1AsG@[jTV>6B>Id[0S_&ap6bGQ9E.W`A*D-^lKtK'LF?R(QnpdLF@C7>kfe>KmAD[o- + t)b9oCK>]LX_i,hL5ZML]V1L3WJZjIgN)763lWa"jA$/ro;i7#cTi#JV,sn>P=GJi(=9G3C + /-;&9Gq$lnR[U'-DnQS=i(XLcK!Mp6\e4=;j5AK)T^!k)aH5@uc'Q3cfoPE";#lD./H^3C/ + -S#BRtp0Ls)%q.Inp)GHNn@SY;.?k1j*k*VWJnq1u,+ksjRF)us4>:_I`/.?UDbq]$f($:T + p@?.lYcYO-_[lZ="/.?UDbq]$f($:Tp=_NiH?8I%O*oH\$#rmjqCPFB5EN^5pF8VA5kfc%d + I7W<\a&D?q\E#dNh`tMRF,<J/*&2*E$AB8tF"$SmF%3;N3HDN)rWPOdXng<3H=#5Y9J44YW + ^$#1KuBLV[7:a/+#`K7RSW#R?etVEdQ]Bj[:e%$r,k:A>7_a;(Gd4P_Pf>e`^Ge@/UGXfV* + g$N0LXtV0C4U\+t&Wjj_n,JW,XQP`^Z"H/S=A?&!nXX,fJfbR9/*E>2NZTD=a4Jhu=MTI.$ + r<`%^OKm?,:DLY(lsZY]BAkl&nK"`ZgE?P"mWr%RPoUSC:/]F*%r`>l"f&b^?BOcuM"USC> + ??TVTH0lQ1AQ-"a%_N&n^J'u]k:tK#dhAPIsI?(HjEj&q_:1:dT6.[+EF%AIMq]$>lA@;<Y + ES4pKo%hJ`^qh#%:r8_.0k]%n<L?-3KK0WRcC4]I0SaHMF!APmR/@fF+WJ:g#VjBh)p"C6( + J:&.$0K1e`P`P1@Lh'&k!Xe]+pR1k-"0OoR$6T'_Aoj,bR(mAde_trQp[0m3FOl0bIT>]L[ + 5=g_JW+oF#iBE4^h+<c)GT_`Z293bR(I5?dsM_D>.KLfb<M$f:9.D1<^oB_OU+a;q5'*3Fl + -W'1R%,X8T-6UE4KtW\>fZk+$*EJN77FQkMr1j<0gW[Y6a#1.T'_P%.r2fbW_'b8g>p$?O; + *0IL,f<45d&%pRdhRp)%krqGSHEf^U4'3*0n'?+96'U!R_;#s0jn_oA$_B_Kciq)3,d$`qO + CW?BIRciF&mnpX5nb)Q=3,'[QEgMqcQs`gd.oFsp;>cL9#ok$ChQV"Ij+b:d?8JCLU,c_Xa + '?+I3lCk'IeB;_o%#J\Qri-D0'7P&JK$Gm*7:jpTes8o>ALis\tncNm`qD!=+tEsq7cghqb + >4SkNskUqqu6#:<K(`-#8BHP;=Qs>;>KM="aC,/)N/LZBm3`o&>b806N/6^AIJF<>LjA:\m + 6'ZDL@@RVLK>bUL0<gf<PebU_!qYGJ9gY&"%@DV/%j2h#g9Z_5QWm:qomng?p[W@B@d'GOR + ^)W`ElpZ+R:g;>,S[-VKR:!]4[O2G$-Q^?6MGt=;iVc%dbo64Q]I5>qV:=#MLhL!<"/$::d + GCPh;)O0=Jmcj+!Fb-$(L,hQWkI;JeV]Ss`.BY5IGNT>q-4)bSX7Pg&'[2[BJ"J_nb6)hL< + 4_59aIZfMNnc2!HgG%K%/jiV(4kVt\(>+"=W?K_Db`fH#Nh,U@?/7f<4>i!EELF.X25j3c" + ZT^`Z29Eb]2($o#C6OLW(7=.a2n\S@Z-ibTY0I*%0"qkiol&Z96?Nbab]!Wj<`^F3(@8a"_ + X=3a4:n#]lLja4',F[_lPa=V^'Y@norm'BTj3JiSjYj)/o7It\k`LbQjMF3aOa/'K0+_jjP + m;q=drg!bd<@:/:6+^n-Ec1/5fc[Ap>+fiJM:n)OWcN.Jb=W?LVe=>7Dg44st*3q'<$)ooc + DfROeC^Y;NB?jn&E\N8b$ZeXFNr6A!r-a*_6Z`XsKZos:5H[&r*07'ZP*kjfCCa.bS8>_.L + 6s3)%9p!Af*pfgkpc$XF)Uog1NI)`(e/rP-EC]QJ\*%Hk+#qbRDIeAprt7e/FdWoA!3n0,r + \K3If7mXp<9%p-I(7$94#aQ.n3dXm.0Tuqn@>C?GIQW-4rUV;+^?PH@PA]ZZ9ZG[V==ia5< + 6,d,f88(HQV"9qH:(Z(nRRd*pUukMJSX]UH9tN/o`WMj%(s;bTe88X4q`\adt7P&Iolq.>h + .8\%82Y?5t%gbS]_Rgcq$V+]pQ8YrXuIA'F%M3@cq-Ru=XNt[$0?PV]lmuQ=%]HO[2eYlqa + APHb/*VJ94YBdg0]n=)tcTQn;VkU0MI/g#m],UX=Yr6Og-b10,DG:'Yh'@PE%WYAA4h%<FH + MdQn%D+4b[O[\OWO4l2k(L\n`G`WKQuqBUW="PUMD'q73gc1P+N(.1^-'Z3`m.'F%=]\ec" + ZT^52RU:\(@\IW%Q)-qIEOY_))bA,[j1QEqdScjo*:#iYmP3R.L@?,i<hR%E%04i\D$VVB8 + >fcdQp.RT%a7-!r02%d$/GQt(b/mG7.q*#WfO#BMRH#]j`bCP+](k$S\]?qq9qFS0`a%d$/ + SQud8:e'Qq_oT:j5F"di?cHD_#IQicPR"IDd'=9bO>qIBn`Z34=*6];53Ro_3L.B6'beY:C + )*$Mc:1mA#iK5i"F"di?#0pAr3NlelqR43[beY:C))q`CnU9]4s1CR=4E)tZF"di?#0oJT3 + k@CPNf5ucK/o;TE6^.-T[5_Tk$S\]@*ZPJh&Q6j9(BuiK/o<O3<SGdF+X9pc>OZG_&U\8S: + Pb(S;*%.H.4lk5NZ>`k$ZKfk*.n)?hIn=k!XZcF4$BHNBDN>3LGFZQnr\8#BMN!0F)[5D(l + 390F)Y'c37WOcCpa;#<&@u82EiiOb;GsnZJ@FDn\*j<msrbopN^(1Dd>WML3V'OE?+o@D8\ + 9f_ei+B4K%QoA%T.X3C,&2.QW@osT-)J$M*5@!^tUR7;Uh.0l9.3Ur.&GPl9pcOB^8qO`dM + 3C7L#[I:d#SP*>&<$fLV1,@=)U85t>\bq?H=/`c`@`?[BIVum&UdS9ncGqqJ+(Z<:E;B6sC + $9@e06H>):/>5X:Am>mF_P?"=]:_sV+me,\!'d]P['_pQlKX;m];7J'.7?c1@Mf^f8Ye/4X + PK6Guq2\qPmOsW?aEC>)CR/B/M_RkD>Aic+J6mp6<\PPKf$-O%Cou2;Im[\]D7"jO)\Vjc/ + A5NFh6polg$$pB_YuKanI/l0[riWk,=DZF/,fQHG)NMJord4.'oKIs\m7s7"srm&AGm9fHl + lcEr('pCH:n`i4()l>)%nQ%lI^5&A1lQ*a:X)B1JUr7^Zjc]qTe1O%u?g_o6#(+%,*KmtI3 + _bN%YW+r;pj_A+GDg24_rPFS?iT=ZIUM*D&CR&jIT%n)C*6L#9G-mKW+ROa3*ftS;&]6^cB + 5I3BQ0W,EWf^Id[h^sgk%OQAGF67$q7DBGi(EKgnS[4RqW!jcQ2]Zj1^nFZ#BMR(F$_gQK/ + o<O3DL(H?k2=,Ng#)UR"IDdj5aSXk$S\]3'!@Y3LGFZ:(HDo%d%/ZPCkl_K/o=ZjBrJ[?k2 + <Y3LGFZR"ICo%d%./k$X45K/o<O3LJjf?k2=,%d#`2R"IDdK/l[:k$S\]@#gG'3LGFZR,d7 + 8%d%./ju>AgK/o<O3DL(H?k2=,Ng#)UR"IDdj5fEm,?uXae)F6[T'mJbIk`s!o$j2/7V2H< + Y?uMPR-69ANbL4X8$3otgQQ3F6=PZ"?8Gc_,\]D=ni/@>U2Vi(dkp[U$fa#QAo'T6d6(]U< + 5>ccSEdOt&OU-5RE_@?cM/g*I!\%;a=gp#jilMJZZ9]HoZs$,=WSs/9t5Z>ol@NOhV\>3Dm + +T^g1sb?jL`Es2Pnh_-0`"Kf;Ul0P(7WRk546d0JBsr3W%k'XH0^3A$;:k)#qm-k&pE@f<j + )L?'DpuVR9Il/)U)0l%b#\0&%t=Ym%CJp90>,+(\V^eA<46T6gC6Vmem-QlKZ1)m^W3j,lk + 2W6g.*(9!ad4KdPQ3]\qJr/$TWpQ*)(Vf^8QdbX'-/[R(2lIK_A])'"F(48Y3c+LQan#JXS + >Gd.8#2b`bmDa:uQW07bH4!pm0#Q`mWPthCY(T2EU1"@^$30k"IpK^.nWKG9b^40\A+R.RS + $uB@X](D6jf_U.U?$<Dq>TBrihD;So4m#qICo,p1`5oY0"k_Jeq+G,KmNi]ig4Ar79t829! + Zn9h>%5G!lO(A.E*`U"`a'dn`E!LlhNt2(<JFOSld^klWf\jmF4-BBl3iQnQFtag0;#;jme + aWT%rB4(V[@7j5b)_CUJrp_S(I)F"di?0ZV;O*6c5=b].YW#BMR(F.=5o_&U\8*%(u40F)Y + Qa2u.;beY:CEH3`<F"di?S/fbh*6c5=-O4]H#BMT>ah\t@_&U[=E\I`>0F)Zh*6c5=beY8H + #BMR(F"kYV_&U\8*6`DC0F)YQ#BQCTbeY:C_&Og-F"di?0ZV;O*6c5=b].YW#BMR(F.=5o_ + &U\8*%**8c1/5fIHGcrbXjEZN\-&%G0Kj>Y2:hdYu'(-:TTqiFj?L/Apo(1SQ"8,H]6()&M + @%S/"\g:R)>G*'[:@UBFloB(PWpJ\(=<-c<`:G8i@s+&sJ39%$Q>Aqk*jnfTEcdoB*eJs+r + \,;!GN7Sl7Wq.BY@"Lc0ac,aH&TjA&8fIHLIbAhcU7?WoVk4d^:FNRh.1;Fbq$7upEqXjno + u2G2$TO*sn"`L$7))C>\L;L:e^X](D'MWTer<h4([gUc.H?Gt^7?E886AHkBtHIL?tj4eKL + ,IO*Ag?UoH*d<fP*Y"<cPW"hBV0,E$kdsR>GbV":Sh@-H:iTcpq\!>%7r`BfpNC>Kpml8GZ + b*lL>br)C-a_;_--=p0eU"C0HFpOj6,ds]mRr41*lYO<3LGFZ9YaM1)jl7<R)9%H`O17WR" + ICm^en>UR"IDd_ZUsu[=L?*K/lW@;-Y'-K/o=:"<>CgJN9*M3D@4c>T9&_3LI\e*6#=:3LG + FZ9YaM1)jl7<R)9%H`O17WR"ICm^en>UR"IDd_ZUsu[=L?*K/lW@;-Y'-K/o=:"<>CgJN9* + M3D@4c>T9&_3LI\e*6#=:3LGFZ9YaM1)jl7<R)9%H`O17WR"ICm^en>UR"IDd_ZUsu[=L>j + YH4u[!mTurl,4Pge>'N3HMVrp<ik:UJ%e'KRb]HaCcH^G;(&V8l`@a9?Blm1*kBT'n,+gn0 + Tp>~> +Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-dpi_expected.pdf b/testfiles/cli_tests/testcases/export-dpi_expected.pdf Binary files differnew file mode 100644 index 0000000..9a2bb9f --- /dev/null +++ b/testfiles/cli_tests/testcases/export-dpi_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-dpi_expected.png b/testfiles/cli_tests/testcases/export-dpi_expected.png Binary files differnew file mode 100644 index 0000000..cf1781e --- /dev/null +++ b/testfiles/cli_tests/testcases/export-dpi_expected.png diff --git a/testfiles/cli_tests/testcases/export-dpi_expected.ps b/testfiles/cli_tests/testcases/export-dpi_expected.ps new file mode 100644 index 0000000..a2b5a45 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-dpi_expected.ps @@ -0,0 +1,298 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Thu Mar 5 09:46:34 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%DocumentMedia: 61x32mm 173 90 0 () () +%%BoundingBox: 0 0 173 90 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +3 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 3 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 61x32mm +%%PageBoundingBox: 0 0 173 90 +173 90 cairo_set_page_size +%%EndPageSetup +q 0 0 173 90 rectclip +1 0 0 -1 0 90 cm q +0.9 0.950196 0.9 rg +90 45 m 90 69.852 69.852 90 45 90 c 20.148 90 0 69.852 0 45 c 0 20.148 +20.148 0 45 0 c 69.852 0 90 20.148 90 45 c f +0 0.501961 0 rg +82.5 45 m 82.5 65.711 65.711 82.5 45 82.5 c 24.289 82.5 7.5 65.711 7.5 +45 c 7.5 24.289 24.289 7.5 45 7.5 c 65.711 7.5 82.5 24.289 82.5 45 c f +Q q +82 0 91 90 re W n +q +82 0 91 90 re W n +% Fallback Image: x=82 y=0 w=91 h=90 res=300ppi size=427500 +[ 91.2 0 0 -90 82 90 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 380 + /Height 375 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 380 0 0 -375 0 375 ] +>> +cairo_image + Gb"0WH'"9PS\T5"b>sR!5geEA>#*o-O@iO4X\%*-qcMm@A1J8n(%L39mSUBAm&DJ3@:ip8) + &VLH0Le;2,\jHDCQ=u(:dd_5R$mA&Hg^cQIr2eK@?;Q,q=WJOchCMul8"XcoqhP25Q/l$&' + n<a=Y]l$e'lpth:o&06UsLLHX2%i]jYpmGE]YOWEc85od<KkkZ$,8VKGqr2Qt7:-')?F?!= + G)ijoKk-,M'kinDa_Y#9\[mj_.*Y"H7?<B=H9>cZ;-;Q[:r[X5ERX3R;3b[Eh$MJE<8#+sH + ql'fM<%cb>QXprUk*6_gmNoJd.*6c5=-K$;T%EuX.b[CR5inD0fbeY8Gi$b`;beY:C@02JK + g;"]P_&Of[.'=$'_&U[-!fl9o^`:S7*%'SlXprUk*6_gmNoJd.*6c5=-K$;T%EuX.b[CR5i + nD0fbeY8Gi$b`;beY:C@02JKg;"]P_&Of[.'=$'_&U[-!fl9o^`:S7*%'SlXprUk*6_gmNo + Jd.*6c5=-K$;T%EuX.b[CR5inD0fbeY8Gi$bafT&-'15+NTQ)LQn)Zn(3Op67M%]:7T1a[& + Z[SCC0sPiP]C:jJe2Y+@8J=&<mBL&2KkPc(_":TKNDNfG0OW`uMS>:NYLZL5o^]q68;7GSd + NphA!N>+I^Oq2&*.=&cS.WB=7!h/-=K@W,VWf")4_-,TGS\%bupH$Akg.GUH:5tWV"$7cHh + 'e[B24b`3[f-_7Z,e=W5qmTl2p=qaUrU-66RJ4Y.-Q_1=\4TD;/l=VT.CL?Wad&[m>jX'!= + &`=5rpn1+]PI<1SMYNdlgF)i>4(:_E%g-H1oIM$a+\fHXgLS47JWPQ!`+AUq<iX@Lt:[kMp + 7;?:V_7!qm-[>0/RUmQ8t"DH1]KCbkh/A3iB@&pDCS.3j'T#jgj)D[R]13b[3ZXB246-2ru + _@&gd\)OaQ<$Fj*E08sW+8/g^,M:-^GU76;9Q2g<GM@7MX&6KOH-R(Sg]_K_@/b%H_>F-s9 + Bk$S\]@#gG'3LGFZR,d78%d%./ju>AgK/o<O3DL(H?k2=,Ng#)UR"IDdj5aSXk$S\]3'!@Y + 3LGFZ:(HDo%d%/ZPCkl_K/o=ZjBrJ[?k2<Y3LGFZR"ICo%d%./k$X45K/o<O3LJjf?k2=,% + d#`2R"IDdK/l[:k$S\]@#gG'3LGFZR,d78%d%./ju>AgK/o<O3DN?,=++8U_DaPg[Md\'kM + 'dlUU/QG8l:IN7gXkUL;atI5JQN0\M+ig=DZj,Xn1[mSLa8uVfbV[g:XgC:R!uAlo!h,VQI + kI0quZ_Im*`n=pmOL([_Gh^9&%F'p<bPhsPX3PmXoub)6/%oL"npjfeR[^>H-I\&PfRCS'A + ]m"2\^4SADHk08?bp2Bs*S):l]d$&B3Bmr8F5M)nuX.o;XR6OR>ptkQ8G*hVtGm3$KDHU.C + /QLqUp3(1&Gh[BF<W%HIWjU!um&=Zt0WMZM%[)/e2uQ!f`k`(Y%V3XH*e+(H)7_P8k0>etf + &g-+pk.3@>ShJ;okU`imr)P2RqlBEp=e%(?+'7'X&eJ\F\:))CNZ3sBkkrC=h1jI?U=^MQr + KT?I4.2Kj%T')f,p><2-I*EFnKo\Fj$RoNndUDS(o3B@Ie#prDE:biq47J2jfh1OsUFEJ+N + W&Z6i;fR:9.(mnp6_d8?[Z7#`oQHHaI\,CPpS8qi#%(j>$3.ok"Y,t[EZP/ho*mhL">?brq + (.u[+cR%AIDc+IP/a"!N-4A?mg`#Pmp0\i0,C37]T#KLIPPL#a.,sF-o'7#&sg+Odc:R4Fb + T"O7/,qq6'XEc$lNP'SfeLHD9>%sOj,[@91;:<CaM:4@W;gAQ,?1AdSASaK=d6(]U\Bhu2b + eY:C$.3,jk$S\]3'!@Y3LGFZ:(HDo%d%/ZPCkl_K/o=ZjBrJ[?k2<Y3LGFZR"ICo%d%./k$ + X45K/o<O3LJjf?k2=,%d#`2R"IDdK/l[:k$S\]@#gG'3LGFZR,d78%d%./ju>AgK/o<O3DL + (H?k2=,Ng#)UR"IDdj5aSXk$S\]3'!@Y3LGFZ:(HDo%d%/ZPG;fOia+F152IPoCb47Q;Ykr + d3QM<+4YS1/MC_rKr8qZu8(XiV7dK=\^2eI/RPQR.S<c1a2bc5\"f6mHKZoK4dgr=Fa'LPf + O)JAZQ25jMS'"MbS1JM.2=+l68[0JeQ'gW)1/&051O%u0=ng%L2/dldpebfrNK+ooSm7OaR + o3s;1a@u^3C<&57RcQ(;:=8<G>HAMV"+j^k=;EaV^*'+S!6m:,`eSJITG#r<n^Ab?>"2SE1 + q:iL2M@PI_BIZBW,^MX7)uGbhM:)4d>9I].b\o@"oZ^^5Vr,:VH_)l[N[%*N=5k?SVKL="a + OPZL=:WSX7'3kt@@LqP$;D?6"!*Vt)D7]6p$lb9u,9I.PZBr60Oc8auuSfcOd<*69h[h;n: + sBP_hmqKGg*Q.mU]$(X*6ljRd%\)"*p&`0'mGM\R+dk/\NR$McN]R=/\b%6pQXH7t-F\,p1 + _Bg"BML9jHjmRZeQ1(]bJj2j)afR#$RP-.)?/@X$,-<iL4S]&ps42+[D<Bo,S7DPXhi.k!b + !GGf]1_"DA9jR*1[!lCAC6j$3FOX4hD/&:53[ft)fA<^9k@VLk/W?>L>R%DkAGHQ%d%./k$ + S\]@*Soik$0b*q#=L_Yl0rA3LGFZB:Di^1j(]b%d$0.QugZB;pejtg!cpCfRD&\*6c6hZd% + as<4>p&p%N/@)07J:F"h7bS8OA:f[6X?AB_k0be]g#F+u]H-BH_Z=I=_$R"IC$B:q98/_,8 + t$=@4M%d%./jp[c2k"*afc/qO9*6c5=bS`BQ2+RY>]=6PaaI%T?R"IC$kH*f:2(^\?8&cOm + _&UZ:38\>.eCrH13LCIo@Eq;X:1\LCahJ+&0F)YQkIf$$9KoV33LGFZQug"(83q_])07J:F + "esIF1eV]be]gj$$._FF/4ia%a;bZ#RPQg0W2LY)KRS[6Ga]]b`Q'i>;-;'+sG18`15!4b4 + GRI/l_hSrk2pXfa.&^7[*`hiSD3;mTWS,Ol^!gk$ZJAR$2d4D(,gM8r>-Tb<1lS?BT3UfD@ + )opR8WXbrOZg_WpIQPOkkmX#7)XX[\nq,ZdmL/(p__U(fW/5Ge>-NCc(OXc?gK-/E[^Z7FR + Ck(5K]ENbcP-iR4Z;+XX^U=L-_:N<3J<TL3fYuL$Em-3mDOZDMtjkmKo?s,j"B2</aDtdZ) + lKKdt/1L'&'Y',PoG$GQkPa\R?VS_62C!!l8Md\c:=#@m@`8VTS^`D,E:I;n1s!TfXmPp2V + GE_I1WsaFqoYN#m]gto.Z+Y<6%?"BXhr@+0E6*;L,ih)kM!;MY,uU2k/\W&c^gEkc8TQhq> + LV?+.SQZBhHAZPGVqeSX_E[f^`HSGLSP+<6ucZh_H)3^Lau<mI"[kdgT=TPY>Gr^>(%'g?. + "[]^LX!SAF+JHt,p^WB#!s,j%4rq'"]`cnJ."Mr?1@@h,K9poU6:2Vo[&od["Jb]-Xmbfu9 + eAWGhgo3r3lcl$7ekff1h5t?,(k$S[i*p/.$S3c#s?k-<Sk(M5(q;2>QXq'TU<FJWnbo+_9 + YV:j6$?JON:3g>p=)So;KRKguKS2@Z2FhLqDnqmI06N/60ZO38gl63q$2[Vu#RPPl0LomGC + rRHh9/+C8F8Xd#@1En33+IsoB7`-3R,aPoeLf==6\II[R3S9q=!98QX9s$=1oJ($*coEn0Z + Qb+cMBnLbTX%(*%0!n=uokALMRHA*&a^l[0C]njtOhaEsDW@3TcE'@?/7fPRdK]/'K0;_Aq + a`nMGMFLTCr+Ji;d3Hd)\pXfLi2F,DK+rFd&00$&+s4d<!TcEo.[lf^,pBd5aaTi:3E1HfN + b\N/*1^AO2<j"e7O,PF;kWbnjQC*YfUB2<06Vf6S-hL/u49Tkm84f*KHaF.H*qF"c4YXo^r + [.]q#\1i\5V7>.$?"nN)/W.D[:S5#cMk._=iAKi&V5qRb04E]Tk'ZUqr6q*1O453WU8-S?o + c<_>g3jq>VNmsr(WIg:-CC%]8rP9Vqbd9P`^Z"0+#DcXEREg$^,5K1(GAc;m-C/c-`of`NK + +pZZIG^NHWR$XVoV;;SpU^kf\-&E"`@.BHek['4T4C^XZ\/r"C5S3V13^Lg:#_bU==>]lU2 + 0!j<,+F-ccZ=lkhW-C<Y&$6\i<."ER*m7<AHWc/5QQF_U[>jhc_aopb$W%*P*^['i0M2<SN + 18NEY]k&'jq04#`)&8MQ3r/nsg+3+7U`>f2*-kn,!1Fd.h\<q7cm&\jG,,m!4cl@NICX-S# + T4&44)!6Lp*<2@,Qp\<93FOc-7)K>T+ksl(0Ua4n?==>s(?U:t*3$NO)KX!"0IONqaQ[+C= + V^(Pf:4M,?XO@H($:2$S0PF3C>*DVL[5=g_JYCGfo8"&:RDf=F,ncm_]5s0bR(mA''>9=@8 + >J"3F$Vbfp.LVA4`.%$0K<S@LcNRk!Xe]C\-.e%TsG,7"RF7p8u.NZ6[YN&9D=O@PERR#]h + 3.S2L2q?k1j$k!Y"cX7ra9*3pa3M%F`omp;#7A4)^t+m(?1^!,uL@E0A!+MsYAc116[ULqf + ,bG+`$)jsX_qiHlA3Eg2Cm-C/cV[,+LdPRjVK_IK^Wt--rm!M_0afBbq?2E`\X7rc_)jR'0 + E+8BI-H&Uq[:YYQq[B6ofkZ=/P+ju9]k15E]6p:as7Jm'bq!W^p$Z*thAPGqW]jDC.5J!W; + sa(b(;7'<Yr<b/Y^O?N>t[kSj8@a%s),c4&Qc0Ig9@VY?A0+.iJgr"@cXPO,?GiG?h![ERf + E;gkF[+a3Q%0L>U"A(SgKNRm?lN*eR+^8ERi)^\'*9kMW-sHiNkV<SbM9Za5;2JcnJ%O,N] + DA0jMXN%s'/9'6DCT?N'>sO2(M#Lp;3f@ZqSp=<noe3ojubPrT3G3N&8i[lOoS=_M9)r805 + alq,A?8];Z63u=2Ccg6#`F,1#<k*VY0e;gF\LM2cXNk%/G^AT>>&.LD=0fS9P\":ATU-XMo + k2o4%6Suk<8&ZJDB?VM;9UMSacI4kH`Z1_hKK1OER/H.TF3(BJ0rM[`4ET^:fY.?,L^'&+k + 3P:B4*9W/IsXBA&.Kt5bXjEZ%\5U,5;'trZ7:4Fq9Sg81N_cHr2(k(OB'tDcKm-h6YDGJ2a + )?hq4!tC6WRcZ3Hq@V),bOIfb*:`H=@@ePs+8gN>W[5F+XCI%d&jQfji=SV*j'5ma.@8oLF + !WLTJW>F"Vb.'!WX&jokVp*R#\-ZHA]>8%+/tS=omO$d9cpZHA\["m\Kf:=('j`#Q'4X3CD + .&,nY4jokXf5g1CPZHA\+3u:>S3K&)5`Z2:a#W,$YOZBbWbZ<M7k*[79bhY1$hR7_/r#Z;/ + h\NKK$sAnU?8IXZHYggL-2u.uN8!O.cZ(nSe]jMR1]:_C_1M4Z_[8P\H"D9m[a+d#++EnKf + 7/4K;uW:gF10<'G4i7EY./N)MIGWVH!s7r(DY=X\mkIM_cI=L=m^7W#s5t/GGgnAFfohZnp + k\!U>^cNVjhbJqE)Wcr3C\jF10?jj_MUnh&Oh[J,\W]S?6k8I2-hEQGac.V(TlZ^6fSP7<d + lO\7L]HS0iZ*ILu5Uc24"3jug6:;9U1EG?1+VQT!t;Kf?'Vq<Ol,NB'Dcbpme1!u2&-B?kG + QpatV>SNGTMEHte41hR3Y&-^-5F7tme_]5C)At(f154N:0+UV_fRIf;*pFq@NN7hggp<U1& + cCER+bf1WsF(^t&gQ$*f*25-!RlRYoIN<Kc_O,3&Cd#'=F,7]#D<C?d*2;q7RlTpYHT-'/n + 8g+SJD"P[#:D^N*25-!RlPggpL4V0(phJW6?aU8&;;jnb`O-*cl@M<S1%37R58sL;#^G6U@ + ;c[3S1@H#'5U;RoSVKA*cEh%T.JWb+.5<hp/qH7,cB?F/EMEMn&_f[^*X_fp,S7><VPs,F\ + LS^AZ:2/T^)lRHO%DXcG'h^@6MSZt%LigY'W2/BXu@4;[EjW4?:2p1NJ>7B#bN`3q%Fpqn` + @\Tm'Cp+%MKZ>./Fs8&AfMDTB"bTX$E5]c!A%$<QtqkHMkcMTWa@h)AOX>8u3_lnj@S1!3A + &p&j1AsG@[jTV>6B>Id[0S_&ap6bGQ9E.W`A*D-^lKtK'LF?R(QnpdLF@C7>kfe>KmAD[o- + t)b9oCK>]LX_i,hL5ZML]V1L3WJZjIgN)763lWa"jA$/ro;i7#cTi#JV,sn>P=GJi(=9G3C + /-;&9Gq$lnR[U'-DnQS=i(XLcK!Mp6\e4=;j5AK)T^!k)aH5@uc'Q3cfoPE";#lD./H^3C/ + -S#BRtp0Ls)%q.Inp)GHNn@SY;.?k1j*k*VWJnq1u,+ksjRF)us4>:_I`/.?UDbq]$f($:T + p@?.lYcYO-_[lZ="/.?UDbq]$f($:Tp=_NiH?8I%O*oH\$#rmjqCPFB5EN^5pF8VA5kfc%d + I7W<\a&D?q\E#dNh`tMRF,<J/*&2*E$AB8tF"$SmF%3;N3HDN)rWPOdXng<3H=#5Y9J44YW + ^$#1KuBLV[7:a/+#`K7RSW#R?etVEdQ]Bj[:e%$r,k:A>7_a;(Gd4P_Pf>e`^Ge@/UGXfV* + g$N0LXtV0C4U\+t&Wjj_n,JW,XQP`^Z"H/S=A?&!nXX,fJfbR9/*E>2NZTD=a4Jhu=MTI.$ + r<`%^OKm?,:DLY(lsZY]BAkl&nK"`ZgE?P"mWr%RPoUSC:/]F*%r`>l"f&b^?BOcuM"USC> + ??TVTH0lQ1AQ-"a%_N&n^J'u]k:tK#dhAPIsI?(HjEj&q_:1:dT6.[+EF%AIMq]$>lA@;<Y + ES4pKo%hJ`^qh#%:r8_.0k]%n<L?-3KK0WRcC4]I0SaHMF!APmR/@fF+WJ:g#VjBh)p"C6( + J:&.$0K1e`P`P1@Lh'&k!Xe]+pR1k-"0OoR$6T'_Aoj,bR(mAde_trQp[0m3FOl0bIT>]L[ + 5=g_JW+oF#iBE4^h+<c)GT_`Z293bR(I5?dsM_D>.KLfb<M$f:9.D1<^oB_OU+a;q5'*3Fl + -W'1R%,X8T-6UE4KtW\>fZk+$*EJN77FQkMr1j<0gW[Y6a#1.T'_P%.r2fbW_'b8g>p$?O; + *0IL,f<45d&%pRdhRp)%krqGSHEf^U4'3*0n'?+96'U!R_;#s0jn_oA$_B_Kciq)3,d$`qO + CW?BIRciF&mnpX5nb)Q=3,'[QEgMqcQs`gd.oFsp;>cL9#ok$ChQV"Ij+b:d?8JCLU,c_Xa + '?+I3lCk'IeB;_o%#J\Qri-D0'7P&JK$Gm*7:jpTes8o>ALis\tncNm`qD!=+tEsq7cghqb + >4SkNskUqqu6#:<K(`-#8BHP;=Qs>;>KM="aC,/)N/LZBm3`o&>b806N/6^AIJF<>LjA:\m + 6'ZDL@@RVLK>bUL0<gf<PebU_!qYGJ9gY&"%@DV/%j2h#g9Z_5QWm:qomng?p[W@B@d'GOR + ^)W`ElpZ+R:g;>,S[-VKR:!]4[O2G$-Q^?6MGt=;iVc%dbo64Q]I5>qV:=#MLhL!<"/$::d + GCPh;)O0=Jmcj+!Fb-$(L,hQWkI;JeV]Ss`.BY5IGNT>q-4)bSX7Pg&'[2[BJ"J_nb6)hL< + 4_59aIZfMNnc2!HgG%K%/jiV(4kVt\(>+"=W?K_Db`fH#Nh,U@?/7f<4>i!EELF.X25j3c" + ZT^`Z29Eb]2($o#C6OLW(7=.a2n\S@Z-ibTY0I*%0"qkiol&Z96?Nbab]!Wj<`^F3(@8a"_ + X=3a4:n#]lLja4',F[_lPa=V^'Y@norm'BTj3JiSjYj)/o7It\k`LbQjMF3aOa/'K0+_jjP + m;q=drg!bd<@:/:6+^n-Ec1/5fc[Ap>+fiJM:n)OWcN.Jb=W?LVe=>7Dg44st*3q'<$)ooc + DfROeC^Y;NB?jn&E\N8b$ZeXFNr6A!r-a*_6Z`XsKZos:5H[&r*07'ZP*kjfCCa.bS8>_.L + 6s3)%9p!Af*pfgkpc$XF)Uog1NI)`(e/rP-EC]QJ\*%Hk+#qbRDIeAprt7e/FdWoA!3n0,r + \K3If7mXp<9%p-I(7$94#aQ.n3dXm.0Tuqn@>C?GIQW-4rUV;+^?PH@PA]ZZ9ZG[V==ia5< + 6,d,f88(HQV"9qH:(Z(nRRd*pUukMJSX]UH9tN/o`WMj%(s;bTe88X4q`\adt7P&Iolq.>h + .8\%82Y?5t%gbS]_Rgcq$V+]pQ8YrXuIA'F%M3@cq-Ru=XNt[$0?PV]lmuQ=%]HO[2eYlqa + APHb/*VJ94YBdg0]n=)tcTQn;VkU0MI/g#m],UX=Yr6Og-b10,DG:'Yh'@PE%WYAA4h%<FH + MdQn%D+4b[O[\OWO4l2k(L\n`G`WKQuqBUW="PUMD'q73gc1P+N(.1^-'Z3`m.'F%=]\ec" + ZT^52RU:\(@\IW%Q)-qIEOY_))bA,[j1QEqdScjo*:#iYmP3R.L@?,i<hR%E%04i\D$VVB8 + >fcdQp.RT%a7-!r02%d$/GQt(b/mG7.q*#WfO#BMRH#]j`bCP+](k$S\]?qq9qFS0`a%d$/ + SQud8:e'Qq_oT:j5F"di?cHD_#IQicPR"IDd'=9bO>qIBn`Z34=*6];53Ro_3L.B6'beY:C + )*$Mc:1mA#iK5i"F"di?#0pAr3NlelqR43[beY:C))q`CnU9]4s1CR=4E)tZF"di?#0oJT3 + k@CPNf5ucK/o;TE6^.-T[5_Tk$S\]@*ZPJh&Q6j9(BuiK/o<O3<SGdF+X9pc>OZG_&U\8S: + Pb(S;*%.H.4lk5NZ>`k$ZKfk*.n)?hIn=k!XZcF4$BHNBDN>3LGFZQnr\8#BMN!0F)[5D(l + 390F)Y'c37WOcCpa;#<&@u82EiiOb;GsnZJ@FDn\*j<msrbopN^(1Dd>WML3V'OE?+o@D8\ + 9f_ei+B4K%QoA%T.X3C,&2.QW@osT-)J$M*5@!^tUR7;Uh.0l9.3Ur.&GPl9pcOB^8qO`dM + 3C7L#[I:d#SP*>&<$fLV1,@=)U85t>\bq?H=/`c`@`?[BIVum&UdS9ncGqqJ+(Z<:E;B6sC + $9@e06H>):/>5X:Am>mF_P?"=]:_sV+me,\!'d]P['_pQlKX;m];7J'.7?c1@Mf^f8Ye/4X + PK6Guq2\qPmOsW?aEC>)CR/B/M_RkD>Aic+J6mp6<\PPKf$-O%Cou2;Im[\]D7"jO)\Vjc/ + A5NFh6polg$$pB_YuKanI/l0[riWk,=DZF/,fQHG)NMJord4.'oKIs\m7s7"srm&AGm9fHl + lcEr('pCH:n`i4()l>)%nQ%lI^5&A1lQ*a:X)B1JUr7^Zjc]qTe1O%u?g_o6#(+%,*KmtI3 + _bN%YW+r;pj_A+GDg24_rPFS?iT=ZIUM*D&CR&jIT%n)C*6L#9G-mKW+ROa3*ftS;&]6^cB + 5I3BQ0W,EWf^Id[h^sgk%OQAGF67$q7DBGi(EKgnS[4RqW!jcQ2]Zj1^nFZ#BMR(F$_gQK/ + o<O3DL(H?k2=,Ng#)UR"IDdj5aSXk$S\]3'!@Y3LGFZ:(HDo%d%/ZPCkl_K/o=ZjBrJ[?k2 + <Y3LGFZR"ICo%d%./k$X45K/o<O3LJjf?k2=,%d#`2R"IDdK/l[:k$S\]@#gG'3LGFZR,d7 + 8%d%./ju>AgK/o<O3DL(H?k2=,Ng#)UR"IDdj5fEm,?uXae)F6[T'mJbIk`s!o$j2/7V2H< + Y?uMPR-69ANbL4X8$3otgQQ3F6=PZ"?8Gc_,\]D=ni/@>U2Vi(dkp[U$fa#QAo'T6d6(]U< + 5>ccSEdOt&OU-5RE_@?cM/g*I!\%;a=gp#jilMJZZ9]HoZs$,=WSs/9t5Z>ol@NOhV\>3Dm + +T^g1sb?jL`Es2Pnh_-0`"Kf;Ul0P(7WRk546d0JBsr3W%k'XH0^3A$;:k)#qm-k&pE@f<j + )L?'DpuVR9Il/)U)0l%b#\0&%t=Ym%CJp90>,+(\V^eA<46T6gC6Vmem-QlKZ1)m^W3j,lk + 2W6g.*(9!ad4KdPQ3]\qJr/$TWpQ*)(Vf^8QdbX'-/[R(2lIK_A])'"F(48Y3c+LQan#JXS + >Gd.8#2b`bmDa:uQW07bH4!pm0#Q`mWPthCY(T2EU1"@^$30k"IpK^.nWKG9b^40\A+R.RS + $uB@X](D6jf_U.U?$<Dq>TBrihD;So4m#qICo,p1`5oY0"k_Jeq+G,KmNi]ig4Ar79t829! + Zn9h>%5G!lO(A.E*`U"`a'dn`E!LlhNt2(<JFOSld^klWf\jmF4-BBl3iQnQFtag0;#;jme + aWT%rB4(V[@7j5b)_CUJrp_S(I)F"di?0ZV;O*6c5=b].YW#BMR(F.=5o_&U\8*%(u40F)Y + Qa2u.;beY:CEH3`<F"di?S/fbh*6c5=-O4]H#BMT>ah\t@_&U[=E\I`>0F)Zh*6c5=beY8H + #BMR(F"kYV_&U\8*6`DC0F)YQ#BQCTbeY:C_&Og-F"di?0ZV;O*6c5=b].YW#BMR(F.=5o_ + &U\8*%**8c1/5fIHGcrbXjEZN\-&%G0Kj>Y2:hdYu'(-:TTqiFj?L/Apo(1SQ"8,H]6()&M + @%S/"\g:R)>G*'[:@UBFloB(PWpJ\(=<-c<`:G8i@s+&sJ39%$Q>Aqk*jnfTEcdoB*eJs+r + \,;!GN7Sl7Wq.BY@"Lc0ac,aH&TjA&8fIHLIbAhcU7?WoVk4d^:FNRh.1;Fbq$7upEqXjno + u2G2$TO*sn"`L$7))C>\L;L:e^X](D'MWTer<h4([gUc.H?Gt^7?E886AHkBtHIL?tj4eKL + ,IO*Ag?UoH*d<fP*Y"<cPW"hBV0,E$kdsR>GbV":Sh@-H:iTcpq\!>%7r`BfpNC>Kpml8GZ + b*lL>br)C-a_;_--=p0eU"C0HFpOj6,ds]mRr41*lYO<3LGFZ9YaM1)jl7<R)9%H`O17WR" + ICm^en>UR"IDd_ZUsu[=L?*K/lW@;-Y'-K/o=:"<>CgJN9*M3D@4c>T9&_3LI\e*6#=:3LG + FZ9YaM1)jl7<R)9%H`O17WR"ICm^en>UR"IDd_ZUsu[=L?*K/lW@;-Y'-K/o=:"<>CgJN9* + M3D@4c>T9&_3LI\e*6#=:3LGFZ9YaM1)jl7<R)9%H`O17WR"ICm^en>UR"IDd_ZUsu[=L>j + YH4u[!mTurl,4Pge>'N3HMVrp<ik:UJ%e'KRb]HaCcH^G;(&V8l`@a9?Blm1*kBT'n,+gn0 + Tp>~> +Q +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-height_expected.png b/testfiles/cli_tests/testcases/export-height_expected.png Binary files differnew file mode 100644 index 0000000..e6ab7ed --- /dev/null +++ b/testfiles/cli_tests/testcases/export-height_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.emf b/testfiles/cli_tests/testcases/export-margin_drawing_expected.emf Binary files differnew file mode 100644 index 0000000..9e23657 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_drawing_expected.emf diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.eps b/testfiles/cli_tests/testcases/export-margin_drawing_expected.eps new file mode 100644 index 0000000..3029a52 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_drawing_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:25:06 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 150 150 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 150 150 +%%EndPageSetup +q 37 37 76 76 rectclip +1 0 0 -1 0 150 cm q +0 0 1 rg +37.5 37.5 37.5 75 re f +1 0 0 rg +75 37.5 37.5 75 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.pdf b/testfiles/cli_tests/testcases/export-margin_drawing_expected.pdf Binary files differnew file mode 100644 index 0000000..0535214 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_drawing_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.png b/testfiles/cli_tests/testcases/export-margin_drawing_expected.png Binary files differnew file mode 100644 index 0000000..de4aeba --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_drawing_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.ps b/testfiles/cli_tests/testcases/export-margin_drawing_expected.ps new file mode 100644 index 0000000..025c45c --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_drawing_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:25:05 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 53x53mm 150 150 0 () () +%%BoundingBox: 37 37 113 113 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 53x53mm +%%PageBoundingBox: 37 37 113 113 +150 150 cairo_set_page_size +%%EndPageSetup +q 37 37 76 76 rectclip +1 0 0 -1 0 150 cm q +0 0 1 rg +37.5 37.5 37.5 75 re f +1 0 0 rg +75 37.5 37.5 75 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.svg b/testfiles/cli_tests/testcases/export-margin_drawing_expected.svg new file mode 100644 index 0000000..e22c4ef --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_drawing_expected.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="square_px.svg" + id="svg4" + version="1.1" + height="200" + width="200"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + fit-margin-bottom="50" + fit-margin-right="50" + fit-margin-left="50" + fit-margin-top="50" + id="namedview6" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <rect + id="square-blue" + fill="#0000ff" + height="100" + width="50" + y="50" + x="50" /> + <rect + id="square-red" + fill="#ff0000" + height="100" + width="50" + y="50" + x="100" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.wmf b/testfiles/cli_tests/testcases/export-margin_drawing_expected.wmf Binary files differnew file mode 100644 index 0000000..d37195f --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_drawing_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-margin_export-area_expected.png b/testfiles/cli_tests/testcases/export-margin_export-area_expected.png Binary files differnew file mode 100644 index 0000000..2e53613 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-area_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.emf b/testfiles/cli_tests/testcases/export-margin_export-id_expected.emf Binary files differnew file mode 100644 index 0000000..3802d6d --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_expected.emf diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.eps b/testfiles/cli_tests/testcases/export-margin_export-id_expected.eps new file mode 100644 index 0000000..6f5f368 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Fri Mar 20 20:03:34 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 113 150 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 113 150 +%%EndPageSetup +q 0 37 75 76 rectclip +1 0 0 -1 0 150 cm q +0 0 1 rg +0 37.5 37.5 75 re f +1 0 0 rg +37.5 37.5 37.5 75 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.pdf b/testfiles/cli_tests/testcases/export-margin_export-id_expected.pdf Binary files differnew file mode 100644 index 0000000..3f2adf7 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.png b/testfiles/cli_tests/testcases/export-margin_export-id_expected.png Binary files differnew file mode 100644 index 0000000..d044884 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.ps b/testfiles/cli_tests/testcases/export-margin_export-id_expected.ps new file mode 100644 index 0000000..47be99f --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Fri Mar 20 20:03:12 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 40x53mm 113 150 0 () () +%%BoundingBox: 0 37 75 113 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 40x53mm +%%PageBoundingBox: 0 37 75 113 +113 150 cairo_set_page_size +%%EndPageSetup +q 0 37 75 76 rectclip +1 0 0 -1 0 150 cm q +0 0 1 rg +0 37.5 37.5 75 re f +1 0 0 rg +37.5 37.5 37.5 75 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.svg b/testfiles/cli_tests/testcases/export-margin_export-id_expected.svg new file mode 100644 index 0000000..76e4eb2 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_expected.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="square_px.svg" + id="svg4" + version="1.1" + height="200" + width="150"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + fit-margin-bottom="50" + fit-margin-right="50" + fit-margin-left="50" + fit-margin-top="50" + id="namedview6" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <rect + id="square-blue" + fill="#0000ff" + height="100" + width="50" + y="50" + x="0" /> + <rect + id="square-red" + fill="#ff0000" + height="100" + width="50" + y="50" + x="50" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.wmf b/testfiles/cli_tests/testcases/export-margin_export-id_expected.wmf Binary files differnew file mode 100644 index 0000000..407efb7 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.emf b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.emf Binary files differnew file mode 100644 index 0000000..5dbda47 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.emf diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.eps b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.eps new file mode 100644 index 0000000..b9ac1df --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.eps @@ -0,0 +1,80 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:25:02 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 113 150 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 113 150 +%%EndPageSetup +q 37 37 38 76 rectclip +1 0 0 -1 0 150 cm q +1 0 0 rg +37.5 37.5 37.5 75 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.pdf b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.pdf Binary files differnew file mode 100644 index 0000000..736e623 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.png b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.png Binary files differnew file mode 100644 index 0000000..a63f9c4 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.ps b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.ps new file mode 100644 index 0000000..1512864 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.ps @@ -0,0 +1,117 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:25:01 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 40x53mm 113 150 0 () () +%%BoundingBox: 37 37 75 113 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 40x53mm +%%PageBoundingBox: 37 37 75 113 +113 150 cairo_set_page_size +%%EndPageSetup +q 37 37 38 76 rectclip +1 0 0 -1 0 150 cm q +1 0 0 rg +37.5 37.5 37.5 75 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.svg b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.svg new file mode 100644 index 0000000..0d1c2ac --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.svg @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="square_px.svg" + id="svg4" + version="1.1" + height="200" + width="150"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + fit-margin-bottom="50" + fit-margin-right="50" + fit-margin-left="50" + fit-margin-top="50" + id="namedview6" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <rect + id="square-red" + fill="#ff0000" + height="100" + width="50" + y="50" + x="50" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.wmf b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.wmf Binary files differnew file mode 100644 index 0000000..169b86d --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.emf b/testfiles/cli_tests/testcases/export-margin_mm_expected.emf Binary files differnew file mode 100644 index 0000000..78c3182 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_expected.emf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.eps b/testfiles/cli_tests/testcases/export-margin_mm_expected.eps new file mode 100644 index 0000000..fba673e --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:24:54 2020 +%%Pages: 1 +%%BoundingBox: 0 0 851 851 +%%HiResBoundingBox: 0 0 851 851 +%%LanguageLevel: 3 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 851 851 +%%EndPageSetup +q 283 284 284 284 rectclip +1 0 0 -1 0 851 cm q +0 0 1 rg +283.465 283.465 141.73 283.465 re f +1 0 0 rg +425.195 283.465 141.734 283.465 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.pdf b/testfiles/cli_tests/testcases/export-margin_mm_expected.pdf Binary files differnew file mode 100644 index 0000000..f4c472c --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.png b/testfiles/cli_tests/testcases/export-margin_mm_expected.png Binary files differnew file mode 100644 index 0000000..9c22341 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.ps b/testfiles/cli_tests/testcases/export-margin_mm_expected.ps new file mode 100644 index 0000000..abb8818 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:24:53 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 300x300mm 850 850 0 () () +%%BoundingBox: 283 284 567 568 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 300x300mm +%%PageBoundingBox: 283 284 567 568 +851 851 cairo_set_page_size +%%EndPageSetup +q 283 284 284 284 rectclip +1 0 0 -1 0 851 cm q +0 0 1 rg +283.465 283.465 141.73 283.465 re f +1 0 0 rg +425.195 283.465 141.734 283.465 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.svg b/testfiles/cli_tests/testcases/export-margin_mm_expected.svg new file mode 100644 index 0000000..424e8f8 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_expected.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="square_mm.svg" + id="svg4" + version="1.1" + height="300mm" + width="300mm"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + fit-margin-bottom="50" + fit-margin-right="50" + fit-margin-left="50" + fit-margin-top="50" + id="namedview6" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <rect + id="square-blue" + fill="#0000ff" + height="100mm" + width="50mm" + y="377.95276" + x="377.95276" /> + <rect + id="square-red" + fill="#ff0000" + height="100mm" + width="50mm" + y="377.95276" + x="566.92914" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.wmf b/testfiles/cli_tests/testcases/export-margin_mm_expected.wmf Binary files differnew file mode 100644 index 0000000..0131399 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.emf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.emf Binary files differnew file mode 100644 index 0000000..e0130bf --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.emf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.eps b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.eps new file mode 100644 index 0000000..7975c1d --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Mar 21 23:14:25 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 567 567 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 567 567 +%%EndPageSetup +q 141 141 285 285 rectclip +1 0 0 -1 0 567 cm q +0 0 1 rg +141.73 141.73 141.734 283.465 re f +1 0 0 rg +283.465 141.73 141.73 283.465 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.pdf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.pdf Binary files differnew file mode 100644 index 0000000..a463c55 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.png b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.png Binary files differnew file mode 100644 index 0000000..84fd7bc --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.ps b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.ps new file mode 100644 index 0000000..d43e2b3 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Mar 21 23:14:19 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 200x200mm 567 567 0 () () +%%BoundingBox: 141 141 426 426 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 200x200mm +%%PageBoundingBox: 141 141 426 426 +567 567 cairo_set_page_size +%%EndPageSetup +q 141 141 285 285 rectclip +1 0 0 -1 0 567 cm q +0 0 1 rg +141.73 141.73 141.734 283.465 re f +1 0 0 rg +283.465 141.73 141.73 283.465 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.svg b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.svg new file mode 100644 index 0000000..e7773cd --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="square_mm_viewbox.svg" + id="svg4" + version="1.1" + viewBox="0 0 200 200" + height="200mm" + width="200mm"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + fit-margin-bottom="50" + fit-margin-right="50" + fit-margin-left="50" + fit-margin-top="50" + id="namedview6" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <!-- Consider that usually 1 user unit = 1 px = 1/96 inch, but viewBox scale the the drawing here, + so that 1 (unitless) user unit is equivalent to 1 mm after scaling. + The first square (square-mm) doesn't actually have a size of 100 mm. + The second and third square together has the size of 100 mm × 100 mm. + <rect x="0" y="0" width="100mm" height="100mm" fill="yellow" id="square-mm" />--> + <rect + id="square-blue" + fill="#0000ff" + height="100" + width="50" + y="50" + x="50" /> + <rect + id="square-red" + fill="#ff0000" + height="100" + width="50" + y="50" + x="100" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.wmf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.wmf Binary files differnew file mode 100644 index 0000000..f8c842d --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.emf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.emf Binary files differnew file mode 100644 index 0000000..6315da5 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.emf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.eps b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.eps new file mode 100644 index 0000000..3d0d510 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Mar 21 23:11:11 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 426 567 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 426 567 +%%EndPageSetup +q 0 141 284 285 rectclip +1 0 0 -1 0 567 cm q +0 0 1 rg +0 141.73 141.73 283.465 re f +1 0 0 rg +141.73 141.73 141.734 283.465 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.pdf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.pdf Binary files differnew file mode 100644 index 0000000..f9914b4 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.png b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.png Binary files differnew file mode 100644 index 0000000..51a98e1 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.ps b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.ps new file mode 100644 index 0000000..08192c1 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Mar 21 23:11:23 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 150x200mm 425 567 0 () () +%%BoundingBox: 0 141 284 426 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 150x200mm +%%PageBoundingBox: 0 141 284 426 +426 567 cairo_set_page_size +%%EndPageSetup +q 0 141 284 285 rectclip +1 0 0 -1 0 567 cm q +0 0 1 rg +0 141.73 141.73 283.465 re f +1 0 0 rg +141.73 141.73 141.734 283.465 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.svg b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.svg new file mode 100644 index 0000000..460de99 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="square_mm_viewbox.svg" + id="svg4" + version="1.1" + viewBox="0 0 150 200" + height="200mm" + width="150mm"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + fit-margin-bottom="50" + fit-margin-right="50" + fit-margin-left="50" + fit-margin-top="50" + id="namedview6" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <!-- Consider that usually 1 user unit = 1 px = 1/96 inch, but viewBox scale the the drawing here, + so that 1 (unitless) user unit is equivalent to 1 mm after scaling. + The first square (square-mm) doesn't actually have a size of 100 mm. + The second and third square together has the size of 100 mm × 100 mm. + <rect x="0" y="0" width="100mm" height="100mm" fill="yellow" id="square-mm" />--> + <rect + id="square-blue" + fill="#0000ff" + height="100" + width="50" + y="50" + x="-3.814697e-07" /> + <rect + id="square-red" + fill="#ff0000" + height="100" + width="50" + y="50" + x="50" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.wmf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.wmf Binary files differnew file mode 100644 index 0000000..18179f4 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.emf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.emf Binary files differnew file mode 100644 index 0000000..78c3182 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.emf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.eps b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.eps new file mode 100644 index 0000000..fba673e --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:24:54 2020 +%%Pages: 1 +%%BoundingBox: 0 0 851 851 +%%HiResBoundingBox: 0 0 851 851 +%%LanguageLevel: 3 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 851 851 +%%EndPageSetup +q 283 284 284 284 rectclip +1 0 0 -1 0 851 cm q +0 0 1 rg +283.465 283.465 141.73 283.465 re f +1 0 0 rg +425.195 283.465 141.734 283.465 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.pdf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.pdf Binary files differnew file mode 100644 index 0000000..f4c472c --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.png b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.png Binary files differnew file mode 100644 index 0000000..9c22341 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.ps b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.ps new file mode 100644 index 0000000..abb8818 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:24:53 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 300x300mm 850 850 0 () () +%%BoundingBox: 283 284 567 568 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 300x300mm +%%PageBoundingBox: 283 284 567 568 +851 851 cairo_set_page_size +%%EndPageSetup +q 283 284 284 284 rectclip +1 0 0 -1 0 851 cm q +0 0 1 rg +283.465 283.465 141.73 283.465 re f +1 0 0 rg +425.195 283.465 141.734 283.465 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.svg b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.svg new file mode 100644 index 0000000..8274392 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="square_mm_viewbox.svg" + id="svg4" + version="1.1" + viewBox="0 0 300 300" + height="300mm" + width="300mm"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + fit-margin-bottom="50" + fit-margin-right="50" + fit-margin-left="50" + fit-margin-top="50" + id="namedview6" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <!-- Consider that usually 1 user unit = 1 px = 1/96 inch, but viewBox scale the the drawing here, + so that 1 (unitless) user unit is equivalent to 1 mm after scaling. + The first square (square-mm) doesn't actually have a size of 100 mm. + The second and third square together has the size of 100 mm × 100 mm. + <rect x="0" y="0" width="100mm" height="100mm" fill="yellow" id="square-mm" />--> + <rect + id="square-blue" + fill="#0000ff" + height="100" + width="50" + y="100" + x="100" /> + <rect + id="square-red" + fill="#ff0000" + height="100" + width="50" + y="100" + x="150" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.wmf b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.wmf Binary files differnew file mode 100644 index 0000000..0131399 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.emf b/testfiles/cli_tests/testcases/export-margin_px_expected.emf Binary files differnew file mode 100644 index 0000000..0d52e4d --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_px_expected.emf diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.eps b/testfiles/cli_tests/testcases/export-margin_px_expected.eps new file mode 100644 index 0000000..dcc1bc0 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_px_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:24:50 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 225 225 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 225 225 +%%EndPageSetup +q 75 75 75 75 rectclip +1 0 0 -1 0 225 cm q +0 0 1 rg +75 75 37.5 75 re f +1 0 0 rg +112.5 75 37.5 75 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.pdf b/testfiles/cli_tests/testcases/export-margin_px_expected.pdf Binary files differnew file mode 100644 index 0000000..a467503 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_px_expected.pdf diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.png b/testfiles/cli_tests/testcases/export-margin_px_expected.png Binary files differnew file mode 100644 index 0000000..a9ce6f9 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_px_expected.png diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.ps b/testfiles/cli_tests/testcases/export-margin_px_expected.ps new file mode 100644 index 0000000..c2fa5e8 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_px_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Mar 20 19:24:49 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 79x79mm 225 225 0 () () +%%BoundingBox: 75 75 150 150 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 79x79mm +%%PageBoundingBox: 75 75 150 150 +225 225 cairo_set_page_size +%%EndPageSetup +q 75 75 75 75 rectclip +1 0 0 -1 0 225 cm q +0 0 1 rg +75 75 37.5 75 re f +1 0 0 rg +112.5 75 37.5 75 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.svg b/testfiles/cli_tests/testcases/export-margin_px_expected.svg new file mode 100644 index 0000000..b4ec04f --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_px_expected.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + sodipodi:docname="square_px.svg" + id="svg4" + version="1.1" + height="300" + width="300"> + <metadata + id="metadata10"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs8" /> + <sodipodi:namedview + fit-margin-bottom="50" + fit-margin-right="50" + fit-margin-left="50" + fit-margin-top="50" + id="namedview6" + inkscape:window-height="480" + inkscape:window-width="640" + inkscape:pageshadow="2" + inkscape:pageopacity="0" + guidetolerance="10" + gridtolerance="10" + objecttolerance="10" + borderopacity="1" + bordercolor="#666666" + pagecolor="#ffffff" /> + <rect + id="square-blue" + fill="#0000ff" + height="100" + width="50" + y="100" + x="100" /> + <rect + id="square-red" + fill="#ff0000" + height="100" + width="50" + y="100" + x="150" /> +</svg> diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.wmf b/testfiles/cli_tests/testcases/export-margin_px_expected.wmf Binary files differnew file mode 100644 index 0000000..57bd577 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_px_expected.wmf diff --git a/testfiles/cli_tests/testcases/export-width_expected.png b/testfiles/cli_tests/testcases/export-width_expected.png Binary files differnew file mode 100644 index 0000000..f05cecd --- /dev/null +++ b/testfiles/cli_tests/testcases/export-width_expected.png diff --git a/testfiles/cli_tests/testcases/export_hints.svg b/testfiles/cli_tests/testcases/export_hints.svg new file mode 100644 index 0000000..87c06f5 --- /dev/null +++ b/testfiles/cli_tests/testcases/export_hints.svg @@ -0,0 +1,7 @@ +<!-- Note: inkscape:export-ydpi is actually ignored, see src/ui/dialog/export.cpp and src/io/file-export-cmd.cpp --> + +<svg xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="190" height="80" + inkscape:export-filename="export_hints_drawing.png" inkscape:export-xdpi="111" inkscape:export-ydpi="222"> + <rect id="rect1" x="10" y="10" width="80" height="60" fill="#00f" inkscape:export-filename="export_hints_rectangle.png" inkscape:export-xdpi="123" inkscape:export-ydpi="456"/> + <rect id="rect2" x="100" y="10" width="80" height="60" fill="#f00"/> +</svg> diff --git a/testfiles/cli_tests/testcases/filter.svg b/testfiles/cli_tests/testcases/filter.svg new file mode 100644 index 0000000..6111da3 --- /dev/null +++ b/testfiles/cli_tests/testcases/filter.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="230" height="120" viewBox="0 0 230 120" xmlns="http://www.w3.org/2000/svg"> + <filter id="blurMe"> + <feGaussianBlur stdDeviation="5"/> + </filter> + <circle cx="60" cy="60" r="60" fill="green" fill-opacity="0.1" /> + <circle cx="60" cy="60" r="50" fill="green" /> + <circle cx="170" cy="60" r="50" fill="green" filter="url(#blurMe)" /> +</svg> diff --git a/testfiles/cli_tests/testcases/librevenge_formats/corel_draw.cdr b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw.cdr Binary files differnew file mode 100644 index 0000000..ccdb02a --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw.cdr diff --git a/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2.cdr b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2.cdr Binary files differnew file mode 100644 index 0000000..4a74dbc --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2.cdr diff --git a/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2_expected.png Binary files differnew file mode 100644 index 0000000..79a0966 --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2_expected.png diff --git a/testfiles/cli_tests/testcases/librevenge_formats/corel_draw_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw_expected.png Binary files differnew file mode 100644 index 0000000..b3ee3e4 --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw_expected.png diff --git a/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd Binary files differnew file mode 100644 index 0000000..a526a70 --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd diff --git a/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd_expected.png Binary files differnew file mode 100644 index 0000000..43ba022 --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd_expected.png diff --git a/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx Binary files differnew file mode 100644 index 0000000..ef8f6a1 --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx diff --git a/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx_expected.png Binary files differnew file mode 100644 index 0000000..5f1bdfa --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx_expected.png diff --git a/testfiles/cli_tests/testcases/librevenge_formats/word_perfect.wpg b/testfiles/cli_tests/testcases/librevenge_formats/word_perfect.wpg Binary files differnew file mode 100644 index 0000000..02e1b82 --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/word_perfect.wpg diff --git a/testfiles/cli_tests/testcases/librevenge_formats/word_perfect_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/word_perfect_expected.png Binary files differnew file mode 100644 index 0000000..aa5ac9e --- /dev/null +++ b/testfiles/cli_tests/testcases/librevenge_formats/word_perfect_expected.png diff --git a/testfiles/cli_tests/testcases/pdf-mesh.pdf b/testfiles/cli_tests/testcases/pdf-mesh.pdf Binary files differnew file mode 100644 index 0000000..8d4c29c --- /dev/null +++ b/testfiles/cli_tests/testcases/pdf-mesh.pdf diff --git a/testfiles/cli_tests/testcases/pyramids.svg b/testfiles/cli_tests/testcases/pyramids.svg new file mode 100644 index 0000000..30ac82a --- /dev/null +++ b/testfiles/cli_tests/testcases/pyramids.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="185px" height="100px"> + <rect x="4.888" y="5.333" width="175" height="90" fill="#fff" stroke="#000" id="rect_misaligned" /> + + <rect x="10" y="10" width="80" height="80" fill="none" stroke="#000" id="rect_1" /> + <rect x="15" y="15" width="70" height="70" fill="none" stroke="#000" id="rect_2" /> + <rect x="20" y="20" width="60" height="60" fill="none" stroke="#000" id="rect_3" /> + <rect x="25" y="25" width="50" height="50" fill="none" stroke="#000" id="rect_4" /> + <rect x="30.5" y="30.5" width="40" height="40" fill="red" fill-opacity="0.2" id="quad_1" /> + <rect x="35.5" y="35.5" width="30" height="30" fill="red" fill-opacity="0.2" id="quad_2" /> + <rect x="40.5" y="40.5" width="20" height="20" fill="red" fill-opacity="0.2" id="quad_3" /> + <rect x="45.5" y="45.5" width="10" height="10" fill="red" fill-opacity="0.2" id="quad_4" /> + + <rect x="95.5" y="10.5" width="80" height="80" fill="none" stroke="#000" id="rect_snapped_1" /> + <rect x="100.5" y="15.5" width="70" height="70" fill="none" stroke="#000" id="rect_snapped_2" /> + <rect x="105.5" y="20.5" width="60" height="60" fill="none" stroke="#000" id="rect_snapped_3" /> + <rect x="110.5" y="25.5" width="50" height="50" fill="none" stroke="#000" id="rect_snapped_4" /> + <rect x="115" y="30" width="40" height="40" fill="green" fill-opacity="0.2" id="quad_snapped_1" /> + <rect x="120" y="35" width="30" height="30" fill="green" fill-opacity="0.2" id="quad_snapped_2" /> + <rect x="125" y="40" width="20" height="20" fill="green" fill-opacity="0.2" id="quad_snapped_3" /> + <rect x="130" y="45" width="10" height="10" fill="green" fill-opacity="0.2" id="quad_snapped_4" /> +</svg> diff --git a/testfiles/cli_tests/testcases/rects.svg b/testfiles/cli_tests/testcases/rects.svg new file mode 100644 index 0000000..3d90ef1 --- /dev/null +++ b/testfiles/cli_tests/testcases/rects.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="100px"> + <rect x="10" y="10" width="80" height="80" fill="#f00" id="rect1" /> + <rect x="110" y="20" width="80" height="70" fill="#0f0" id="rect2" /> + <rect x="210" y="30" width="80" height="60" fill="#00f" id="rect3" /> +</svg> diff --git a/testfiles/cli_tests/testcases/shapes.svg b/testfiles/cli_tests/testcases/shapes.svg new file mode 100644 index 0000000..61ad01d --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="400" height="300" version="1.1" xmlns="http://www.w3.org/2000/svg"> + <g stroke="#000"> + <rect x="10" y="5" width="160" height="130" fill="#00f" stroke-width="2"/> + <ellipse cx="275" cy="130" rx="120" ry="100" fill="#f00" stroke-width="4"/> + <path d="m95 290 9.9517-87.343-74.468-46.716 86.143-17.526 21.418-85.259 43.288 76.511 87.704-5.9771-59.39 64.812 32.787 81.565-79.993-36.455z" fill="#ff0" stroke-width="6"/> + </g> +</svg> diff --git a/testfiles/cli_tests/testcases/shapes_expected.emf b/testfiles/cli_tests/testcases/shapes_expected.emf Binary files differnew file mode 100644 index 0000000..4bf1faa --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes_expected.emf diff --git a/testfiles/cli_tests/testcases/shapes_expected.eps b/testfiles/cli_tests/testcases/shapes_expected.eps new file mode 100644 index 0000000..fe91e4d --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes_expected.eps @@ -0,0 +1,109 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Feb 22 20:44:27 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 291 220 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 0 291 220 +%%EndPageSetup +q 0 0 291 220 rectclip +1 0 0 -1 0 220 cm q +0 0 1 rg +0.75 0.75 120 97.5 re f +0 g +1.5 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 1 0 0 cm +0.75 0.75 120 97.5 re S Q +1 0 0 rg +289.5 94.5 m 289.5 135.922 249.207 169.5 199.5 169.5 c 149.793 169.5 109.5 + 135.922 109.5 94.5 c 109.5 53.078 149.793 19.5 199.5 19.5 c 249.207 19.5 + 289.5 53.078 289.5 94.5 c f +0 g +3 w +q 1 0 0 1 0 0 cm +289.5 94.5 m 289.5 135.922 249.207 169.5 199.5 169.5 c 149.793 169.5 109.5 + 135.922 109.5 94.5 c 109.5 53.078 149.793 19.5 199.5 19.5 c 249.207 19.5 + 289.5 53.078 289.5 94.5 c S Q +1 1 0 rg +64.5 214.5 m 71.965 148.992 l 16.113 113.957 l 80.719 100.813 l 96.785 +36.867 l 129.25 94.25 l 195.027 89.766 l 150.484 138.375 l 175.074 199.551 + l 115.082 172.207 l h +64.5 214.5 m f +0 g +4.5 w +q 1 0 0 1 0 0 cm +64.5 214.5 m 71.965 148.992 l 16.113 113.957 l 80.719 100.813 l 96.785 +36.867 l 129.25 94.25 l 195.027 89.766 l 150.484 138.375 l 175.074 199.551 + l 115.082 172.207 l h +64.5 214.5 m S Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/shapes_expected.pdf b/testfiles/cli_tests/testcases/shapes_expected.pdf Binary files differnew file mode 100644 index 0000000..bff07b6 --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes_expected.pdf diff --git a/testfiles/cli_tests/testcases/shapes_expected.png b/testfiles/cli_tests/testcases/shapes_expected.png Binary files differnew file mode 100644 index 0000000..3e81da4 --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes_expected.png diff --git a/testfiles/cli_tests/testcases/shapes_expected.ps b/testfiles/cli_tests/testcases/shapes_expected.ps new file mode 100644 index 0000000..9037026 --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes_expected.ps @@ -0,0 +1,146 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Feb 22 20:44:25 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 106x79mm 300 225 0 () () +%%BoundingBox: 6 2 298 222 +%%EndComments +%%BeginProlog +/languagelevel where +{ pop languagelevel } { 1 } ifelse +2 lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto + (This print job requires a PostScript Language Level 2 printer.) show + showpage quit } if +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +/cairo_set_page_size { + % Change paper size, but only if different from previous paper size otherwise + % duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size + % so we use the same when checking if the size changes. + /setpagedevice where { + pop currentpagedevice + /PageSize known { + 2 copy + currentpagedevice /PageSize get aload pop + exch 4 1 roll + sub abs 5 gt + 3 1 roll + sub abs 5 gt + or + } { + true + } ifelse + { + 2 array astore + 2 dict begin + /PageSize exch def + /ImagingBBox null def + currentdict end + setpagedevice + } { + pop pop + } ifelse + } { + pop + } ifelse +} def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageMedia: 106x79mm +%%PageBoundingBox: 6 2 298 222 +300 225 cairo_set_page_size +%%EndPageSetup +q 6 2 292 220 rectclip +1 0 0 -1 0 225 cm q +0 0 1 rg +7.5 3.75 120 97.5 re f +0 g +1.5 w +0 J +0 j +[] 0.0 d +4 M q 1 0 0 1 0 0 cm +7.5 3.75 120 97.5 re S Q +1 0 0 rg +296.25 97.5 m 296.25 138.922 255.957 172.5 206.25 172.5 c 156.543 172.5 + 116.25 138.922 116.25 97.5 c 116.25 56.078 156.543 22.5 206.25 22.5 c 255.957 + 22.5 296.25 56.078 296.25 97.5 c f +0 g +3 w +q 1 0 0 1 0 0 cm +296.25 97.5 m 296.25 138.922 255.957 172.5 206.25 172.5 c 156.543 172.5 + 116.25 138.922 116.25 97.5 c 116.25 56.078 156.543 22.5 206.25 22.5 c 255.957 + 22.5 296.25 56.078 296.25 97.5 c S Q +1 1 0 rg +71.25 217.5 m 78.715 151.992 l 22.863 116.957 l 87.469 103.813 l 103.535 + 39.867 l 136 97.25 l 201.777 92.766 l 157.234 141.375 l 181.824 202.551 + l 121.832 175.207 l h +71.25 217.5 m f +0 g +4.5 w +q 1 0 0 1 0 0 cm +71.25 217.5 m 78.715 151.992 l 22.863 116.957 l 87.469 103.813 l 103.535 + 39.867 l 136 97.25 l 201.777 92.766 l 157.234 141.375 l 181.824 202.551 + l 121.832 175.207 l h +71.25 217.5 m S Q +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/shapes_expected.wmf b/testfiles/cli_tests/testcases/shapes_expected.wmf Binary files differnew file mode 100644 index 0000000..1b3fdcf --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes_expected.wmf diff --git a/testfiles/cli_tests/testcases/shapes_expected.xaml b/testfiles/cli_tests/testcases/shapes_expected.xaml new file mode 100644 index 0000000..025f668 --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes_expected.xaml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--This file is NOT compatible with Silverlight--> +<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Stretch="Uniform"> + <Canvas Name="svg10" Width="400" Height="300"> + <Canvas.Resources/> + <!--Unknown tag: metadata--> + <!--Unknown tag: sodipodi:namedview--> + <Canvas Name="g8"> + <Rectangle xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="10" Canvas.Top="5" Width="160" Height="130" Name="rect2" Fill="#FF0000FF" StrokeThickness="2" Stroke="#FF000000"/> + <Ellipse xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Canvas.Left="155" Width="240" Canvas.Top="30" Height="200" Name="ellipse4" Fill="#FFFF0000" StrokeThickness="4" Stroke="#FF000000"/> + <Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path6" Fill="#FFFFFF00" StrokeThickness="6" Stroke="#FF000000"> + <Path.Data> + <PathGeometry Figures="m95 290 9.9517-87.343-74.468-46.716 86.143-17.526 21.418-85.259 43.288 76.511 87.704-5.9771-59.39 64.812 32.787 81.565-79.993-36.455z" FillRule="NonZero"/> + </Path.Data> + </Path> + </Canvas> + </Canvas> +</Viewbox> diff --git a/testfiles/cli_tests/testcases/square_mm.svg b/testfiles/cli_tests/testcases/square_mm.svg new file mode 100644 index 0000000..b52aec6 --- /dev/null +++ b/testfiles/cli_tests/testcases/square_mm.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="200mm" height="200mm"> + <rect x="50mm" y="50mm" width="50mm" height="100mm" fill="blue" id="square-blue" /> + <rect x="100mm" y="50mm" width="50mm" height="100mm" fill="red" id="square-red" /> +</svg> diff --git a/testfiles/cli_tests/testcases/square_mm_viewbox.svg b/testfiles/cli_tests/testcases/square_mm_viewbox.svg new file mode 100644 index 0000000..394b205 --- /dev/null +++ b/testfiles/cli_tests/testcases/square_mm_viewbox.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="200mm" height="200mm" viewBox="0 0 200 200"> + <!-- Consider that usually 1 user unit = 1 px = 1/96 inch, but viewBox scale the the drawing here, + so that 1 (unitless) user unit is equivalent to 1 mm after scaling. + The first square (square-mm) doesn't actually have a size of 100 mm. + The second and third square together has the size of 100 mm × 100 mm. + <rect x="0" y="0" width="100mm" height="100mm" fill="yellow" id="square-mm" />--> + <rect x="50" y="50" width="50" height="100" fill="blue" id="square-blue" /> + <rect x="100" y="50" width="50" height="100" fill="red" id="square-red" /> +</svg> diff --git a/testfiles/cli_tests/testcases/square_px.svg b/testfiles/cli_tests/testcases/square_px.svg new file mode 100644 index 0000000..7467f7d --- /dev/null +++ b/testfiles/cli_tests/testcases/square_px.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px"> + <rect x="50" y="50" width="50" height="100" fill="blue" id="square-blue" /> + <rect x="100" y="50" width="50" height="100" fill="red" id="square-red" /> +</svg> diff --git a/testfiles/cli_tests/testcases/systemLanguage.svg b/testfiles/cli_tests/testcases/systemLanguage.svg new file mode 100644 index 0000000..c650dc9 --- /dev/null +++ b/testfiles/cli_tests/testcases/systemLanguage.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="500" height="100"> + <switch id="switch"> + <!-- some fuzz to probe for crashing issues --> + <rect systemLanguage="" width="1" height="1"/> + <rect systemLanguage=" " width="1" height="1"/> + <rect systemLanguage="_" width="1" height="1"/> + <rect systemLanguage="-" width="1" height="1"/> + <rect systemLanguage="#" width="1" height="1"/> + <rect systemLanguage="-CH" width="1" height="1"/> + + <!-- use rects instead of text to avoid any issues with font rendering --> + <!-- note: we don't support the 'allowReorder' attribute yet --> + <rect systemLanguage="en" x="10" y="10" width="80" height="80" fill="#00f"/> + <rect systemLanguage="fr" x="110" y="10" width="80" height="80" fill="#00f"/> + <rect systemLanguage="de-CH" x="210" y="10" width="80" height="80" fill="#00f"/> + <rect systemLanguage="es, pt" x="310" y="10" width="80" height="80" fill="#00f"/> + <rect x="410" y="10" width="80" height="80" fill="#00f"/> + </switch> +</svg> diff --git a/testfiles/cli_tests/testcases/systemLanguage_RDF.svg b/testfiles/cli_tests/testcases/systemLanguage_RDF.svg new file mode 100644 index 0000000..7e1223e --- /dev/null +++ b/testfiles/cli_tests/testcases/systemLanguage_RDF.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="500" height="100" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <metadata> + <rdf:RDF> + <cc:Work> + <dc:language>fr</dc:language> + </cc:Work> + </rdf:RDF> + </metadata> + <use xlink:href="systemLanguage.svg#switch" /> +</svg> diff --git a/testfiles/cli_tests/testcases/systemLanguage_de.png b/testfiles/cli_tests/testcases/systemLanguage_de.png Binary files differnew file mode 100644 index 0000000..1dbfe36 --- /dev/null +++ b/testfiles/cli_tests/testcases/systemLanguage_de.png diff --git a/testfiles/cli_tests/testcases/systemLanguage_default.png b/testfiles/cli_tests/testcases/systemLanguage_default.png Binary files differnew file mode 100644 index 0000000..67cb9f0 --- /dev/null +++ b/testfiles/cli_tests/testcases/systemLanguage_default.png diff --git a/testfiles/cli_tests/testcases/systemLanguage_en.png b/testfiles/cli_tests/testcases/systemLanguage_en.png Binary files differnew file mode 100644 index 0000000..31679aa --- /dev/null +++ b/testfiles/cli_tests/testcases/systemLanguage_en.png diff --git a/testfiles/cli_tests/testcases/systemLanguage_fr.png b/testfiles/cli_tests/testcases/systemLanguage_fr.png Binary files differnew file mode 100644 index 0000000..deeb4bf --- /dev/null +++ b/testfiles/cli_tests/testcases/systemLanguage_fr.png diff --git a/testfiles/cli_tests/testcases/systemLanguage_pt.png b/testfiles/cli_tests/testcases/systemLanguage_pt.png Binary files differnew file mode 100644 index 0000000..91e5b4b --- /dev/null +++ b/testfiles/cli_tests/testcases/systemLanguage_pt.png diff --git a/testfiles/cli_tests/testcases/text.svg b/testfiles/cli_tests/testcases/text.svg new file mode 100644 index 0000000..5dd1c7f --- /dev/null +++ b/testfiles/cli_tests/testcases/text.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="50px"> + <text x="10" y="25">some text</text> +</svg> diff --git a/testfiles/doc-per-case-test.cpp b/testfiles/doc-per-case-test.cpp new file mode 100644 index 0000000..0f3721c --- /dev/null +++ b/testfiles/doc-per-case-test.cpp @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Test fixture with SPDocument per entire test case. + * + * Author: + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "doc-per-case-test.h" + +#include "inkscape.h" + +SPDocument *DocPerCaseTest::_doc = 0; + +DocPerCaseTest::DocPerCaseTest() : + ::testing::Test() +{ +} + +void DocPerCaseTest::SetUpTestCase() +{ + if ( !Inkscape::Application::exists() ) + { + // Create the global inkscape object. + Inkscape::Application::create(false); + } + + _doc = SPDocument::createNewDoc( NULL, TRUE, true ); + ASSERT_TRUE( _doc != NULL ); +} + +void DocPerCaseTest::TearDownTestCase() +{ + if (_doc) { + _doc->doUnref(); + _doc = NULL; + } +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/testfiles/doc-per-case-test.h b/testfiles/doc-per-case-test.h new file mode 100644 index 0000000..fbd6ff3 --- /dev/null +++ b/testfiles/doc-per-case-test.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Test fixture with SPDocument per entire test case. + * + * Author: + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtest/gtest.h" + +#include "document.h" + + +/** + * Simple fixture that creates a single SPDocument to be shared between all tests + * in this test case. + */ +class DocPerCaseTest : public ::testing::Test +{ +public: + DocPerCaseTest(); + +protected: + static void SetUpTestCase(); + + static void TearDownTestCase(); + + static SPDocument *_doc; +}; + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/testfiles/fuzzer.cpp b/testfiles/fuzzer.cpp new file mode 100644 index 0000000..450d98c --- /dev/null +++ b/testfiles/fuzzer.cpp @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: see git history + * + * Copyright (C) 2017 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include "xml/repr.h" +#include "inkscape.h" +#include "document.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + g_type_init(); + Inkscape::GC::init(); + if ( !Inkscape::Application::exists() ) + Inkscape::Application::create(false); + //void* a= sp_repr_read_mem((const char*)data, size, 0); + SPDocument *doc = SPDocument::createNewDocFromMem( (const char*)data, size, 0); + if(doc) + doc->doUnref(); + return 0; +} diff --git a/testfiles/fuzzer.dict b/testfiles/fuzzer.dict new file mode 100644 index 0000000..c746484 --- /dev/null +++ b/testfiles/fuzzer.dict @@ -0,0 +1,526 @@ +# Dictionary for the fuzzer to "guess" faster important words. +# Contains xml keywords and svg element names and attributes. +# It might be useful to remove some of them, maybe. +# SPDX-License-Identifier: GPL-2.0-or-later + +"100" +"200" +"300" +"400" +"500" +"600" +"700" +"800" +"900" +"a" +"accent-height" +"accumulate" +"additive" +"after-edge" +"alignment-baseline" +"all" +"alphabetic" +"altGlyph" +"altGlyphDef" +"altGlyphItem" +"amplitude" +"animate" +"animateColor" +"animateMotion" +"animateTransform" +"arabic-form" +"ascent" +attr_encoding=" encoding=\"1\"" +attr_generic=" a=\"1\"" +attr_href=" href=\"1\"" +"attributeName" +"attributeType" +attr_standalone=" standalone=\"no\"" +attr_version=" version=\"1\"" +attr_xml_base=" xml:base=\"1\"" +attr_xml_id=" xml:id=\"1\"" +attr_xml_lang=" xml:lang=\"1\"" +attr_xmlns=" xmlns=\"1\"" +attr_xml_space=" xml:space=\"1\"" +"auto" +"azimuth" +"baseFrequency" +"baseline" +"baseline-shift" +"baseProfile" +"bbox" +"before-edge" +"begin" +"bevel" +"bias" +"bidi-override" +"blink" +"block" +"bold" +"bolder" +"butt" +"by" +"calcMode" +"cap-height" +"caption" +"central" +"circle" +"class" +"clip" +"clip-path" +"clipPath" +"clipPathUnits" +"clip-rule" +"collapse" +"color" +"color-interpolation" +"color-interpolation-filters" +"color-profile" +"color-rendering" +"compact" +"condensed" +"contentScriptType" +"contentStyleType" +"crispEdges" +"crosshair" +"currentColor" +"cursor" +"cx" +"cy" +"d" +"default" +"defs" +"desc" +"descent" +"diffuseConstant" +"direction" +"display" +"divisor" +"dominant-baseline" +"dur" +"dx" +"dy" +"edgeMode" +"elevation" +"ellipse" +"embed" +"enable-background" +"end" +entity_builtin="<" +entity_decimal="" +entity_external="&a;" +entity_hex="" +"e-resize" +"evenodd" +"expanded" +"exponent" +"externalResourcesRequired" +"extra-condensed" +"extra-expanded" +"feBlend" +"feColorMatrix" +"feComponentTransfer" +"feComposite" +"feConvolveMatrix" +"feDiffuseLighting" +"feDisplacementMap" +"feDistantLight" +"feFlood" +"feFuncA" +"feFuncB" +"feFuncG" +"feFuncR" +"feGaussianBlur" +"feImage" +"feMerge" +"feMergeNode" +"feMorphology" +"feOffset" +"fePointLight" +"feSpecularLighting" +"feSpotLight" +"feTile" +"feTurbulence" +"fill" +"fill-opacity" +"fill-rule" +"filter" +"filterRes" +"filterUnits" +"flood-color" +"flood-opacity" +"font" +"font-face" +"font-face-format" +"font-face-name" +"font-face-src" +"font-face-uri" +"font-family" +"font-size" +"font-size-adjust" +"font-stretch" +"font-style" +"font-variant" +"font-weight" +"foreignObject" +"format" +"from" +"fx" +"fy" +"g" +"g1" +"g2" +"geometricPrecision" +"glyph" +"glyph-name" +"glyph-orientation-horizontal" +"glyph-orientation-vertical" +"glyphRef" +"gradientTransform" +"gradientUnits" +"hanging" +"height" +"help" +"hidden" +"hkern" +"horiz-adv-x" +"horiz-origin-x" +"horiz-origin-y" +"icon" +"id" +"ideographic" +"image" +"image-rendering" +"in" +"in2" +"individual" +"inherit" +"inline" +"inline-table" +"intercept" +"italic" +"k" +"k1" +"k2" +"k3" +"k4" +"kernelMatrix" +"kernelUnitLength" +"kerning" +"keyPoints" +"keySplines" +"keyTimes" +"lang" +"lengthAdjust" +"letter-spacing" +"lighter" +"lighting-color" +"limitingConeAngle" +"line" +"linearGradient" +"linearRGB" +"'line-height'" +"line-through" +"list-item" +"local" +"lr" +"lr-tb" +"ltr" +"marker" +"marker-end" +"markerHeight" +"marker-mid" +"marker-start" +"markerUnits" +"markerWidth" +"mask" +"maskContentUnits" +"maskUnits" +"mathematical" +"max" +"media" +"menu" +"message-box" +"metadata" +"method" +"middle" +"min" +"missing-glyph" +"miter" +"mode" +"move" +"mpath" +"name" +"narrower" +"ne-resize" +"new" +"no-change" +"none" +"nonzero" +"normal" +"n-resize" +"numOctaves" +"nw-resize" +"oblique" +"offset" +"onabort" +"onactivate" +"onbegin" +"onclick" +"onend" +"onerror" +"onfocusin" +"onfocusout" +"onload" +"onmousedown" +"onmousemove" +"onmouseout" +"onmouseover" +"onmouseup" +"onrepeat" +"onresize" +"onscroll" +"onunload" +"onzoom" +"opacity" +"operator" +"optimizeLegibility" +"optimizeQuality" +"optimizeSpeed" +"order" +"orient" +"orientation" +"origin" +"overflow" +"overline" +"overline-position" +"overline-thickness" +"paint" +"painted" +"panose-1" +"path" +"pathLength" +"pattern" +"patternContentUnits" +"patternTransform" +"patternUnits" +"pointer" +"pointer-events" +"points" +"pointsAtX" +"pointsAtY" +"pointsAtZ" +"polygon" +"polyline" +"preserveAlpha" +"preserveAspectRatio" +"primitiveUnits" +"properties" +"r" +"radialGradient" +"radius" +"rect" +"refX" +"refY" +"rendering-intent" +"repeatCount" +"repeatDur" +"requiredExtensions" +"requiredFeatures" +"reset-size" +"restart" +"result" +"rl" +"rl-tb" +"rotate" +"round" +"rtl" +"run-in" +"rx" +"ry" +"scale" +"script" +"scroll" +"see" +"seed" +"semi-condensed" +"semi-expanded" +"se-resize" +"set" +"shape-rendering" +"slope" +"small-caps" +"small-caption" +"spacing" +"Specifying" +"specularConstant" +"specularExponent" +"spreadMethod" +"square" +"s-resize" +"sRGB" +"start" +"startOffset" +"status-bar" +"stdDeviation" +"stemh" +"stemv" +"stitchTiles" +"stop" +"stop-color" +"stop-opacity" +"strikethrough-position" +"strikethrough-thickness" +"string" +string_any="ANY" +string_brackets="[]" +string_cdata="CDATA" +string_col_fallback=":fallback" +string_col_generic=":a" +string_col_include=":include" +string_dashes="--" +string_empty_dblquotes="\"\"" +string_empty="EMPTY" +string_empty_quotes="''" +string_entities="ENTITIES" +string_entity="ENTITY" +string_fixed="#FIXED" +string_id="ID" +string_idref="IDREF" +string_idrefs="IDREFS" +string_implied="#IMPLIED" +string_nmtoken="NMTOKEN" +string_nmtokens="NMTOKENS" +string_notation="NOTATION" +string_parentheses="()" +string_pcdata="#PCDATA" +string_percent="%a" +string_public="PUBLIC" +string_required="#REQUIRED" +string_schema=":schema" +string_system="SYSTEM" +string_ucs4="UCS-4" +string_utf16="UTF-16" +string_utf8="UTF-8" +string_xmlns="xmlns:" +"stroke" +"stroke-dasharray" +"stroke-dashoffset" +"stroke-linecap" +"stroke-linejoin" +"stroke-miterlimit" +"stroke-opacity" +"stroke-width" +"style" +"sub" +"super" +"surfaceScale" +"svg" +"switch" +"sw-resize" +"symbol" +"systemLanguage" +"table" +"table-caption" +"table-cell" +"table-column" +"table-column-group" +"table-footer-group" +"table-header-group" +"table-row" +"table-row-group" +"tableValues" +tag_attlist="<!ATTLIST" +tag_cdata="<![CDATA[" +tag_close="</a>" +tag_doctype="<!DOCTYPE" +tag_element="<!ELEMENT" +tag_entity="<!ENTITY" +tag_ignore="<![IGNORE[" +tag_include="<![INCLUDE[" +tag_notation="<!NOTATION" +tag_open="<a>" +tag_open_close="<a />" +tag_open_exclamation="<!" +tag_open_q="<?" +tag_sq2_close="]]>" +tag_xml_q="<?xml?>" +"target" +"targetX" +"targetY" +"tb" +"tb-rl" +"text" +"text-after-edge" +"text-anchor" +"text-before-edge" +"text-decoration" +"textLength" +"textPath" +"text-rendering" +"title" +"to" +"transform" +"tref" +"tspan" +"type" +"u1" +"u2" +"ultra-condensed" +"ultra-expanded" +"underline" +"underline-position" +"underline-thickness" +"unicode" +"unicode-bidi" +"unicode-range" +"units-per-em" +"use" +"use-script" +"v-alphabetic" +"values" +"version" +"vert-adv-y" +"vert-origin-x" +"vert-origin-y" +"v-hanging" +"v-ideographic" +"view" +"viewBox" +"viewTarget" +"visibility" +"visible" +"visibleFill" +"visiblePainted" +"visibleStroke" +"vkern" +"v-mathematical" +"wait" +"wider" +"width" +"widths" +"word-spacing" +"w-resize" +"writing-mode" +"x" +"x1" +"x2" +"xChannelSelector" +"x-height" +"xlink:actuate" +"xlink:arcrole" +"xlink:href" +"xlink:role" +"xlink:show" +"xlink:title" +"xlink:type" +#XML +"xml:base" +"xml:lang" +"xml:space" +"y" +"y1" +"y2" +"yChannelSelector" +"z" +"zoomAndPan" diff --git a/testfiles/rendering_tests/CMakeLists.txt b/testfiles/rendering_tests/CMakeLists.txt new file mode 100644 index 0000000..f3bef01 --- /dev/null +++ b/testfiles/rendering_tests/CMakeLists.txt @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +#add your test here (do not put the .svg extension) +set(RENDERING_TESTS + # -- Generic tests -- + test-empty + test-dont-crash + + # -- Selector tests -- + selector-important-002 + selector-important-003 + + multi-style + + # -- Text tests -- + ## Many (if not all) of these tests are sensitive to the text rendering stack: FreeType, HarfBuzz, Pango. + + # test-baseline-shift + ## Small differences with code adapted for Pango 1.44. + + # test-glyph-y-pos + ## to be fixed since an update happened between harfbuzz 1.5.1(OK) and 1.6.0(FAIL). + ## If you re-enable the test, you may have to *slightly* fix the expected rendering (hoping the fix happens upstream). + ## Please also check that the rendering with harfbuzz <=1.5.1 is not *too* wrong (for older systems) + ## cf Tav's post : https://www.patreon.com/posts/into-sinkhole-19021727 + ## and bug https://bugzilla.gnome.org/show_bug.cgi?id=787526 + + # test-rtl-vertical + + # text-shaping + ## Expected rendering generated with Pango 1.44. Currently fails with + ## CI as CI uses Pango 1.40. Enable after updating CI to Ubuntu 20.04. + + # text-glyphs-combining.svg + ## Expected rendering generated with Pango 1.44. + + # text-glyphs-vertical.svg + ## Expected rendering generated with Pango 1.44. + + # -- LPE tests -- + test-powerstroke-join +) + + +foreach(rendering_test ${RENDERING_TESTS}) + set(testname "render_${rendering_test}") + add_test(NAME ${testname} + COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/test.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/inkscape ${CMAKE_CURRENT_SOURCE_DIR}/${rendering_test} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/testfiles/rendering_tests) + set_tests_properties(${testname} PROPERTIES ENVIRONMENT "${INKSCAPE_TEST_PROFILE_DIR_ENV}/${testname};${CMAKE_CTEST_ENV}") +endforeach() + diff --git a/testfiles/rendering_tests/README b/testfiles/rendering_tests/README new file mode 100644 index 0000000..6ebcb4c --- /dev/null +++ b/testfiles/rendering_tests/README @@ -0,0 +1,26 @@ +HOWTO + +# Add a rendering test: + - create the svg file + - 0.92: + - inkscape <yourfile>.svg -d 96 -e expected_rendering/<yourfile>.png + - inkscape <yourfile>.svg -d 384 -e expected_rendering/<yourfile>-large.png + - 1.0: + - inkscape -d 96 --export-filename=expected_rendering/<yourfile>.png <yourfile>.svg + - inkscape -d 384 --export-filename=expected_rendering/<yourfile>-large.png <yourfile>.svg + - add the test in CMakeLists.txt + - use stable if possible to generate the reference png files + - git add <yourfile>.svg expected_rendering/<yourfile>-large.png expected_rendering/<yourfile>.png + +# Fix a failing test (due to a change in code): + - DO *NOT* MODIFY the expected rendering (or the svg) before getting advice from inkscape-devel@ + - fix your code if possible + - IF you change introduces a greater compatibility with css or browsers + - AND you cannot reasonably "update" files from older versions to match the appearance + - AND inkscape-devel@ has a consensus that it's the only way + -> do as you must + - manually double check the changes + +# Fix a failing test (due to a change in pixman or cairo): + - update renderings. Use a *stable* version to generate the renderings, NOT TRUNK + - manually check appearances diff --git a/testfiles/rendering_tests/expected_rendering/multi-style.png b/testfiles/rendering_tests/expected_rendering/multi-style.png Binary files differnew file mode 100644 index 0000000..7c7c2fb --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/multi-style.png diff --git a/testfiles/rendering_tests/expected_rendering/selector-important-002-large.png b/testfiles/rendering_tests/expected_rendering/selector-important-002-large.png Binary files differnew file mode 100644 index 0000000..e92eef0 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/selector-important-002-large.png diff --git a/testfiles/rendering_tests/expected_rendering/selector-important-002.png b/testfiles/rendering_tests/expected_rendering/selector-important-002.png Binary files differnew file mode 100644 index 0000000..b0af9bd --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/selector-important-002.png diff --git a/testfiles/rendering_tests/expected_rendering/selector-important-003-large.png b/testfiles/rendering_tests/expected_rendering/selector-important-003-large.png Binary files differnew file mode 100644 index 0000000..91cb3af --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/selector-important-003-large.png diff --git a/testfiles/rendering_tests/expected_rendering/selector-important-003.png b/testfiles/rendering_tests/expected_rendering/selector-important-003.png Binary files differnew file mode 100644 index 0000000..dfe3dbc --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/selector-important-003.png diff --git a/testfiles/rendering_tests/expected_rendering/test-baseline-shift-large.png b/testfiles/rendering_tests/expected_rendering/test-baseline-shift-large.png Binary files differnew file mode 100644 index 0000000..29369a8 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-baseline-shift-large.png diff --git a/testfiles/rendering_tests/expected_rendering/test-baseline-shift.png b/testfiles/rendering_tests/expected_rendering/test-baseline-shift.png Binary files differnew file mode 100644 index 0000000..45aed90 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-baseline-shift.png diff --git a/testfiles/rendering_tests/expected_rendering/test-dont-crash.png b/testfiles/rendering_tests/expected_rendering/test-dont-crash.png Binary files differnew file mode 100644 index 0000000..a2d005e --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-dont-crash.png diff --git a/testfiles/rendering_tests/expected_rendering/test-empty-large.png b/testfiles/rendering_tests/expected_rendering/test-empty-large.png Binary files differnew file mode 100644 index 0000000..34acf1f --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-empty-large.png diff --git a/testfiles/rendering_tests/expected_rendering/test-empty.png b/testfiles/rendering_tests/expected_rendering/test-empty.png Binary files differnew file mode 100644 index 0000000..2e0a5fe --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-empty.png diff --git a/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos-large.png b/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos-large.png Binary files differnew file mode 100644 index 0000000..e60f477 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos-large.png diff --git a/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos.png b/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos.png Binary files differnew file mode 100644 index 0000000..85a3050 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos.png diff --git a/testfiles/rendering_tests/expected_rendering/test-powerstroke-join-large.png b/testfiles/rendering_tests/expected_rendering/test-powerstroke-join-large.png Binary files differnew file mode 100644 index 0000000..72d8821 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-powerstroke-join-large.png diff --git a/testfiles/rendering_tests/expected_rendering/test-powerstroke-join.png b/testfiles/rendering_tests/expected_rendering/test-powerstroke-join.png Binary files differnew file mode 100644 index 0000000..1eeec07 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-powerstroke-join.png diff --git a/testfiles/rendering_tests/expected_rendering/test-rtl-vertical-large.png b/testfiles/rendering_tests/expected_rendering/test-rtl-vertical-large.png Binary files differnew file mode 100644 index 0000000..84abe78 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-rtl-vertical-large.png diff --git a/testfiles/rendering_tests/expected_rendering/test-rtl-vertical.png b/testfiles/rendering_tests/expected_rendering/test-rtl-vertical.png Binary files differnew file mode 100644 index 0000000..ea8836f --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/test-rtl-vertical.png diff --git a/testfiles/rendering_tests/expected_rendering/text-glyphs-combining-large.png b/testfiles/rendering_tests/expected_rendering/text-glyphs-combining-large.png Binary files differnew file mode 100644 index 0000000..6952968 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/text-glyphs-combining-large.png diff --git a/testfiles/rendering_tests/expected_rendering/text-glyphs-combining.png b/testfiles/rendering_tests/expected_rendering/text-glyphs-combining.png Binary files differnew file mode 100644 index 0000000..98e06a7 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/text-glyphs-combining.png diff --git a/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical-large.png b/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical-large.png Binary files differnew file mode 100644 index 0000000..d7091db --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical-large.png diff --git a/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical.png b/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical.png Binary files differnew file mode 100644 index 0000000..eb46075 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical.png diff --git a/testfiles/rendering_tests/expected_rendering/text-shaping-large.png b/testfiles/rendering_tests/expected_rendering/text-shaping-large.png Binary files differnew file mode 100644 index 0000000..e84ebf5 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/text-shaping-large.png diff --git a/testfiles/rendering_tests/expected_rendering/text-shaping.png b/testfiles/rendering_tests/expected_rendering/text-shaping.png Binary files differnew file mode 100644 index 0000000..346ab77 --- /dev/null +++ b/testfiles/rendering_tests/expected_rendering/text-shaping.png diff --git a/testfiles/rendering_tests/fonts/Estedad-Medium.ttf b/testfiles/rendering_tests/fonts/Estedad-Medium.ttf Binary files differnew file mode 100644 index 0000000..d4844c2 --- /dev/null +++ b/testfiles/rendering_tests/fonts/Estedad-Medium.ttf diff --git a/testfiles/rendering_tests/fonts/GeomTest-Regular.otf b/testfiles/rendering_tests/fonts/GeomTest-Regular.otf Binary files differnew file mode 100755 index 0000000..f11fd09 --- /dev/null +++ b/testfiles/rendering_tests/fonts/GeomTest-Regular.otf diff --git a/testfiles/rendering_tests/fonts/LICENSES b/testfiles/rendering_tests/fonts/LICENSES new file mode 100644 index 0000000..71bfc0e --- /dev/null +++ b/testfiles/rendering_tests/fonts/LICENSES @@ -0,0 +1,10 @@ + +All fonts in this directory are licensed under open licenses. + +Lohit (https://pagure.io/lohit SIL Open Font 1.1) +NotoSans (https://www.google.com/get/noto/ Open Font License 1.1) +Estedad (https://github.com/aminabedi68/Estedad/ SIL Open Font 1.1) + +GeomTest Released under Open Font Licens 1.1. Copyright Tavmjong Bah 2015,2019 + + diff --git a/testfiles/rendering_tests/fonts/Lohit-Telugu.ttf b/testfiles/rendering_tests/fonts/Lohit-Telugu.ttf Binary files differnew file mode 100644 index 0000000..3869703 --- /dev/null +++ b/testfiles/rendering_tests/fonts/Lohit-Telugu.ttf diff --git a/testfiles/rendering_tests/fonts/NotoSans-Regular.ttf b/testfiles/rendering_tests/fonts/NotoSans-Regular.ttf Binary files differnew file mode 100644 index 0000000..b031a49 --- /dev/null +++ b/testfiles/rendering_tests/fonts/NotoSans-Regular.ttf diff --git a/testfiles/rendering_tests/fonts/NotoSansCJKjp-Regular.otf b/testfiles/rendering_tests/fonts/NotoSansCJKjp-Regular.otf Binary files differnew file mode 100644 index 0000000..296fbeb --- /dev/null +++ b/testfiles/rendering_tests/fonts/NotoSansCJKjp-Regular.otf diff --git a/testfiles/rendering_tests/fonts/NotoSansHebrew-Regular.ttf b/testfiles/rendering_tests/fonts/NotoSansHebrew-Regular.ttf Binary files differnew file mode 100644 index 0000000..9bf03ab --- /dev/null +++ b/testfiles/rendering_tests/fonts/NotoSansHebrew-Regular.ttf diff --git a/testfiles/rendering_tests/multi-style.svg b/testfiles/rendering_tests/multi-style.svg new file mode 100644 index 0000000..473192e --- /dev/null +++ b/testfiles/rendering_tests/multi-style.svg @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns="http://www.w3.org/2000/svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="80" + height="80" + viewBox="0 0 80 80" + version="1.1"> + <style + id="first"> +rect { fill: #800000; } +/* class "c1" is redefined several times, only the last one counts */ +.c1 { fill: #ff0000; } +.c2 { fill: #ff9900; } +</style> + <defs> + <style + id="insidedefs"> +rect { fill: #ffff00; } +.c1 { fill: #008000; } +.c3 { fill: #00ff00; } +</style> + </defs> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + id="background" + width="80" + height="80" /> + <rect + width="20" + height="20" /> + <rect + width="20" + height="20" + x="30" + class="c1" /> + <rect + width="20" + height="20" + x="60" + class="c2" /> + <rect + width="20" + height="20" + class="c3" + y="30" /> + <rect + class="c4" + width="20" + height="20" + x="30" + y="30" /> + <rect + class="c5" + width="20" + height="20" + x="60" + y="30" /> + <style + id="insidegroup"> +#background { fill: white; } +.c5 { fill: #00ccff; } +/* nested CSS selector (with XML entity because not using CDATA) */ +g.g1 > rect { fill: #00ffcc; } +</style> + <rect + class="c5" + width="20" + height="20" + y="60" /> + <rect + width="20" + height="20" + x="30" + y="60" /> + <g + class="g1"> + <rect + width="20" + height="20" + x="60" + y="60" /> + </g> + </g> + <style + id="last"><!-- using CDATA --><![CDATA[ +rect { fill: #0000ff; } +.c1 { fill: #990099; } +.c4 { fill: #ff00ff; } +]]></style> +</svg> diff --git a/testfiles/rendering_tests/selector-important-002.svg b/testfiles/rendering_tests/selector-important-002.svg new file mode 100644 index 0000000..e5a66b6 --- /dev/null +++ b/testfiles/rendering_tests/selector-important-002.svg @@ -0,0 +1,58 @@ +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="480" height="360" + style="fill:orange !important"> + + <title>Style "!important" — 002</title> + + <style type="text/css"> + + <!-- Later rule overrides same specificity previous rule. --> + #groupA use { fill: red !important; } + #groupA use { fill: blue !important; } + + #groupB .classB { fill: red !important; } + #groupB .classB { fill: blue !important; } + + #groupC #MyRectC { fill: red !important; } + #groupC #MyRectC { fill: blue !important; } + + #groupD { fill: blue !important; } + #classD { fill: red !important; } + + #groupE use { fill: blue !important; } + #groupE { fill: red !important; } + </style> + + <defs> + <rect id="MyRect" width="40" height="40"/> + </defs> + + <!-- + <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Style "!important" — 002</text> + <a href="https://svgwg.org/svg2-draft/stylling.html"> + <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/styling.html</text> + </a> + --> + + <g id="groupA"> + <use id="MyRectA" class="classA" x="20" y="100" xlink:href="#MyRect" /> + </g> + + <g id="groupB"> + <use id="MyRectB" class="classB" x="120" y="100" xlink:href="#MyRect" /> + </g> + + <g id="groupC"> + <use id="MyRectC" class="classC" x="220" y="100" xlink:href="#MyRect" /> + </g> + + <g id="groupD"> + <use id="MyRectD" class="classD" x="320" y="100" xlink:href="#MyRect" /> + </g> + + <g id="groupE"> + <use id="MyRectE" class="classE" x="420" y="100" xlink:href="#MyRect" /> + </g> + +</svg> diff --git a/testfiles/rendering_tests/selector-important-003.svg b/testfiles/rendering_tests/selector-important-003.svg new file mode 100644 index 0000000..831319f --- /dev/null +++ b/testfiles/rendering_tests/selector-important-003.svg @@ -0,0 +1,57 @@ +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="480" height="360"> + + <title>Style "!important" — 003</title> + + <style type="text/css"> + + /* !important is not inherited. */ + g #groupA { fill: red !important; } + use { fill: blue; } + + /* Attributes cannot have !important. */ + #MyRectB { fill: blue; } + + /* Inline can have !important. */ + #MyRectC { fill: red !important; } + + /* Bad property shouldn't set !important. */ + #MyRectD { fill: XXX !important; } + + /* Bad inline property shouldn't set !important. */ + #MyRectE { fill: blue; } + </style> + + <defs> + <rect id="MyRect" width="40" height="40"/> + </defs> + + <!-- + <text id="title" x="240" y="50" style="fill:black; font-size:24px; text-anchor:middle;">Style "!important" — 003</text> + <a href="https://svgwg.org/svg2-draft/stylling.html"> + <text id="source" x="240" y="70" style="fill:black; font-size:12px; text-anchor:middle;">https://svgwg.org/svg2-draft/styling.html</text> + </a> + --> + + <g id="groupA"> + <use id="MyRectA" class="classA" x="20" y="100" xlink:href="#MyRect" /> + </g> + + <g id="groupB"> + <use id="MyRectB" class="classB" x="120" y="100" xlink:href="#MyRect" fill="red !important"/> + </g> + + <g id="groupC"> + <use id="MyRectC" class="classC" x="220" y="100" xlink:href="#MyRect" style="fill: blue !important"/> + </g> + + <g id="groupD"> + <use id="MyRectD" class="classD" x="320" y="100" xlink:href="#MyRect" style="fill: blue"/> + </g> + + <g id="groupE"> + <use id="MyRectE" class="classE" x="420" y="100" xlink:href="#MyRect" style="fill: XXX !important"/> + </g> + +</svg> diff --git a/testfiles/rendering_tests/test-baseline-shift.svg b/testfiles/rendering_tests/test-baseline-shift.svg new file mode 100644 index 0000000..534ffab --- /dev/null +++ b/testfiles/rendering_tests/test-baseline-shift.svg @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> + +<svg width="600" height="600" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + viewBox="0 0 600 600"> + <style type="text/css"> + text { + font-family: DejaVu Sans; + font-size: 36px; + } + .title { + text-anchor: middle; + } + </style> + + <g> + <text x="50" y="200">subscript: H<tspan style="font-size:65%;baseline-shift:sub">2</tspan>O</text> + <text x="50" y="300">superscript: m<tspan style="font-size:65%;baseline-shift:super">2</tspan></text> + <text x="530" y="200" style="writing-mode:tb-rl">subscript: H<tspan style="font-size:65%;baseline-shift:sub">2</tspan>O</text> + <text x="430" y="200" style="writing-mode:tb-rl">superscript: m<tspan style="font-size:65%;baseline-shift:super">2</tspan></text> + </g> + + <text class="title" x="50%" y="120">Sub- and Superscript</text> + +</svg> diff --git a/testfiles/rendering_tests/test-dont-crash.svg b/testfiles/rendering_tests/test-dont-crash.svg new file mode 100644 index 0000000..d01c0ea --- /dev/null +++ b/testfiles/rendering_tests/test-dont-crash.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + viewBox="0 0 210 297" + height="297mm" + width="210mm"> + <g + id="layer1" + inkscape:groupmode="layer" + inkscape:label="Layer 1"> + <!-- missing xlink:href attribute - don't care how it's rendered (place it + off-page), but Inkscape should not crash --> + <image + y="-100" + x="-100" + height="50" + width="50" /> + </g> +</svg> diff --git a/testfiles/rendering_tests/test-empty.svg b/testfiles/rendering_tests/test-empty.svg new file mode 100644 index 0000000..3b5ee5a --- /dev/null +++ b/testfiles/rendering_tests/test-empty.svg @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="210mm" + height="297mm" + viewBox="0 0 210 297" + version="1.1" + id="svg8" + inkscape:version="0.92.1 r15371" + sodipodi:docname="test-empty.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.7" + inkscape:cx="132.86611" + inkscape:cy="438.52092" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1920" + inkscape:window-height="1055" + inkscape:window-x="1920" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <rect + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:2.64583325;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98039216" + id="rect7" + width="92.226196" + height="75.595238" + x="52.160713" + y="46.023808" + rx="6.6565199" + ry="6.6565199" /> + </g> +</svg> diff --git a/testfiles/rendering_tests/test-glyph-y-pos.svg b/testfiles/rendering_tests/test-glyph-y-pos.svg new file mode 100644 index 0000000..28200c7 --- /dev/null +++ b/testfiles/rendering_tests/test-glyph-y-pos.svg @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> + +<svg width="600" height="600" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + viewBox="0 0 600 600"> + <style type="text/css"> + text { + font-family: DejaVu Sans; + font-size: 36px; + } + .title { + text-anchor: middle; + } + </style> + + <g> + <text x="50" y="200">G̃g̃X̃x̃</text> + <text x="300" y="200" style="writing-mode:vertical-lr;">G̃g̃X̃x̃</text> + <text x="500" y="200" style="writing-mode:vertical-lr;text-orientation:upright">G̃g̃X̃x̃</text> + </g> + + <text class="title" x="50%" y="120">Composed Glyphs</text> + +</svg> diff --git a/testfiles/rendering_tests/test-powerstroke-join.svg b/testfiles/rendering_tests/test-powerstroke-join.svg new file mode 100644 index 0000000..2c05fb3 --- /dev/null +++ b/testfiles/rendering_tests/test-powerstroke-join.svg @@ -0,0 +1,6 @@ +<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns="http://www.w3.org/2000/svg" height="103.10469" width="114.42079"> + <defs id="defs8"> + <inkscape:path-effect end_linecap_type="zerowidth" scale_width="1" miter_limit="4" linejoin_type="extrp_arc" start_linecap_type="zerowidth" interpolator_beta="0.2" interpolator_type="CubicBezierSmooth" sort_points="true" offset_points="0.2,6 | 1,6 | 1.8,6" lpeversion="1" is_visible="true" id="path-effect12" effect="powerstroke" /> + </defs> + <path inkscape:original-d="M 37.025152,63.80944 C 62.629473,85.82239 121.42349,99.11534 92.9073,25.53973 73.516303,45.478852 29.421533,5.937486 9.304592,36.285332" inkscape:path-effect="#path-effect12"/> +</svg> diff --git a/testfiles/rendering_tests/test-rtl-vertical.svg b/testfiles/rendering_tests/test-rtl-vertical.svg new file mode 100644 index 0000000..a959c18 --- /dev/null +++ b/testfiles/rendering_tests/test-rtl-vertical.svg @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> + +<svg width="600" height="600" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + viewBox="0 0 600 600"> + <style type="text/css"> + text { + font-family: DejaVu Sans; + font-size: 36px; + } + .title { + text-anchor: middle; + } + </style> + + <g> + <text x="50" y="200">أبجد</text> + <text x="300" y="200" style="writing-mode:vertical-lr;">بجد</text> + <text x="500" y="200" style="writing-mode:vertical-lr;text-orientation:upright">أبجد</text> + </g> + + <text class="title" x="50%" y="120">RTL text in vertical mode</text> + +</svg> diff --git a/testfiles/rendering_tests/test.sh b/testfiles/rendering_tests/test.sh new file mode 100755 index 0000000..11167dd --- /dev/null +++ b/testfiles/rendering_tests/test.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later + +if [ "$#" -lt 2 ]; then + echo "pass the path of the inkscape executable as parameter then the name of the test" $# + exit 1 +fi + +command -v compare >/dev/null 2>&1 || { echo >&2 "I require ImageMagick's 'compare' but it's not installed. Aborting."; exit 1; } + +INKSCAPE_EXE=$1 +exit_status=0 +test=$2 +EXPECTED=$(dirname $test)"/expected_rendering/"$(basename $test) +testname=$(basename $test) + + + ${INKSCAPE_EXE} --export-filename=${testname}.png -d 96 ${test}.svg #2>/dev/null >/dev/null + compare -metric AE ${testname}.png ${EXPECTED}.png ${testname}-compare.png 2> ${testname}-result.txt + test1=`cat ${testname}-result.txt` + echo $test1 + if [ "$test1" = 0 ]; then + echo ${testname} "PASSED" + rm ${testname}.png ${testname}-compare.png + else + echo ${testname} "FAILED" + exit_status=1 + fi + +if [ -f "${EXPECTED}-large.png" ]; then + ${INKSCAPE_EXE} --export-filename=${testname}-large.png -d 384 ${test}.svg #2>/dev/null >/dev/null + compare -metric AE ${testname}-large.png ${EXPECTED}-large.png ${testname}-compare-large.png 2> ${testname}-result.txt + test2=`cat ${testname}-result.txt` + if [ "$test2" = 0 ]; then + echo ${testname}-large "PASSED" + rm ${testname}-large.png ${testname}-compare-large.png + else + echo ${testname}-large "FAILED" + exit_status=1 + fi +else + echo ${testname}-large "SKIPPED" +fi + +rm ${testname}-result.txt +exit $exit_status diff --git a/testfiles/rendering_tests/text-glyphs-combining.svg b/testfiles/rendering_tests/text-glyphs-combining.svg new file mode 100644 index 0000000..29be00e --- /dev/null +++ b/testfiles/rendering_tests/text-glyphs-combining.svg @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + width="100%" + height="100%" + viewBox="0 0 600 600"> + + <style type="text/css"> + + @font-face { + font-family: "Noto Sans"; + src: url("fonts/NotoSans-Regular.ttf"); + } + + text { + font-family: "Noto Sans"; + font-size: 30px; + } + + </style> + + <text x="25%" y="10%">õoÌ‹oÌ“oÌ›oÌ£oÌ«o̳oÌ»o̓oÍ‹oÍ—oÍ¡</text> + <text x="25%" y="25%" style="writing-mode:vertical-lr">õoÌ‹oÌ“oÌ›oÌ£oÌ«o̳oÌ»o̓oÍ‹oÍ—oÍ¡</text> + <text x="50%" y="25%" style="writing-mode:vertical-lr;text-orientation:upright">õoÌ‹oÌ“oÌ›oÌ£oÌ«o̳oÌ»o̓oÍ‹oÍ—oÍ¡</text> + <text x="75%" y="25%" style="writing-mode:vertical-lr;text-orientation:sideways">õoÌ‹oÌ“oÌ›oÌ£oÌ«o̳oÌ»o̓oÍ‹oÍ—oÍ¡</text> + + <!-- Show reference point --> + <circle cx="25%" cy="10%" r="2" style="fill:lightblue"/> + <circle cx="25%" cy="25%" r="2" style="fill:lightblue"/> + <circle cx="50%" cy="25%" r="2" style="fill:lightblue"/> + <circle cx="75%" cy="25%" r="2" style="fill:lightblue"/> + +</svg> diff --git a/testfiles/rendering_tests/text-glyphs-vertical.svg b/testfiles/rendering_tests/text-glyphs-vertical.svg new file mode 100644 index 0000000..f1264fd --- /dev/null +++ b/testfiles/rendering_tests/text-glyphs-vertical.svg @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + width="100%" + height="100%" + viewBox="0 0 600 600"> + + <style type="text/css"> + + @font-face { + font-family: "Noto Sans"; + src: url("fonts/NotoSans-Regular.ttf"); + } + + @font-face { + font-family: "Noto Sans CJK JP"; + src: url("fonts/NotoSansCJKjp-Regular.otf"); + } + + @font-face { + font-family: "GeomTest"; + src: url("fonts/GeomTest.otf"); + } + + text { + font-family: "Noto Sans"; + font-size: 30px; + } + + .geomtest { + font-family: GeomTest; + } + + </style> + + <text x="100" y="100">㆕㆖㆘<tspan class="geomtest">A回ーऄ</tspan>G̃g̃X̃x̃</text> + <text x="115" y="200" style="writing-mode:vertical-lr">㆕㆖㆘<tspan class="geomtest">A回ーऄ</tspan>G̃g̃X̃x̃</text> + <text x="305" y="200" style="writing-mode:vertical-lr;text-orientation:upright">㆕㆖㆘<tspan class="geomtest">A回ーऄ</tspan>G̃g̃X̃x̃</text> + <text x="495" y="200" style="writing-mode:vertical-lr;text-orientation:sideways">㆕㆖㆘<tspan class="geomtest">A回ーऄ</tspan>G̃g̃X̃x̃</text> + + <!-- Show reference point --> + <circle cx="100" cy="100" r="2" style="fill:lightblue"/> + <circle cx="115" cy="200" r="2" style="fill:lightblue"/> + <circle cx="305" cy="200" r="2" style="fill:lightblue"/> + <circle cx="495" cy="200" r="2" style="fill:lightblue"/> + +</svg> diff --git a/testfiles/rendering_tests/text-shaping.svg b/testfiles/rendering_tests/text-shaping.svg new file mode 100644 index 0000000..80aa95a --- /dev/null +++ b/testfiles/rendering_tests/text-shaping.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + width="100%" + height="100%" + viewBox="0 0 600 600"> + + <style type="text/css"> + + @font-face { + font-family: "Estedad"; + src: url("fonts/Estedad-Medium.ttf"); + } + + @font-face { + font-family: "Noto Sans Hebrew"; + src: url("fonts/NotoSansHebrew-Regular.ttf"); + } + + @font-face { + font-family: "Noto Sans"; + src: url("fonts/NotoSans-Regular.ttf"); + } + + @font-face { + font-family: "Noto Sans CJK JP"; + src: url("fonts/NotoSansCJKjp-Regular.otf"); + } + + @font-face { + font-family: "Lohit Telugu"; + src: url("fonts/Lohit-Telugu.ttf"); + } + + </style> + + <g style="fill:none;stroke:black;stroke-width:0.5px;font-size:42px;font-family:serif;text-anchor:middle"> + + <!-- bug https://gitlab.com/inkscape/inkscape/-/issues/469 --> + <text xml:space="preserve" + x="300" + y="50" + style="font-family:Estedad;direction:rtl">نیرو</text> + + <text xml:space="preserve" + x="300" + y="100" + style="font-family:Estedad;direction:rtl">بÙسْم٠اللَّه٠الرَّØْمَن٠الرَّØÙيمÙ</text> + + <text xml:space="preserve" + x="300" + y="150" + style="font-family:'Noto Sans Hebrew';direction:rtl">ש×ָלוֹ×</text> + + <text xml:space="preserve" + x="300" + y="200" + style="font-family:'Noto Sans Hebrew';direction:rtl">חִירִיק</text> + + <text xml:space="preserve" + x="300" + y="250" + style="font-family:'Noto Sans'">â â̂ aÌ‚ aÌ‚Ì‚</text> + + <text xml:space="preserve" + x="300" + y="300" + style="font-family:'Noto Sans'">a aÌ¥ Ä… ą</text> + + <text xml:space="preserve" + x="300" + y="350" + style="font-family:'Noto Sans CJK JP'">ヘ ペ ペ</text> + + <text xml:space="preserve" + x="300" + y="400" + style="font-family:'Lohit Telugu'">తెలà±à°—à±à°²à±‹</text> + + <!-- Teluga bug https://gitlab.com/inkscape/inkscape/-/issues/394 --> + <text xml:space="preserve" + x="300" + y="450" + style="font-family:'Lohit Telugu'">à°—à±à°°à°‚థాలయం</text> + + <!-- Teluga bug https://launchpadlibrarian.net/167162208/inkscape-telugu-text.svg --> + <text xml:space="preserve" + x="300" + y="500" + style="font-family:'Lohit Telugu'">ఇంకà±â€Œà°¸à±à°•à±‡à°ªà±</text> + </g> +</svg> diff --git a/testfiles/src/2geom-characterization-test.cpp b/testfiles/src/2geom-characterization-test.cpp new file mode 100644 index 0000000..d3f099b --- /dev/null +++ b/testfiles/src/2geom-characterization-test.cpp @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * 2Geom Lib characterization tests + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include <gtest/gtest.h> + +#include <2geom/path.h> + +TEST(Characterization2Geom, retrievingBackElementOfAnEmptyClosedPathFails) +{ + Geom::Path path(Geom::Point(3, 5)); + path.close(); + ASSERT_TRUE(path.closed()); + ASSERT_EQ(path.size_closed(), 0u); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/attributes-test.cpp b/testfiles/src/attributes-test.cpp new file mode 100644 index 0000000..791f140 --- /dev/null +++ b/testfiles/src/attributes-test.cpp @@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Unit tests for attributes. + * + * Author: + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <string> +#include <utility> +#include <vector> + +#include "gtest/gtest.h" + +#include "attributes.h" + +namespace { + +static const unsigned int FIRST_VALID_ID = 1; + +class AttributeInfo +{ +public: + AttributeInfo(std::string attr, bool supported) : + attr(std::move(attr)), + supported(supported) + { + } + + std::string attr; + bool supported; +}; + +typedef std::vector<AttributeInfo>::iterator AttrItr; + +std::vector<AttributeInfo> getKnownAttrs() +{ +/* Originally extracted mechanically from + http://www.w3.org/TR/SVG11/attindex.html: + + tidy -wrap 999 -asxml < attindex.html 2>/dev/null | + tr -d \\n | + sed 's,<tr>,@,g' | + tr @ \\n | + sed 's,</td>.*,,;s,^<td>,,;1,/^%/d;/^%/d;s,^, {",;s/$/", false},/' | + uniq + + attindex.html lacks attributeName, begin, additive, font, marker; + I've added these manually. + + SVG 2: white-space, shape-inside, shape-subtrace, shape-padding, shape-margin +*/ + AttributeInfo all_attrs[] = { + AttributeInfo("attributeName", true), + AttributeInfo("begin", true), + AttributeInfo("additive", true), + AttributeInfo("font", true), + AttributeInfo("-inkscape-font-specification", true), // TODO look into this attribute's name + AttributeInfo("marker", true), + AttributeInfo("line-height", true), + + AttributeInfo("accent-height", true), + AttributeInfo("accumulate", true), + AttributeInfo("alignment-baseline", true), + AttributeInfo("alphabetic", true), + AttributeInfo("amplitude", true), + AttributeInfo("animate", false), + AttributeInfo("arabic-form", true), + AttributeInfo("ascent", true), + AttributeInfo("attributeType", true), + AttributeInfo("azimuth", true), + AttributeInfo("baseFrequency", true), + AttributeInfo("baseline-shift", true), + AttributeInfo("baseProfile", false), + AttributeInfo("bbox", true), + AttributeInfo("bias", true), + AttributeInfo("by", true), + AttributeInfo("calcMode", true), + AttributeInfo("cap-height", true), + AttributeInfo("class", false), + AttributeInfo("clip", true), + AttributeInfo("clip-path", true), + AttributeInfo("clip-rule", true), + AttributeInfo("clipPathUnits", true), + AttributeInfo("color", true), + AttributeInfo("color-interpolation", true), + AttributeInfo("color-interpolation-filters", true), + AttributeInfo("color-profile", true), + AttributeInfo("color-rendering", true), + AttributeInfo("contentScriptType", false), + AttributeInfo("contentStyleType", false), + AttributeInfo("cursor", true), + AttributeInfo("cx", true), + AttributeInfo("cy", true), + AttributeInfo("d", true), + AttributeInfo("descent", true), + AttributeInfo("diffuseConstant", true), + AttributeInfo("direction", true), + AttributeInfo("display", true), + AttributeInfo("divisor", true), + AttributeInfo("dominant-baseline", true), + AttributeInfo("dur", true), + AttributeInfo("dx", true), + AttributeInfo("dy", true), + AttributeInfo("edgeMode", true), + AttributeInfo("elevation", true), + AttributeInfo("enable-background", true), + AttributeInfo("end", true), + AttributeInfo("exponent", true), + AttributeInfo("externalResourcesRequired", false), + AttributeInfo("feBlend", false), + AttributeInfo("feColorMatrix", false), + AttributeInfo("feComponentTransfer", false), + AttributeInfo("feComposite", false), + AttributeInfo("feConvolveMatrix", false), + AttributeInfo("feDiffuseLighting", false), + AttributeInfo("feDisplacementMap", false), + AttributeInfo("feFlood", false), + AttributeInfo("feGaussianBlur", false), + AttributeInfo("feImage", false), + AttributeInfo("feMerge", false), + AttributeInfo("feMorphology", false), + AttributeInfo("feOffset", false), + AttributeInfo("feSpecularLighting", false), + AttributeInfo("feTile", false), + AttributeInfo("fill", true), + AttributeInfo("fill-opacity", true), + AttributeInfo("fill-rule", true), + AttributeInfo("filter", true), + AttributeInfo("filterRes", true), + AttributeInfo("filterUnits", true), + AttributeInfo("flood-color", true), + AttributeInfo("flood-opacity", true), + AttributeInfo("font-family", true), + AttributeInfo("font-feature-settings", true), + AttributeInfo("font-size", true), + AttributeInfo("font-size-adjust", true), + AttributeInfo("font-stretch", true), + AttributeInfo("font-style", true), + AttributeInfo("font-variant", true), + AttributeInfo("font-variant-ligatures", true), + AttributeInfo("font-variant-position", true), + AttributeInfo("font-variant-caps", true), + AttributeInfo("font-variant-numeric", true), + AttributeInfo("font-variant-east-asian", true), + AttributeInfo("font-variant-alternates", true), + AttributeInfo("font-variation-settings", true), + AttributeInfo("font-weight", true), + AttributeInfo("format", false), + AttributeInfo("from", true), + AttributeInfo("fx", true), + AttributeInfo("fr", true), + AttributeInfo("fy", true), + AttributeInfo("g1", true), + AttributeInfo("g2", true), + AttributeInfo("glyph-name", true), + AttributeInfo("glyph-orientation-horizontal", true), + AttributeInfo("glyph-orientation-vertical", true), + AttributeInfo("glyphRef", false), + AttributeInfo("gradientTransform", true), + AttributeInfo("gradientUnits", true), + AttributeInfo("hanging", true), + AttributeInfo("hatchContentUnits", true), // SVG 2.0 + AttributeInfo("hatchTransform", true), // SVG 2.0 TODO renamed to transform + AttributeInfo("hatchUnits", true), // SVG 2.0 + AttributeInfo("height", true), + AttributeInfo("horiz-adv-x", true), + AttributeInfo("horiz-origin-x", true), + AttributeInfo("horiz-origin-y", true), + AttributeInfo("ideographic", true), + AttributeInfo("image-rendering", true), + AttributeInfo("in", true), + AttributeInfo("in2", true), + AttributeInfo("inline-size", true), + AttributeInfo("intercept", true), + AttributeInfo("isolation", true), + AttributeInfo("k", true), + AttributeInfo("k1", true), + AttributeInfo("k2", true), + AttributeInfo("k3", true), + AttributeInfo("k4", true), + AttributeInfo("kernelMatrix", true), + AttributeInfo("kernelUnitLength", true), + AttributeInfo("kerning", true), + AttributeInfo("keyPoints", false), + AttributeInfo("keySplines", true), + AttributeInfo("keyTimes", true), + AttributeInfo("lang", true), + AttributeInfo("lengthAdjust", true), + AttributeInfo("letter-spacing", true), + AttributeInfo("lighting-color", true), + AttributeInfo("limitingConeAngle", true), + AttributeInfo("local", true), + AttributeInfo("marker-end", true), + AttributeInfo("marker-mid", true), + AttributeInfo("marker-start", true), + AttributeInfo("markerHeight", true), + AttributeInfo("markerUnits", true), + AttributeInfo("markerWidth", true), + AttributeInfo("mask", true), + AttributeInfo("maskContentUnits", true), + AttributeInfo("maskUnits", true), + AttributeInfo("mathematical", true), + AttributeInfo("max", true), + AttributeInfo("media", false), + AttributeInfo("method", false), + AttributeInfo("min", true), + AttributeInfo("mix-blend-mode", true), + AttributeInfo("mode", true), + AttributeInfo("name", true), + AttributeInfo("numOctaves", true), + AttributeInfo("offset", true), + AttributeInfo("onabort", false), + AttributeInfo("onactivate", false), + AttributeInfo("onbegin", false), + AttributeInfo("onclick", false), + AttributeInfo("onend", false), + AttributeInfo("onerror", false), + AttributeInfo("onfocusin", false), + AttributeInfo("onfocusout", false), + AttributeInfo("onload", true), + AttributeInfo("onmousedown", false), + AttributeInfo("onmousemove", false), + AttributeInfo("onmouseout", false), + AttributeInfo("onmouseover", false), + AttributeInfo("onmouseup", false), + AttributeInfo("onrepeat", false), + AttributeInfo("onresize", false), + AttributeInfo("onscroll", false), + AttributeInfo("onunload", false), + AttributeInfo("onzoom", false), + AttributeInfo("opacity", true), + AttributeInfo("operator", true), + AttributeInfo("order", true), + AttributeInfo("orient", true), + AttributeInfo("orientation", true), + AttributeInfo("origin", false), + AttributeInfo("overflow", true), + AttributeInfo("overline-position", true), + AttributeInfo("overline-thickness", true), + AttributeInfo("paint-order", true), + AttributeInfo("panose-1", true), + AttributeInfo("path", true), + AttributeInfo("pathLength", false), + AttributeInfo("patternContentUnits", true), + AttributeInfo("patternTransform", true), + AttributeInfo("patternUnits", true), + AttributeInfo("pitch", true), // SVG 2.- + AttributeInfo("pointer-events", true), + AttributeInfo("points", true), + AttributeInfo("pointsAtX", true), + AttributeInfo("pointsAtY", true), + AttributeInfo("pointsAtZ", true), + AttributeInfo("preserveAlpha", true), + AttributeInfo("preserveAspectRatio", true), + AttributeInfo("primitiveUnits", true), + AttributeInfo("r", true), + AttributeInfo("radius", true), + AttributeInfo("refX", true), + AttributeInfo("refY", true), + AttributeInfo("rendering-intent", true), + AttributeInfo("repeatCount", true), + AttributeInfo("repeatDur", true), + AttributeInfo("requiredFeatures", true), + AttributeInfo("requiredExtensions", true), + AttributeInfo("restart", true), + AttributeInfo("result", true), + AttributeInfo("rotate", true), + AttributeInfo("rx", true), + AttributeInfo("ry", true), + AttributeInfo("scale", true), + AttributeInfo("seed", true), + AttributeInfo("shape-inside", true), + AttributeInfo("shape-margin", true), + AttributeInfo("shape-subtract", true), + AttributeInfo("shape-padding", true), + AttributeInfo("shape-rendering", true), + AttributeInfo("side", true), + AttributeInfo("slope", true), + AttributeInfo("solid-color", true), // SVG 2.0 + AttributeInfo("solid-opacity", true), // SVG 2.0 + AttributeInfo("spacing", false), + AttributeInfo("specularConstant", true), + AttributeInfo("specularExponent", true), + AttributeInfo("spreadMethod", true), + AttributeInfo("startOffset", true), + AttributeInfo("stdDeviation", true), + AttributeInfo("stemh", true), + AttributeInfo("stemv", true), + AttributeInfo("stitchTiles", true), + AttributeInfo("stop-color", true), + AttributeInfo("stop-opacity", true), + AttributeInfo("strikethrough-position", true), + AttributeInfo("strikethrough-thickness", true), + AttributeInfo("stroke", true), + AttributeInfo("stroke-dasharray", true), + AttributeInfo("stroke-dashoffset", true), + AttributeInfo("stroke-linecap", true), + AttributeInfo("stroke-linejoin", true), + AttributeInfo("stroke-miterlimit", true), + AttributeInfo("stroke-opacity", true), + AttributeInfo("stroke-width", true), + AttributeInfo("style", true), + AttributeInfo("surfaceScale", true), + AttributeInfo("systemLanguage", true), + AttributeInfo("tableValues", true), + AttributeInfo("target", true), + AttributeInfo("targetX", true), + AttributeInfo("targetY", true), + AttributeInfo("text-align", true), + AttributeInfo("text-anchor", true), + AttributeInfo("text-decoration", true), + AttributeInfo("text-decoration-color", true), + AttributeInfo("text-decoration-fill", true), + AttributeInfo("text-decoration-line", true), + AttributeInfo("text-decoration-stroke", true), + AttributeInfo("text-decoration-style", true), + AttributeInfo("text-indent", true), + AttributeInfo("text-orientation", true), + AttributeInfo("text-rendering", true), + AttributeInfo("text-transform", true), + AttributeInfo("textLength", true), + AttributeInfo("title", false), + AttributeInfo("to", true), + AttributeInfo("transform", true), + AttributeInfo("type", true), + AttributeInfo("u1", true), + AttributeInfo("u2", true), + AttributeInfo("underline-position", true), + AttributeInfo("underline-thickness", true), + AttributeInfo("unicode", true), + AttributeInfo("unicode-bidi", true), + AttributeInfo("unicode-range", true), + AttributeInfo("units-per-em", true), + AttributeInfo("v-alphabetic", true), + AttributeInfo("v-hanging", true), + AttributeInfo("v-ideographic", true), + AttributeInfo("v-mathematical", true), + AttributeInfo("values", true), + AttributeInfo("vector-effect", true), + AttributeInfo("version", true), + AttributeInfo("vert-adv-y", true), + AttributeInfo("vert-origin-x", true), + AttributeInfo("vert-origin-y", true), + AttributeInfo("viewBox", true), + AttributeInfo("viewTarget", false), + AttributeInfo("visibility", true), + AttributeInfo("white-space", true), + AttributeInfo("width", true), + AttributeInfo("widths", true), + AttributeInfo("word-spacing", true), + AttributeInfo("writing-mode", true), + AttributeInfo("x", true), + AttributeInfo("x-height", true), + AttributeInfo("x1", true), + AttributeInfo("x2", true), + AttributeInfo("xChannelSelector", true), + AttributeInfo("xlink:actuate", true), + AttributeInfo("xlink:arcrole", true), + AttributeInfo("xlink:href", true), + AttributeInfo("xlink:role", true), + AttributeInfo("xlink:show", true), + AttributeInfo("xlink:title", true), + AttributeInfo("xlink:type", true), + AttributeInfo("xml:base", false), + AttributeInfo("xml:lang", true), + AttributeInfo("xml:space", true), + AttributeInfo("xmlns", false), + AttributeInfo("xmlns:xlink", false), + AttributeInfo("y", true), + AttributeInfo("y1", true), + AttributeInfo("y2", true), + AttributeInfo("yChannelSelector", true), + AttributeInfo("z", true), + AttributeInfo("zoomAndPan", false), + + // Extra attributes. + AttributeInfo("id", true), + AttributeInfo("inkscape:bbox-nodes", true), + AttributeInfo("inkscape:bbox-paths", true), + AttributeInfo("inkscape:box3dsidetype", true), + AttributeInfo("inkscape:collect", true), + AttributeInfo("inkscape:color", true), + AttributeInfo("inkscape:connection-end", true), + AttributeInfo("inkscape:connection-end-point", true), + AttributeInfo("inkscape:connection-points", true), + AttributeInfo("inkscape:connection-start", true), + AttributeInfo("inkscape:connection-start-point", true), + AttributeInfo("inkscape:connector-avoid", true), + AttributeInfo("inkscape:connector-curvature", true), + AttributeInfo("inkscape:connector-spacing", true), + AttributeInfo("inkscape:connector-type", true), + AttributeInfo("inkscape:corner0", true), + AttributeInfo("inkscape:corner7", true), + AttributeInfo("inkscape:current-layer", true), + AttributeInfo("inkscape:cx", true), + AttributeInfo("inkscape:cy", true), + AttributeInfo("inkscape:document-units", true), + AttributeInfo("inkscape:dstBox", true), + AttributeInfo("inkscape:dstColumn", true), + AttributeInfo("inkscape:dstPath", true), + AttributeInfo("inkscape:dstShape", true), + AttributeInfo("inkscape:excludeShape", true), + AttributeInfo("inkscape:expanded", true), + AttributeInfo("inkscape:flatsided", true), + AttributeInfo("inkscape:groupmode", true), + AttributeInfo("inkscape:highlight-color", true), + AttributeInfo("inkscape:href", true), + AttributeInfo("inkscape:label", true), + AttributeInfo("inkscape:layoutOptions", true), + AttributeInfo("inkscape:lockguides", true), + AttributeInfo("inkscape:locked", true), + AttributeInfo("inkscape:object-nodes", true), + AttributeInfo("inkscape:object-paths", true), + AttributeInfo("inkscape:original", true), + AttributeInfo("inkscape:original-d", true), + AttributeInfo("inkscape:pagecheckerboard", true), + AttributeInfo("inkscape:pageopacity", true), + AttributeInfo("inkscape:pageshadow", true), + AttributeInfo("inkscape:path-effect", true), + AttributeInfo("inkscape:persp3d", true), + AttributeInfo("inkscape:persp3d-origin", true), + AttributeInfo("inkscape:perspectiveID", true), + AttributeInfo("inkscape:radius", true), + AttributeInfo("inkscape:randomized", true), + AttributeInfo("inkscape:rounded", true), + AttributeInfo("inkscape:snap-bbox", true), + AttributeInfo("inkscape:snap-bbox-edge-midpoints", true), + AttributeInfo("inkscape:snap-bbox-midpoints", true), + AttributeInfo("inkscape:snap-center", true), + AttributeInfo("inkscape:snap-global", true), + AttributeInfo("inkscape:snap-grids", true), + AttributeInfo("inkscape:snap-intersection-paths", true), + AttributeInfo("inkscape:snap-midpoints", true), + AttributeInfo("inkscape:snap-nodes", true), + AttributeInfo("inkscape:snap-object-midpoints", true), + AttributeInfo("inkscape:snap-others", true), + AttributeInfo("inkscape:snap-from-guide", true), + AttributeInfo("inkscape:snap-page", true), + AttributeInfo("inkscape:snap-path-clip", true), + AttributeInfo("inkscape:snap-path-mask", true), + AttributeInfo("inkscape:snap-perpendicular", true), + AttributeInfo("inkscape:snap-smooth-nodes", true), + AttributeInfo("inkscape:snap-tangential", true), + AttributeInfo("inkscape:snap-text-baseline", true), + AttributeInfo("inkscape:snap-to-guides", true), + AttributeInfo("inkscape:spray-origin", true), + AttributeInfo("inkscape:srcNoMarkup", true), + AttributeInfo("inkscape:srcPango", true), + AttributeInfo("inkscape:transform-center-x", true), + AttributeInfo("inkscape:transform-center-y", true), + AttributeInfo("inkscape:version", true), + AttributeInfo("inkscape:vp_x", true), + AttributeInfo("inkscape:vp_y", true), + AttributeInfo("inkscape:vp_z", true), + AttributeInfo("inkscape:window-height", true), + AttributeInfo("inkscape:window-maximized", true), + AttributeInfo("inkscape:window-width", true), + AttributeInfo("inkscape:window-x", true), + AttributeInfo("inkscape:window-y", true), + AttributeInfo("inkscape:zoom", true), + AttributeInfo("inkscape:svg-dpi", true), + AttributeInfo("osb:paint", true), + AttributeInfo("sodipodi:arc-type", true), + AttributeInfo("sodipodi:arg1", true), + AttributeInfo("sodipodi:arg2", true), + AttributeInfo("sodipodi:argument", true), + AttributeInfo("sodipodi:cx", true), + AttributeInfo("sodipodi:cy", true), + AttributeInfo("sodipodi:docname", true), + AttributeInfo("sodipodi:end", true), + AttributeInfo("sodipodi:expansion", true), + AttributeInfo("sodipodi:insensitive", true), + AttributeInfo("sodipodi:linespacing", true), + AttributeInfo("sodipodi:open", true), + AttributeInfo("sodipodi:original", true), + AttributeInfo("sodipodi:r1", true), + AttributeInfo("sodipodi:r2", true), + AttributeInfo("sodipodi:radius", true), + AttributeInfo("sodipodi:revolution", true), + AttributeInfo("sodipodi:role", true), + AttributeInfo("sodipodi:rx", true), + AttributeInfo("sodipodi:ry", true), + AttributeInfo("sodipodi:sides", true), + AttributeInfo("sodipodi:start", true), + AttributeInfo("sodipodi:t0", true), + AttributeInfo("sodipodi:type", true), + AttributeInfo("sodipodi:version", false), + + // SPMeshPatch + AttributeInfo("tensor", true), + + // SPNamedView + AttributeInfo("fit-margin-top", true), + AttributeInfo("fit-margin-left", true), + AttributeInfo("fit-margin-right", true), + AttributeInfo("fit-margin-bottom", true), + AttributeInfo("units", true), + AttributeInfo("viewonly", true), + AttributeInfo("showgrid", true), +// AttributeInfo("gridtype", true), + AttributeInfo("showguides", true), + AttributeInfo("gridtolerance", true), + AttributeInfo("guidetolerance", true), + AttributeInfo("objecttolerance", true), +/* AttributeInfo("gridoriginx", true), + AttributeInfo("gridoriginy", true), + AttributeInfo("gridspacingx", true), + AttributeInfo("gridspacingy", true), + AttributeInfo("gridanglex", true), + AttributeInfo("gridanglez", true), + AttributeInfo("gridcolor", true), + AttributeInfo("gridopacity", true), + AttributeInfo("gridempcolor", true), + AttributeInfo("gridempopacity", true), + AttributeInfo("gridempspacing", true), */ + AttributeInfo("guidecolor", true), + AttributeInfo("guideopacity", true), + AttributeInfo("guidehicolor", true), + AttributeInfo("guidehiopacity", true), + AttributeInfo("showborder", true), + AttributeInfo("inkscape:showpageshadow", true), + AttributeInfo("borderlayer", true), + AttributeInfo("bordercolor", true), + AttributeInfo("borderopacity", true), + AttributeInfo("pagecolor", true), + + // SPGuide + AttributeInfo("position", true) + }; + + size_t count = sizeof(all_attrs) / sizeof(all_attrs[0]); + std::vector<AttributeInfo> vect(all_attrs, all_attrs + count); + EXPECT_GT(vect.size(), size_t(100)); // should be more than + return vect; +} + +/** + * Returns a vector with counts for all IDs up to the highest known value. + * + * The index is the ID, and the value is the number of times that ID is seen. + */ +std::vector<size_t> getIdIds() +{ + std::vector<size_t> ids; + std::vector<AttributeInfo> all_attrs = getKnownAttrs(); + ids.reserve(all_attrs.size()); // minimize memory thrashing + for (auto & all_attr : all_attrs) { + auto id = sp_attribute_lookup(all_attr.attr.c_str()); + if (id >= ids.size()) { + ids.resize(id + 1); + } + ids[id]++; + } + + return ids; +} + +// Ensure 'supported' value for each known attribute is correct. +TEST(AttributesTest, SupportedKnown) +{ + std::vector<AttributeInfo> all_attrs = getKnownAttrs(); + for (AttrItr it(all_attrs.begin()); it != all_attrs.end(); ++it) { + auto id = sp_attribute_lookup(it->attr.c_str()); + EXPECT_EQ(it->supported, id != 0u) << "Matching for attribute '" << it->attr << "'"; + } +} + +// Ensure names of known attributes are preserved when converted to id and back. +TEST(AttributesTest, NameRoundTrip) +{ + std::vector<AttributeInfo> all_attrs = getKnownAttrs(); + for (AttrItr it(all_attrs.begin()); it != all_attrs.end(); ++it) { + if (it->supported) { + auto id = sp_attribute_lookup(it->attr.c_str()); + char const *redoneName = sp_attribute_name(id); + EXPECT_TRUE(redoneName != NULL) << "For attribute '" << it->attr << "'"; + if (redoneName) { + EXPECT_EQ(it->attr, redoneName); + } + } + } +} + +/* Test for any attributes that this test program doesn't know about. + * + * If any are found, then: + * + * If it is in the `inkscape:' namespace then simply add it to all_attrs with + * `true' as the second field (`supported'). + * + * If it is in the `sodipodi:' namespace then check the spelling against sodipodi + * sources. If you don't have sodipodi sources, then don't add it: leave to someone + * else. + * + * Otherwise, it's probably a bug: ~all SVG 1.1 attributes should already be + * in the all_attrs table. However, the comment above all_attrs does mention + * some things missing from attindex.html, so there may be more. Check the SVG + * spec. Another possibility is that the attribute is new in SVG 1.2. In this case, + * check the spelling against the [draft] SVG 1.2 spec before adding to all_attrs. + * (If you can't be bothered checking the spec, then don't update all_attrs.) + * + * If the attribute isn't in either SVG 1.1 or 1.2 then it's probably a mistake + * for it not to be in the inkscape namespace. (Not sure about attributes used only + * on elements in the inkscape namespace though.) + * + * In any case, make sure that the attribute's source is documented accordingly. + */ +TEST(AttributesTest, ValuesAreKnown) +{ + std::vector<size_t> ids = getIdIds(); + for (size_t i = FIRST_VALID_ID; i < ids.size(); ++i) { + if (!ids[i]) { + char const *name = sp_attribute_name((SPAttributeEnum)i); + EXPECT_TRUE(ids[i] > 0) << "Attribute string with enum " << i << " {" << name << "} not handled"; + } + } +} + +// Ensure two different names aren't mapped to the same enum value. +TEST(AttributesTest, ValuesUnique) +{ + std::vector<size_t> ids = getIdIds(); + for (size_t i = FIRST_VALID_ID; i < ids.size(); ++i) { + EXPECT_LE(ids[i], size_t(1)) << "Attribute enum " << i << " used for multiple strings" + << " including {" << sp_attribute_name((SPAttributeEnum)i) << "}"; + } +} + +} // namespace + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/testfiles/src/color-profile-test.cpp b/testfiles/src/color-profile-test.cpp new file mode 100644 index 0000000..4804763 --- /dev/null +++ b/testfiles/src/color-profile-test.cpp @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Unit tests for color profile. + * + * Author: + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtest/gtest.h" + +#include "attributes.h" +#include "cms-system.h" +#include "object/color-profile.h" +#include "doc-per-case-test.h" + +namespace { + +/** + * Test fixture to inherit a shared doc and create a color profile instance per test. + */ +class ProfTest : public DocPerCaseTest +{ +public: + ProfTest() : + DocPerCaseTest(), + _prof(0) + { + } + +protected: + void SetUp() override + { + DocPerCaseTest::SetUp(); + _prof = new Inkscape::ColorProfile(); + ASSERT_TRUE( _prof != NULL ); + _prof->document = _doc; + } + + void TearDown() override + { + if (_prof) { + delete _prof; + _prof = NULL; + } + DocPerCaseTest::TearDown(); + } + + Inkscape::ColorProfile *_prof; +}; + +typedef ProfTest ColorProfileTest; + +TEST_F(ColorProfileTest, SetRenderingIntent) +{ + struct { + gchar const *attr; + guint intVal; + } + const cases[] = { + {"auto", (guint)Inkscape::RENDERING_INTENT_AUTO}, + {"perceptual", (guint)Inkscape::RENDERING_INTENT_PERCEPTUAL}, + {"relative-colorimetric", (guint)Inkscape::RENDERING_INTENT_RELATIVE_COLORIMETRIC}, + {"saturation", (guint)Inkscape::RENDERING_INTENT_SATURATION}, + {"absolute-colorimetric", (guint)Inkscape::RENDERING_INTENT_ABSOLUTE_COLORIMETRIC}, + {"something-else", (guint)Inkscape::RENDERING_INTENT_UNKNOWN}, + {"auto2", (guint)Inkscape::RENDERING_INTENT_UNKNOWN}, + }; + + for (auto i : cases) { + _prof->setKeyValue( SP_ATTR_RENDERING_INTENT, i.attr); + ASSERT_EQ( (guint)i.intVal, _prof->rendering_intent ) << i.attr; + } +} + +TEST_F(ColorProfileTest, SetLocal) +{ + gchar const* cases[] = { + "local", + "something", + }; + + for (auto & i : cases) { + _prof->setKeyValue( SP_ATTR_LOCAL, i); + ASSERT_TRUE( _prof->local != NULL ); + if ( _prof->local ) { + ASSERT_EQ( std::string(i), _prof->local ); + } + } + _prof->setKeyValue( SP_ATTR_LOCAL, NULL); + ASSERT_EQ( (gchar*)0, _prof->local ); +} + +TEST_F(ColorProfileTest, SetName) +{ + gchar const* cases[] = { + "name", + "something", + }; + + for (auto & i : cases) { + _prof->setKeyValue( SP_ATTR_NAME, i); + ASSERT_TRUE( _prof->name != NULL ); + if ( _prof->name ) { + ASSERT_EQ( std::string(i), _prof->name ); + } + } + _prof->setKeyValue( SP_ATTR_NAME, NULL ); + ASSERT_EQ( (gchar*)0, _prof->name ); +} + + +} // namespace + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/testfiles/src/curve-test.cpp b/testfiles/src/curve-test.cpp new file mode 100644 index 0000000..8c94b77 --- /dev/null +++ b/testfiles/src/curve-test.cpp @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Curve test + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include <gtest/gtest.h> + +#include "display/curve.h" +#include <2geom/curves.h> +#include <2geom/path.h> +#include <2geom/pathvector.h> + +class CurveTest : public ::testing::Test { + public: + Geom::Path path1; + Geom::Path path2; + Geom::Path path3; + Geom::Path path4; + + protected: + CurveTest() + : path4(Geom::Point(3, 5)) // Just a moveto + { + // Closed path + path1.append(Geom::LineSegment(Geom::Point(0, 0), Geom::Point(1, 0))); + path1.append(Geom::LineSegment(Geom::Point(1, 0), Geom::Point(1, 1))); + path1.close(); + // Closed path (ClosingSegment is zero length) + path2.append(Geom::LineSegment(Geom::Point(2, 0), Geom::Point(3, 0))); + path2.append(Geom::CubicBezier(Geom::Point(3, 0), Geom::Point(2, 1), Geom::Point(1, 1), Geom::Point(2, 0))); + path2.close(); + // Open path + path3.setStitching(true); + path3.append(Geom::EllipticalArc(Geom::Point(4, 0), 1, 2, M_PI, false, false, Geom::Point(5, 1))); + path3.append(Geom::LineSegment(Geom::Point(5, 1), Geom::Point(5, 2))); + path3.append(Geom::LineSegment(Geom::Point(6, 4), Geom::Point(2, 4))); + } +}; + +TEST_F(CurveTest, testGetSegmentCount) +{ + { // Zero segments + Geom::PathVector pv; + SPCurve curve(pv); + ASSERT_EQ(curve.get_segment_count(), 0u); + } + { // Zero segments + Geom::PathVector pv; + pv.push_back(Geom::Path()); + SPCurve curve(pv); + ASSERT_EQ(curve.get_segment_count(), 0u); + } + { // Individual paths + Geom::PathVector pv((Geom::Path())); + pv[0] = path1; + ASSERT_EQ(SPCurve(pv).get_segment_count(), 3u); + pv[0] = path2; + ASSERT_EQ(SPCurve(pv).get_segment_count(), 2u); + pv[0] = path3; + ASSERT_EQ(SPCurve(pv).get_segment_count(), 4u); + pv[0] = path4; + ASSERT_EQ(SPCurve(pv).get_segment_count(), 0u); + pv[0].close(); + ASSERT_EQ(SPCurve(pv).get_segment_count(), 0u); + } + { // Combination + Geom::PathVector pv; + pv.push_back(path1); + pv.push_back(path2); + pv.push_back(path3); + pv.push_back(path4); + SPCurve curve(pv); + ASSERT_EQ(curve.get_segment_count(), 9u); + } +} + +TEST_F(CurveTest, testNodesInPathForZeroSegments) +{ + { // Zero segments + Geom::PathVector pv; + SPCurve curve(pv); + ASSERT_EQ(curve.nodes_in_path(), 0u); + } + { // Zero segments + Geom::PathVector pv; + pv.push_back(Geom::Path()); + SPCurve curve(pv); + ASSERT_EQ(curve.nodes_in_path(), 1u); + } +} + +TEST_F(CurveTest, testNodesInPathForIndividualPaths) +{ + Geom::PathVector pv((Geom::Path())); + pv[0] = path1; + ASSERT_EQ(SPCurve(pv).nodes_in_path(), 3u); + pv[0] = path2; + ASSERT_EQ(SPCurve(pv).nodes_in_path(), 2u); // zero length closing segments do not increase the nodecount. + pv[0] = path3; + ASSERT_EQ(SPCurve(pv).nodes_in_path(), 5u); + pv[0] = path4; + ASSERT_EQ(SPCurve(pv).nodes_in_path(), 1u); +} + +TEST_F(CurveTest, testNodesInPathForNakedMoveToClosedPath) +{ + Geom::PathVector pv((Geom::Path())); + pv[0] = path4; // just a MoveTo + pv[0].close(); + ASSERT_EQ(SPCurve(pv).nodes_in_path(), 1u); +} + +/* +TEST_F(CurveTest, testNodesInPathForPathsCombination) +{ + Geom::PathVector pv; + pv.push_back(path1); + pv.push_back(path2); + pv.push_back(path3); + pv.push_back(path4); + SPCurve curve(pv); + ASSERT_EQ(curve.nodes_in_path(), 12u); +} +*/ + +TEST_F(CurveTest, testIsEmpty) +{ + ASSERT_TRUE(SPCurve(Geom::PathVector()).is_empty()); + ASSERT_FALSE(SPCurve(path1).is_empty()); + ASSERT_FALSE(SPCurve(path2).is_empty()); + ASSERT_FALSE(SPCurve(path3).is_empty()); + ASSERT_FALSE(SPCurve(path4).is_empty()); +} + +TEST_F(CurveTest, testIsClosed) +{ + ASSERT_FALSE(SPCurve(Geom::PathVector()).is_closed()); + Geom::PathVector pv((Geom::Path())); + ASSERT_FALSE(SPCurve(pv).is_closed()); + pv[0].close(); + ASSERT_TRUE(SPCurve(pv).is_closed()); + ASSERT_TRUE(SPCurve(path1).is_closed()); + ASSERT_TRUE(SPCurve(path2).is_closed()); + ASSERT_FALSE(SPCurve(path3).is_closed()); + ASSERT_FALSE(SPCurve(path4).is_closed()); +} + +/* +TEST_F(CurveTest, testLastFirstSegment) +{ + Geom::PathVector pv(path4); + ASSERT_EQ(SPCurve(pv).first_segment(), (void *)0); + ASSERT_EQ(SPCurve(pv).last_segment(), (void *)0); + pv[0].close(); + ASSERT_NE(SPCurve(pv).first_segment(), (void *)0); + ASSERT_NE(SPCurve(pv).last_segment(), (void *)0); +} +*/ + +TEST_F(CurveTest, testLastFirstPath) +{ + Geom::PathVector pv; + ASSERT_EQ(SPCurve(pv).first_path(), (void *)0); + ASSERT_EQ(SPCurve(pv).last_path(), (void *)0); + pv.push_back(path1); + ASSERT_EQ(*SPCurve(pv).first_path(), pv[0]); + ASSERT_EQ(*SPCurve(pv).last_path(), pv[0]); + pv.push_back(path2); + ASSERT_EQ(*SPCurve(pv).first_path(), pv[0]); + ASSERT_EQ(*SPCurve(pv).last_path(), pv[1]); + pv.push_back(path3); + ASSERT_EQ(*SPCurve(pv).first_path(), pv[0]); + ASSERT_EQ(*SPCurve(pv).last_path(), pv[2]); + pv.push_back(path4); + ASSERT_EQ(*SPCurve(pv).first_path(), pv[0]); + ASSERT_EQ(*SPCurve(pv).last_path(), pv[3]); +} + +TEST_F(CurveTest, testFirstPoint) +{ + ASSERT_EQ(*(SPCurve(path1).first_point()), Geom::Point(0, 0)); + ASSERT_EQ(*(SPCurve(path2).first_point()), Geom::Point(2, 0)); + ASSERT_EQ(*(SPCurve(path3).first_point()), Geom::Point(4, 0)); + ASSERT_EQ(*(SPCurve(path4).first_point()), Geom::Point(3, 5)); + Geom::PathVector pv; + ASSERT_FALSE(SPCurve(pv).first_point()); + pv.push_back(path1); + pv.push_back(path2); + pv.push_back(path3); + ASSERT_EQ(*(SPCurve(pv).first_point()), Geom::Point(0, 0)); + pv.insert(pv.begin(), path4); + ASSERT_EQ(*(SPCurve(pv).first_point()), Geom::Point(3, 5)); +} + +/* +TEST_F(CurveTest, testLastPoint) +{ + ASSERT_EQ(*(SPCurve(path1).last_point()), Geom::Point(0, 0)); + ASSERT_EQ(*(SPCurve(path2).last_point()), Geom::Point(2, 0)); + ASSERT_EQ(*(SPCurve(path3).last_point()), Geom::Point(8, 4)); + ASSERT_EQ(*(SPCurve(path4).last_point()), Geom::Point(3, 5)); + Geom::PathVector pv; + ASSERT_FALSE(SPCurve(pv).last_point()); + pv.push_back(path1); + pv.push_back(path2); + pv.push_back(path3); + ASSERT_EQ(*(SPCurve(pv).last_point()), Geom::Point(8, 4)); + pv.push_back(path4); + ASSERT_EQ(*(SPCurve(pv).last_point()), Geom::Point(3, 5)); +} +*/ + +TEST_F(CurveTest, testSecondPoint) +{ + ASSERT_EQ(*(SPCurve(path1).second_point()), Geom::Point(1, 0)); + ASSERT_EQ(*(SPCurve(path2).second_point()), Geom::Point(3, 0)); + ASSERT_EQ(*(SPCurve(path3).second_point()), Geom::Point(5, 1)); + ASSERT_EQ(*(SPCurve(path4).second_point()), Geom::Point(3, 5)); + Geom::PathVector pv; + pv.push_back(path1); + pv.push_back(path2); + pv.push_back(path3); + ASSERT_EQ(*(SPCurve(pv).second_point()), Geom::Point(1, 0)); + pv.insert(pv.begin(), path4); + ASSERT_EQ(*SPCurve(pv).second_point(), Geom::Point(0, 0)); +} + +/* +TEST_F(CurveTest, testPenultimatePoint) +{ + ASSERT_EQ(*(SPCurve(Geom::PathVector(path1)).penultimate_point()), Geom::Point(1, 1)); + ASSERT_EQ(*(SPCurve(Geom::PathVector(path2)).penultimate_point()), Geom::Point(3, 0)); + ASSERT_EQ(*(SPCurve(Geom::PathVector(path3)).penultimate_point()), Geom::Point(6, 4)); + ASSERT_EQ(*(SPCurve(Geom::PathVector(path4)).penultimate_point()), Geom::Point(3, 5)); + Geom::PathVector pv; + pv.push_back(path1); + pv.push_back(path2); + pv.push_back(path3); + ASSERT_EQ(*(SPCurve(pv).penultimate_point()), Geom::Point(6, 4)); + pv.push_back(path4); + ASSERT_EQ(*(SPCurve(pv).penultimate_point()), Geom::Point(8, 4)); +} +*/ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/cxxtests-to-migrate/marker-test.h b/testfiles/src/cxxtests-to-migrate/marker-test.h new file mode 100644 index 0000000..1a77aff --- /dev/null +++ b/testfiles/src/cxxtests-to-migrate/marker-test.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * @brief Unit tests for SVG marker handling + *//* + * Authors: + * see git history + * Johan Engelen <goejendaagh@zonnet.nl> + * + * Copyright (C) 2016 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <cxxtest/TestSuite.h> + +#include "sp-marker-loc.h" + +class MarkerTest : public CxxTest::TestSuite +{ +public: + + void testMarkerLoc() + { + // code depends on these *exact* values, so check them here. + TS_ASSERT_EQUALS(SP_MARKER_LOC, 0); + TS_ASSERT_EQUALS(SP_MARKER_LOC_START, 1); + TS_ASSERT_EQUALS(SP_MARKER_LOC_MID, 2); + TS_ASSERT_EQUALS(SP_MARKER_LOC_END, 3); + TS_ASSERT_EQUALS(SP_MARKER_LOC_QTY, 4); + } + +}; + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/cxxtests-to-migrate/mod360-test.h b/testfiles/src/cxxtests-to-migrate/mod360-test.h new file mode 100644 index 0000000..12ee994 --- /dev/null +++ b/testfiles/src/cxxtests-to-migrate/mod360-test.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: see git history + * + * Copyright (C) 2016 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifndef SEEN_MOD_360_TEST_H +#define SEEN_MOD_360_TEST_H + +#include <cxxtest/TestSuite.h> +#include <2geom/math-utils.h> +#include "mod360.h" + + +class Mod360Test : public CxxTest::TestSuite +{ +public: + static double inf() { return INFINITY; } + static double nan() { return ((double)INFINITY) - ((double)INFINITY); } + + void testMod360() + { + double cases[][2] = { + {0, 0}, + {10, 10}, + {360, 0}, + {361, 1}, + {-1, 359}, + {-359, 1}, + {-360, -0}, + {-361, 359}, + {inf(), 0}, + {-inf(), 0}, + {nan(), 0}, + {720, 0}, + {-721, 359}, + {-1000, 80} + }; + + for ( unsigned i = 0; i < G_N_ELEMENTS(cases); i++ ) { + double result = mod360( cases[i][0] ); + TS_ASSERT_EQUALS( cases[i][1], result ); + } + } + +}; + + +#endif // SEEN_MOD_360_TEST_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : + diff --git a/testfiles/src/cxxtests-to-migrate/preferences-test.h b/testfiles/src/cxxtests-to-migrate/preferences-test.h new file mode 100644 index 0000000..0dc04b8 --- /dev/null +++ b/testfiles/src/cxxtests-to-migrate/preferences-test.h @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * @brief Unit tests for the Preferences object + *//* + * Authors: + * see git history + * Krzysztof KosiÅ„ski <tweenk.pl@gmail.com> + * + * Copyright (C) 2016 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <cxxtest/TestSuite.h> +#include "preferences.h" + +#include <glibmm/ustring.h> + +// test observer +class TestObserver : public Inkscape::Preferences::Observer { +public: + TestObserver(Glib::ustring const &path) : + Inkscape::Preferences::Observer(path), + value(0) {} + + virtual void notify(Inkscape::Preferences::Entry const &val) + { + value = val.getInt(); + } + int value; +}; + +class PreferencesTest : public CxxTest::TestSuite { +public: + void setUp() { + prefs = Inkscape::Preferences::get(); + } + void tearDown() { + prefs = NULL; + Inkscape::Preferences::unload(); + } + + void testStartingState() + { + TS_ASSERT_DIFFERS(prefs, static_cast<void*>(0)); + TS_ASSERT_EQUALS(prefs->isWritable(), true); + } + + void testOverwrite() + { + prefs->setInt("/test/intvalue", 123); + prefs->setInt("/test/intvalue", 321); + TS_ASSERT_EQUALS(prefs->getInt("/test/intvalue"), 321); + } + + void testDefaultReturn() + { + TS_ASSERT_EQUALS(prefs->getInt("/this/path/does/not/exist", 123), 123); + } + + void testLimitedReturn() + { + prefs->setInt("/test/intvalue", 1000); + + // simple case + TS_ASSERT_EQUALS(prefs->getIntLimited("/test/intvalue", 123, 0, 500), 123); + // the below may seem quirky but this behaviour is intended + TS_ASSERT_EQUALS(prefs->getIntLimited("/test/intvalue", 123, 1001, 5000), 123); + // corner cases + TS_ASSERT_EQUALS(prefs->getIntLimited("/test/intvalue", 123, 0, 1000), 1000); + TS_ASSERT_EQUALS(prefs->getIntLimited("/test/intvalue", 123, 1000, 5000), 1000); + } + + void testKeyObserverNotification() + { + Glib::ustring const path = "/some/random/path"; + TestObserver obs("/some/random"); + obs.value = 1; + prefs->setInt(path, 5); + TS_ASSERT_EQUALS(obs.value, 1); // no notifications sent before adding + + prefs->addObserver(obs); + prefs->setInt(path, 10); + TS_ASSERT_EQUALS(obs.value, 10); + prefs->setInt("/some/other/random/path", 10); + TS_ASSERT_EQUALS(obs.value, 10); // value should not change + + prefs->removeObserver(obs); + prefs->setInt(path, 15); + TS_ASSERT_EQUALS(obs.value, 10); // no notifications sent after removal + } + + void testEntryObserverNotification() + { + Glib::ustring const path = "/some/random/path"; + TestObserver obs(path); + obs.value = 1; + prefs->setInt(path, 5); + TS_ASSERT_EQUALS(obs.value, 1); // no notifications sent before adding + + prefs->addObserver(obs); + prefs->setInt(path, 10); + TS_ASSERT_EQUALS(obs.value, 10); + + // test that filtering works properly + prefs->setInt("/some/random/value", 1234); + TS_ASSERT_EQUALS(obs.value, 10); + prefs->setInt("/some/randomvalue", 1234); + TS_ASSERT_EQUALS(obs.value, 10); + prefs->setInt("/some/random/path2", 1234); + TS_ASSERT_EQUALS(obs.value, 10); + + prefs->removeObserver(obs); + prefs->setInt(path, 15); + TS_ASSERT_EQUALS(obs.value, 10); // no notifications sent after removal + } + + void testPreferencesEntryMethods() + { + prefs->setInt("/test/prefentry", 100); + Inkscape::Preferences::Entry val = prefs->getEntry("/test/prefentry"); + TS_ASSERT(val.isValid()); + TS_ASSERT_EQUALS(val.getPath(), "/test/prefentry"); + TS_ASSERT_EQUALS(val.getEntryName(), "prefentry"); + TS_ASSERT_EQUALS(val.getInt(), 100); + } +private: + Inkscape::Preferences *prefs; +}; + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/cxxtests-to-migrate/sp-style-elem-test.h b/testfiles/src/cxxtests-to-migrate/sp-style-elem-test.h new file mode 100644 index 0000000..271f319 --- /dev/null +++ b/testfiles/src/cxxtests-to-migrate/sp-style-elem-test.h @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: see git history + * + * Copyright (C) 2016 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#ifndef SEEN_SP_STYLE_ELEM_TEST_H +#define SEEN_SP_STYLE_ELEM_TEST_H + +#include <cxxtest/TestSuite.h> + +#include "test-helpers.h" + +#include "sp-style-elem.h" +#include "xml/repr.h" + +class SPStyleElemTest : public CxxTest::TestSuite +{ +public: + SPDocument* _doc; + + SPStyleElemTest() : + _doc(0) + { + } + + virtual ~SPStyleElemTest() + { + if ( _doc ) + { + _doc->doUnref(); + } + } + + static void createSuiteSubclass( SPStyleElemTest *& dst ) + { + SPStyleElem *style_elem = new SPStyleElem(); + + if ( style_elem ) { + TS_ASSERT(!style_elem->is_css); + TS_ASSERT(style_elem->media.print); + TS_ASSERT(style_elem->media.screen); + delete style_elem; + + dst = new SPStyleElemTest(); + } + } + + static SPStyleElemTest *createSuite() + { + return Inkscape::createSuiteAndDocument<SPStyleElemTest>( createSuiteSubclass ); + } + + static void destroySuite( SPStyleElemTest *suite ) { delete suite; } + +// ------------------------------------------------------------------------- +// ------------------------------------------------------------------------- + + + void testSetType() + { + SPStyleElem *style_elem = new SPStyleElem(); + SP_OBJECT(style_elem)->document = _doc; + + SP_OBJECT(style_elem)->setKeyValue( SP_ATTR_TYPE, "something unrecognized"); + TS_ASSERT( !style_elem->is_css ); + + SP_OBJECT(style_elem)->setKeyValue( SP_ATTR_TYPE, "text/css"); + TS_ASSERT( style_elem->is_css ); + + SP_OBJECT(style_elem)->setKeyValue( SP_ATTR_TYPE, "atext/css"); + TS_ASSERT( !style_elem->is_css ); + + SP_OBJECT(style_elem)->setKeyValue( SP_ATTR_TYPE, "text/cssx"); + TS_ASSERT( !style_elem->is_css ); + + delete style_elem; + } + + void testWrite() + { + TS_ASSERT( _doc ); + TS_ASSERT( _doc->getReprDoc() ); + if ( !_doc->getReprDoc() ) { + return; // evil early return + } + + SPStyleElem *style_elem = new SPStyleElem(); + SP_OBJECT(style_elem)->document = _doc; + + SP_OBJECT(style_elem)->setKeyValue( SP_ATTR_TYPE, "text/css"); + Inkscape::XML::Node *repr = _doc->getReprDoc()->createElement("svg:style"); + SP_OBJECT(style_elem)->updateRepr(_doc->getReprDoc(), repr, SP_OBJECT_WRITE_ALL); + { + gchar const *typ = repr->attribute("type"); + TS_ASSERT( typ != NULL ); + if ( typ ) + { + TS_ASSERT_EQUALS( std::string(typ), std::string("text/css") ); + } + } + + delete style_elem; + } + + void testBuild() + { + TS_ASSERT( _doc ); + TS_ASSERT( _doc->getReprDoc() ); + if ( !_doc->getReprDoc() ) { + return; // evil early return + } + + SPStyleElem *style_elem = new SPStyleElem(); + Inkscape::XML::Node *const repr = _doc->getReprDoc()->createElement("svg:style"); + repr->setAttribute("type", "text/css"); + style_elem->invoke_build( _doc, repr, false); + TS_ASSERT( style_elem->is_css ); + TS_ASSERT( style_elem->media.print ); + TS_ASSERT( style_elem->media.screen ); + + /* Some checks relevant to the read_content test below. */ + { + g_assert(_doc->style_cascade); + CRStyleSheet const *const stylesheet = cr_cascade_get_sheet(_doc->style_cascade, ORIGIN_AUTHOR); + g_assert(stylesheet); + g_assert(stylesheet->statements == NULL); + } + + delete style_elem; + Inkscape::GC::release(repr); + } + + void testReadContent() + { + TS_ASSERT( _doc ); + TS_ASSERT( _doc->getReprDoc() ); + if ( !_doc->getReprDoc() ) { + return; // evil early return + } + + SPStyleElem *style_elem = new SPStyleElem(); + Inkscape::XML::Node *const repr = _doc->getReprDoc()->createElement("svg:style"); + repr->setAttribute("type", "text/css"); + Inkscape::XML::Node *const content_repr = _doc->getReprDoc()->createTextNode(".myclass { }"); + repr->addChild(content_repr, NULL); + style_elem->invoke_build(_doc, repr, false); + TS_ASSERT( style_elem->is_css ); + TS_ASSERT( _doc->style_cascade ); + CRStyleSheet const *const stylesheet = cr_cascade_get_sheet(_doc->style_cascade, ORIGIN_AUTHOR); + TS_ASSERT(stylesheet != NULL); + TS_ASSERT(stylesheet->statements != NULL); + + delete style_elem; + Inkscape::GC::release(repr); + } + +}; + + +#endif // SEEN_SP_STYLE_ELEM_TEST_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/cxxtests-to-migrate/test-helpers.h b/testfiles/src/cxxtests-to-migrate/test-helpers.h new file mode 100644 index 0000000..96bf5b4 --- /dev/null +++ b/testfiles/src/cxxtests-to-migrate/test-helpers.h @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: see git history + * + * Copyright (C) 2016 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#ifndef SEEN_TEST_HELPERS_H +#define SEEN_TEST_HELPERS_H + + +#include <cxxtest/TestSuite.h> + +#include "document.h" +#include "inkscape.h" + + +// Dummy functions to keep linker happy +#if !defined(DUMMY_MAIN_TEST_CALLS_SEEN) +#define DUMMY_MAIN_TEST_CALLS_SEEN +int sp_main_gui (int, char const**) { return 0; } +int sp_main_console (int, char const**) { return 0; } +#endif // DUMMY_MAIN_TEST_CALLS_SEEN + +namespace Inkscape +{ + +template <class T> +T* createSuiteAndDocument( void (*fun)(T*&) ) +{ + T* suite = 0; + +#if !GLIB_CHECK_VERSION(2,36,0) + g_type_init(); +#endif + + Inkscape::GC::init(); + if ( !Inkscape::Application::exists() ) + { + // Create the global inkscape object. + Inkscape::Application::create(false); + } + + SPDocument* tmp = SPDocument::createNewDoc( NULL, TRUE, true ); + if ( tmp ) { + fun( suite ); + if ( suite ) + { + suite->_doc = tmp; + } + else + { + tmp->doUnref(); + } + } + + return suite; +} + +} // namespace Inkscape + +#endif // SEEN_TEST_HELPERS_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/cxxtests-to-migrate/verbs-test.h b/testfiles/src/cxxtests-to-migrate/verbs-test.h new file mode 100644 index 0000000..b8fd299 --- /dev/null +++ b/testfiles/src/cxxtests-to-migrate/verbs-test.h @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: see git history + * + * Copyright (C) 2016 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include <cxxtest/TestSuite.h> + +#include "verbs.h" + +class VerbsTest : public CxxTest::TestSuite +{ +public: + + class TestHook : public Inkscape::Verb { + public: + static int getInternalTableSize() { return _getBaseListSize(); } + + private: + TestHook(); + }; + + void testEnumLength() + { + TS_ASSERT_DIFFERS( 0, static_cast<int>(SP_VERB_LAST) ); + TS_ASSERT_EQUALS( static_cast<int>(SP_VERB_LAST) + 1, TestHook::getInternalTableSize() ); + } + + void testEnumFixed() + { + TS_ASSERT_EQUALS( 0, static_cast<int>(SP_VERB_INVALID) ); + TS_ASSERT_EQUALS( 1, static_cast<int>(SP_VERB_NONE) ); + + TS_ASSERT_DIFFERS( 0, static_cast<int>(SP_VERB_LAST) ); + TS_ASSERT_DIFFERS( 1, static_cast<int>(SP_VERB_LAST) ); + } + + void testFetch() + { + for ( int i = 0; i < static_cast<int>(SP_VERB_LAST); i++ ) + { + char tmp[16]; + snprintf( tmp, sizeof(tmp), "Verb# %d", i ); + tmp[sizeof(tmp)-1] = 0; + std::string descr(tmp); + + Inkscape::Verb* verb = Inkscape::Verb::get(i); + TSM_ASSERT( descr, verb ); + if ( verb ) + { + TSM_ASSERT_EQUALS( descr, verb->get_code(), static_cast<unsigned int>(i) ); + + if ( i != static_cast<int>(SP_VERB_INVALID) ) + { + TSM_ASSERT( descr, verb->get_id() ); + TSM_ASSERT( descr, verb->get_name() ); + + Inkscape::Verb* bounced = verb->getbyid( verb->get_id() ); + // TODO - put this back once verbs are fixed + //TSM_ASSERT( descr, bounced ); + if ( bounced ) + { + TSM_ASSERT_EQUALS( descr, bounced->get_code(), static_cast<unsigned int>(i) ); + } + else + { + TS_FAIL( std::string("Unable to getbyid() for ") + descr + std::string(" ID: '") + std::string(verb->get_id()) + std::string("'") ); + } + } + else + { + TSM_ASSERT( std::string("SP_VERB_INVALID"), !verb->get_id() ); + TSM_ASSERT( std::string("SP_VERB_INVALID"), !verb->get_name() ); + } + } + } + } + +}; + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/dir-util-test.cpp b/testfiles/src/dir-util-test.cpp new file mode 100644 index 0000000..bac5e3c --- /dev/null +++ b/testfiles/src/dir-util-test.cpp @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Unit tests for dir utils. + * + * Author: + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtest/gtest.h" + +#include <glib.h> + +#include "io/dir-util.h" + +namespace { + + +TEST(DirUtilTest, Base) +{ + char const* cases[][3] = { +#if defined(WIN32) || defined(__WIN32__) + {"\\foo\\bar", "\\foo", "bar"}, + {"\\foo\\barney", "\\foo\\bar", "\\foo\\barney"}, + {"\\foo\\bar\\baz", "\\foo\\", "bar\\baz"}, + {"\\foo\\bar\\baz", "\\", "foo\\bar\\baz"}, + {"\\foo\\bar\\baz", "\\foo\\qux", "\\foo\\bar\\baz"}, +#else + {"/foo/bar", "/foo", "bar"}, + {"/foo/barney", "/foo/bar", "/foo/barney"}, + {"/foo/bar/baz", "/foo/", "bar/baz"}, + {"/foo/bar/baz", "/", "foo/bar/baz"}, + {"/foo/bar/baz", "/foo/qux", "/foo/bar/baz"}, +#endif + }; + + for (auto & i : cases) + { + if ( i[0] && i[1] ) { // std::string can't use null. + std::string result = sp_relative_path_from_path( i[0], i[1] ); + ASSERT_FALSE( result.empty() ); + if ( !result.empty() ) + { + ASSERT_EQ( std::string(i[2]), result ); + } + } + } +} + +} // namespace + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/testfiles/src/drag-and-drop-svgz.cpp b/testfiles/src/drag-and-drop-svgz.cpp new file mode 100644 index 0000000..5ea7c0b --- /dev/null +++ b/testfiles/src/drag-and-drop-svgz.cpp @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/** + * @file + * Test that svgz (= compressed SVG) import/drag-and-drop + * is working: https://gitlab.com/inkscape/inkscape/issues/906 . + * + */ +/* + * Authors: + * Shlomi Fish + * + * Copyright (C) 2020 Authors + */ + +#include "doc-per-case-test.h" +#include <glibmm.h> + +#include "extension/db.h" +#include "extension/find_extension_by_mime.h" +#include "extension/internal/svgz.h" +#include "path-prefix.h" +#include "preferences.h" + +#include "gtest/gtest.h" + + +class SvgzImportTest : public DocPerCaseTest { + public: + SvgzImportTest() {} + void TestBody() + { + ASSERT_TRUE(_doc != nullptr); + ASSERT_TRUE(_doc->getRoot() != nullptr); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/dialogs/import/ask_svg", true); + prefs->setBool("/options/onimport", true); + auto ext = Inkscape::Extension::find_by_mime("image/svg+xml-compressed"); + ext->set_gui(true); + auto fn = Glib::build_filename(INKSCAPE_EXAMPLESDIR, "tiger.svgz"); + auto imod = dynamic_cast<Inkscape::Extension::Input *>(ext); + auto svg_mod = (new Inkscape::Extension::Internal::Svg); + ASSERT_TRUE(svg_mod->open(imod, fn.c_str()) != nullptr); + } + ~SvgzImportTest() override {} +}; + +TEST_F(SvgzImportTest, Eq) +{ + SvgzImportTest foo; + foo.TestBody(); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/extract-uri-test.cpp b/testfiles/src/extract-uri-test.cpp new file mode 100644 index 0000000..acff966 --- /dev/null +++ b/testfiles/src/extract-uri-test.cpp @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * Test extract_uri + */ +/* + * Authors: + * Thomas Holder + * + * Copyright (C) 2018 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "extract-uri.h" +#include "gtest/gtest.h" + +TEST(ExtractUriTest, valid) +{ + ASSERT_EQ(extract_uri("url(#foo)"), "#foo"); + ASSERT_EQ(extract_uri("url( \t #foo \t )"), "#foo"); + ASSERT_EQ(extract_uri("url( '#foo' )"), "#foo"); + ASSERT_EQ(extract_uri("url('url(foo)')"), "url(foo)"); + ASSERT_EQ(extract_uri("url(\"foo(url)\")"), "foo(url)"); + ASSERT_EQ(extract_uri("url()bar"), ""); + ASSERT_EQ(extract_uri("url( )bar"), ""); + ASSERT_EQ(extract_uri("url(a b)"), "a b"); +} + +TEST(ExtractUriTest, legacy) +{ + ASSERT_EQ(extract_uri("url (foo)"), "foo"); +} + +TEST(ExtractUriTest, invalid) +{ + ASSERT_EQ(extract_uri("#foo"), ""); + ASSERT_EQ(extract_uri(" url(foo)"), ""); + ASSERT_EQ(extract_uri("url(#foo"), ""); + ASSERT_EQ(extract_uri("url('#foo'"), ""); + ASSERT_EQ(extract_uri("url('#foo)"), ""); + ASSERT_EQ(extract_uri("url #foo)"), ""); +} + +static char const *extract_end(char const *s) +{ + char const *end = nullptr; + extract_uri(s, &end); + return end; +} + +TEST(ExtractUriTest, endptr) +{ + ASSERT_STREQ(extract_end(""), nullptr); + ASSERT_STREQ(extract_end("url(invalid"), nullptr); + ASSERT_STREQ(extract_end("url('invalid)"), nullptr); + ASSERT_STREQ(extract_end("url(valid)"), ""); + ASSERT_STREQ(extract_end("url(valid)foo"), "foo"); + ASSERT_STREQ(extract_end("url('valid')bar"), "bar"); + ASSERT_STREQ(extract_end("url( 'valid' )bar"), "bar"); + ASSERT_STREQ(extract_end("url( valid ) bar "), " bar "); + ASSERT_STREQ(extract_end("url()bar"), "bar"); + ASSERT_STREQ(extract_end("url( )bar"), "bar"); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/lpe-bool-test.cpp b/testfiles/src/lpe-bool-test.cpp new file mode 100644 index 0000000..31bc371 --- /dev/null +++ b/testfiles/src/lpe-bool-test.cpp @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * LPE Boolean operation test + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include <gtest/gtest.h> +#include <src/document.h> +#include <src/inkscape.h> +#include <src/live_effects/lpe-bool.h> +#include <src/object/sp-ellipse.h> +#include <src/object/sp-lpe-item.h> + + + +using namespace Inkscape; +using namespace Inkscape::LivePathEffect; + +class LPEBoolTest : public ::testing::Test { + protected: + void SetUp() override + { + // setup hidden dependency + Application::create(false); + } +}; + +TEST_F(LPEBoolTest, canBeApplyedToNonSiblingPaths) +{ + std::string svg("\ +<svg width='100' height='100'\ + xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'\ + xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'>\ + <defs>\ + <inkscape:path-effect\ + id='path-effect1'\ + effect='bool_op'\ + operation='diff'\ + operand-path='#circle1'\ + lpeversion='1'\ + hide-linked='true' />\ + </defs>\ + <path id='rect1'\ + inkscape:path-effect='#path-effect1'\ + sodipodi:type='rect'\ + width='100' height='100' fill='#ff0000' />\ + <g id='group1'>\ + <circle id='circle1'\ + r='40' cy='50' cx='50' fill='#ffffff' style='display:inline'/>\ + </g>\ +</svg>"); + + SPDocument *doc = SPDocument::createNewDocFromMem(svg.c_str(), svg.size(), true); + doc->ensureUpToDate(); + + auto lpe_item = dynamic_cast<SPLPEItem *>(doc->getObjectById("rect1")); + ASSERT_TRUE(lpe_item != nullptr); + + auto lpe_bool_op_effect = dynamic_cast<LPEBool *>(lpe_item->getPathEffectOfType(EffectType::BOOL_OP)); + ASSERT_TRUE(lpe_bool_op_effect != nullptr); + + auto operand_path = lpe_bool_op_effect->getParameter("operand-path")->param_getSVGValue(); + auto circle = dynamic_cast<SPGenericEllipse *>(doc->getObjectById(operand_path.substr(1))); + ASSERT_TRUE(circle != nullptr); +}
\ No newline at end of file diff --git a/testfiles/src/object-set-test.cpp b/testfiles/src/object-set-test.cpp new file mode 100644 index 0000000..5df9738 --- /dev/null +++ b/testfiles/src/object-set-test.cpp @@ -0,0 +1,636 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Multiindex container for selection + * + * Authors: + * Adrian Boguszewski + * + * Copyright (C) 2016 Adrian Boguszewski + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include <gtest/gtest.h> +#include <doc-per-case-test.h> +#include <src/object/sp-factory.h> +#include <src/object/sp-rect.h> +#include <src/object/sp-path.h> +#include <src/object/sp-use.h> +#include <src/object/sp-root.h> +#include <src/object/object-set.h> +#include <xml/node.h> +#include <src/xml/text-node.h> +#include <src/xml/simple-document.h> +//#include <unistd.h> +#include <2geom/transforms.h> +using namespace Inkscape; +using namespace Inkscape::XML; + +class ObjectSetTest: public DocPerCaseTest { +public: + ObjectSetTest() { + A = new SPObject(); + B = new SPObject(); + C = new SPObject(); + D = new SPObject(); + E = new SPObject(); + F = new SPObject(); + G = new SPObject(); + H = new SPObject(); + X = new SPObject(); + set = new ObjectSet(_doc); + set2 = new ObjectSet(_doc); + auto sd = _doc->getReprDoc(); + auto xt = new TextNode(Util::share_string("x"), sd); + auto ht = new TextNode(Util::share_string("h"), sd); + auto gt = new TextNode(Util::share_string("g"), sd); + auto ft = new TextNode(Util::share_string("f"), sd); + auto et = new TextNode(Util::share_string("e"), sd); + auto dt = new TextNode(Util::share_string("d"), sd); + auto ct = new TextNode(Util::share_string("c"), sd); + auto bt = new TextNode(Util::share_string("b"), sd); + auto at = new TextNode(Util::share_string("a"), sd); + X->invoke_build(_doc, xt, 0); + H->invoke_build(_doc, ht, 0); + G->invoke_build(_doc, gt, 0); + F->invoke_build(_doc, ft, 0); + E->invoke_build(_doc, et, 0); + D->invoke_build(_doc, dt, 0); + C->invoke_build(_doc, ct, 0); + B->invoke_build(_doc, bt, 0); + A->invoke_build(_doc, at, 0); + + //create 3 rects at root of document + Inkscape::XML::Node *repr = _doc->getReprDoc()->createElement("svg:rect"); + _doc->getRoot()->appendChild(repr); + r1.reset(dynamic_cast<SPRect*>(_doc->getObjectByRepr(repr))); + repr = _doc->getReprDoc()->createElement("svg:rect"); + _doc->getRoot()->appendChild(repr); + r2.reset(dynamic_cast<SPRect*>(_doc->getObjectByRepr(repr))); + repr = _doc->getReprDoc()->createElement("svg:rect"); + _doc->getRoot()->appendChild(repr); + r3.reset(dynamic_cast<SPRect*>(_doc->getObjectByRepr(repr))); + EXPECT_EQ(6, _doc->getRoot()->children.size());//metadata, defs, namedview, and those three rects. + r1->x = r1->y = r2->x = r2->y = r3->x = r3->y = 0; + r1->width = r1->height = r2->width = r2->height = r3->width = r3->height = 10; + r1->set_shape(); + r2->set_shape(); + r3->set_shape(); + + } + ~ObjectSetTest() override { + delete set; + delete set2; + delete X; + delete H; + delete G; + delete F; + delete E; + delete D; + delete C; + delete B; + delete A; + } + SPObject* A; + SPObject* B; + SPObject* C; + SPObject* D; + SPObject* E; + SPObject* F; + SPObject* G; + SPObject* H; + SPObject* X; + std::unique_ptr<SPRect> r1; + std::unique_ptr<SPRect> r2; + std::unique_ptr<SPRect> r3; + ObjectSet* set; + ObjectSet* set2; +}; + +#define SP_IS_CLONE(obj) (dynamic_cast<const SPUse*>(obj) != NULL) + +bool containsClone(ObjectSet* set) { + for (auto it : set->items()) { + if (SP_IS_CLONE(it)) { + return true; + } + if (SP_IS_GROUP(it)) { + ObjectSet tmp_set(set->document()); + std::vector<SPObject*> c = it->childList(false); + tmp_set.setList(c); + if (containsClone(&tmp_set)) { + return true; + } + } + } + return false; +} + +TEST_F(ObjectSetTest, Basics) { + EXPECT_EQ(0, set->size()); + set->add(A); + EXPECT_EQ(1, set->size()); + EXPECT_TRUE(set->includes(A)); + set->add(B); + set->add(C); + EXPECT_EQ(3, set->size()); + EXPECT_TRUE(set->includes(B)); + EXPECT_TRUE(set->includes(C)); + EXPECT_FALSE(set->includes(D)); + EXPECT_FALSE(set->includes(X)); + EXPECT_FALSE(set->includes(nullptr)); + set->remove(A); + EXPECT_EQ(2, set->size()); + EXPECT_FALSE(set->includes(A)); + set->clear(); + EXPECT_EQ(0, set->size()); + bool resultNull = set->add((SPObject*)nullptr); + EXPECT_FALSE(resultNull); + EXPECT_EQ(0, set->size()); + bool resultNull2 = set->remove(nullptr); + EXPECT_FALSE(resultNull2); +} + +TEST_F(ObjectSetTest, Advanced) { + set->add(A); + set->add(B); + set->add(C); + EXPECT_TRUE(set->includes(C)); + set->toggle(C); + EXPECT_EQ(2, set->size()); + EXPECT_FALSE(set->includes(C)); + set->toggle(D); + EXPECT_EQ(3, set->size()); + EXPECT_TRUE(set->includes(D)); + set->toggle(D); + EXPECT_EQ(2, set->size()); + EXPECT_FALSE(set->includes(D)); + EXPECT_EQ(nullptr, set->single()); + set->set(X); + EXPECT_EQ(1, set->size()); + EXPECT_TRUE(set->includes(X)); + EXPECT_EQ(X, set->single()); + EXPECT_FALSE(set->isEmpty()); + set->clear(); + EXPECT_TRUE(set->isEmpty()); + std::vector<SPObject*> list1 {A, B, C, D}; + std::vector<SPObject*> list2 {E, F}; + set->addList(list1); + EXPECT_EQ(4, set->size()); + set->addList(list2); + EXPECT_EQ(6, set->size()); + EXPECT_TRUE(set->includes(A)); + EXPECT_TRUE(set->includes(B)); + EXPECT_TRUE(set->includes(C)); + EXPECT_TRUE(set->includes(D)); + EXPECT_TRUE(set->includes(E)); + EXPECT_TRUE(set->includes(F)); + set->setList(list2); + EXPECT_EQ(2, set->size()); + EXPECT_TRUE(set->includes(E)); + EXPECT_TRUE(set->includes(F)); +} + +TEST_F(ObjectSetTest, Items) { + // cannot test smallestItem and largestItem functions due to too many dependencies + // uncomment if the problem is fixed + + SPRect* rect10x100 = &*r1; + rect10x100->x = rect10x100->x = 0; + rect10x100->width = 10; + rect10x100->height = 100; + rect10x100->set_shape(); + + SPRect* rect20x40 = &*r2; + rect20x40->x = rect20x40->x = 0; + rect20x40->width = 20; + rect20x40->height = 40; + rect20x40->set_shape(); + + SPRect* rect30x30 = &*r3; + rect30x30->x = rect30x30->x = 0; + rect30x30->width = 30; + rect30x30->height = 30; + rect30x30->set_shape(); + + + set->add(rect10x100); + EXPECT_EQ(rect10x100, set->singleItem()); + EXPECT_EQ(rect10x100->getRepr(), set->singleRepr()); + set->add(rect20x40); + EXPECT_EQ(nullptr, set->singleItem()); + EXPECT_EQ(nullptr, set->singleRepr()); + set->add(rect30x30); + EXPECT_EQ(3, set->size()); + EXPECT_EQ(rect10x100, set->smallestItem(ObjectSet::CompareSize::HORIZONTAL)); + EXPECT_EQ(rect30x30, set->smallestItem(ObjectSet::CompareSize::VERTICAL)); + EXPECT_EQ(rect20x40, set->smallestItem(ObjectSet::CompareSize::AREA)); + EXPECT_EQ(rect30x30, set->largestItem(ObjectSet::CompareSize::HORIZONTAL)); + EXPECT_EQ(rect10x100, set->largestItem(ObjectSet::CompareSize::VERTICAL)); + EXPECT_EQ(rect10x100, set->largestItem(ObjectSet::CompareSize::AREA)); +} + +TEST_F(ObjectSetTest, Ranges) { + std::vector<SPObject*> objs {A, D, B, E, C, F}; + set->add(objs.begin() + 1, objs.end() - 1); + EXPECT_EQ(4, set->size()); + auto it = set->objects().begin(); + EXPECT_EQ(D, *it++); + EXPECT_EQ(B, *it++); + EXPECT_EQ(E, *it++); + EXPECT_EQ(C, *it++); + EXPECT_EQ(set->objects().end(), it); + SPObject* rect1 = SPFactory::createObject("svg:rect"); + SPObject* rect2 = SPFactory::createObject("svg:rect"); + SPObject* rect3 = SPFactory::createObject("svg:rect"); + set->add(rect1); + set->add(rect2); + set->add(rect3); + EXPECT_EQ(7, set->size()); + auto xmlNode = set->xmlNodes().begin(); + EXPECT_EQ(3, boost::distance(set->xmlNodes())); + EXPECT_EQ(rect1->getRepr(), *xmlNode++); + EXPECT_EQ(rect2->getRepr(), *xmlNode++); + EXPECT_EQ(rect3->getRepr(), *xmlNode++); + EXPECT_EQ(set->xmlNodes().end(), xmlNode); + auto item = set->items().begin(); + EXPECT_EQ(3, boost::distance(set->items())); + EXPECT_EQ(rect1, *item++); + EXPECT_EQ(rect2, *item++); + EXPECT_EQ(rect3, *item++); + EXPECT_EQ(set->items().end(), item); +} + +TEST_F(ObjectSetTest, Autoremoving) { + set->add(A); + EXPECT_TRUE(set->includes(A)); + EXPECT_EQ(1, set->size()); + A->releaseReferences(); + EXPECT_EQ(0, set->size()); +} + +TEST_F(ObjectSetTest, BasicDescendants) { + A->attach(B, nullptr); + B->attach(C, nullptr); + A->attach(D, nullptr); + bool resultB = set->add(B); + bool resultB2 = set->add(B); + EXPECT_TRUE(resultB); + EXPECT_FALSE(resultB2); + EXPECT_TRUE(set->includes(B)); + bool resultC = set->add(C); + EXPECT_FALSE(resultC); + EXPECT_FALSE(set->includes(C)); + EXPECT_EQ(1, set->size()); + bool resultA = set->add(A); + EXPECT_TRUE(resultA); + EXPECT_EQ(1, set->size()); + EXPECT_TRUE(set->includes(A)); + EXPECT_FALSE(set->includes(B)); +} + +TEST_F(ObjectSetTest, AdvancedDescendants) { + A->attach(B, nullptr); + A->attach(C, nullptr); + A->attach(X, nullptr); + B->attach(D, nullptr); + B->attach(E, nullptr); + C->attach(F, nullptr); + C->attach(G, nullptr); + C->attach(H, nullptr); + set->add(A); + bool resultF = set->remove(F); + EXPECT_TRUE(resultF); + EXPECT_EQ(4, set->size()); + EXPECT_FALSE(set->includes(F)); + EXPECT_TRUE(set->includes(B)); + EXPECT_TRUE(set->includes(G)); + EXPECT_TRUE(set->includes(H)); + EXPECT_TRUE(set->includes(X)); + bool resultF2 = set->add(F); + EXPECT_TRUE(resultF2); + EXPECT_EQ(5, set->size()); + EXPECT_TRUE(set->includes(F)); +} + +TEST_F(ObjectSetTest, Removing) { + A->attach(B, nullptr); + A->attach(C, nullptr); + A->attach(X, nullptr); + B->attach(D, nullptr); + B->attach(E, nullptr); + C->attach(F, nullptr); + C->attach(G, nullptr); + C->attach(H, nullptr); + bool removeH = set->remove(H); + EXPECT_FALSE(removeH); + set->add(A); + bool removeX = set->remove(X); + EXPECT_TRUE(removeX); + EXPECT_EQ(2, set->size()); + EXPECT_TRUE(set->includes(B)); + EXPECT_TRUE(set->includes(C)); + EXPECT_FALSE(set->includes(X)); + EXPECT_FALSE(set->includes(A)); + bool removeX2 = set->remove(X); + EXPECT_FALSE(removeX2); + EXPECT_EQ(2, set->size()); + bool removeA = set->remove(A); + EXPECT_FALSE(removeA); + EXPECT_EQ(2, set->size()); + bool removeC = set->remove(C); + EXPECT_TRUE(removeC); + EXPECT_EQ(1, set->size()); + EXPECT_TRUE(set->includes(B)); + EXPECT_FALSE(set->includes(C)); +} + +TEST_F(ObjectSetTest, TwoSets) { + A->attach(B, nullptr); + A->attach(C, nullptr); + set->add(A); + set2->add(A); + EXPECT_EQ(1, set->size()); + EXPECT_EQ(1, set2->size()); + set->remove(B); + EXPECT_EQ(1, set->size()); + EXPECT_TRUE(set->includes(C)); + EXPECT_EQ(1, set2->size()); + EXPECT_TRUE(set2->includes(A)); + C->releaseReferences(); + EXPECT_EQ(0, set->size()); + EXPECT_EQ(1, set2->size()); + EXPECT_TRUE(set2->includes(A)); +} + +TEST_F(ObjectSetTest, SetRemoving) { + ObjectSet *objectSet = new ObjectSet(_doc); + A->attach(B, nullptr); + objectSet->add(A); + objectSet->add(C); + EXPECT_EQ(2, objectSet->size()); + delete objectSet; + EXPECT_STREQ(nullptr, A->getId()); + EXPECT_STREQ(nullptr, C->getId()); +} + +TEST_F(ObjectSetTest, Delete) { + //we cannot use the same item as in other tests since it will be freed at the test destructor + + EXPECT_EQ(_doc->getRoot(), r1->parent); + set->add(r1.get()); + set->deleteItems(); + r1.release(); + EXPECT_EQ(0, set->size()); + //EXPECT_EQ(nullptr, r1->parent); +} + +TEST_F(ObjectSetTest, Ops) { + set->add(r1.get()); + set->add(r2.get()); + set->add(r3.get()); + set->duplicate(); + EXPECT_EQ(9, _doc->getRoot()->children.size());//metadata, defs, namedview, and those 3x2 rects. + EXPECT_EQ(3, set->size()); + EXPECT_FALSE(set->includes(r1.get())); + set->deleteItems(); + EXPECT_TRUE(set->isEmpty()); + set->add(r1.get()); + set->add(r2.get()); + set->add(r3.get()); + set->group();//r1-3 are now invalid (grouping makes copies) + r1.release(); + r2.release(); + r3.release(); + EXPECT_EQ(4, _doc->getRoot()->children.size()); + EXPECT_EQ(1, set->size()); + set->ungroup(); + EXPECT_EQ(6, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + /* Uncomment this when toNextLayer is made desktop-independent + set->group(); + set2->add(set->singleItem()->childList(false)[0]); + EXPECT_EQ(3, set->singleItem()->children.size()); + EXPECT_EQ(4, _doc->getRoot()->children.size()); + set2->popFromGroup(); + EXPECT_EQ(2, set->singleItem()->children.size()); + EXPECT_EQ(5, _doc->getRoot()->children.size()); + set->ungroup(); + set->add(set2->singleItem()); + */ + set->clone(); + EXPECT_EQ(9, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_NE(nullptr,dynamic_cast<SPUse*>(*(set->items().begin()))); + EXPECT_EQ(nullptr,dynamic_cast<SPRect*>(*(set->items().begin()))); + set->unlink(); + EXPECT_EQ(9, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_EQ(nullptr,dynamic_cast<SPUse*>(*(set->items().begin()))); + EXPECT_NE(nullptr,dynamic_cast<SPRect*>(*(set->items().begin()))); + set->clone(); //creates 3 clones + set->clone(); //creates 3 clones of clones + EXPECT_EQ(15, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_NE(nullptr,dynamic_cast<SPUse*>( ((SPUse*)(*(set->items().begin())))->get_original()));//"original is a Use" + set->unlink(); //clone of clone of rect -> rect + EXPECT_EQ(nullptr,dynamic_cast<SPUse*>(*(set->items().begin()))); + EXPECT_NE(nullptr,dynamic_cast<SPRect*>(*(set->items().begin()))); + set->clone(); + set->set(*(set->items().begin())); + set->cloneOriginal();//get clone original + EXPECT_EQ(18, _doc->getRoot()->children.size()); + EXPECT_EQ(1, set->size()); + EXPECT_NE(nullptr,dynamic_cast<SPRect*>(*(set->items().begin()))); + //let's stop here. + // TODO: write a hundred more tests to check clone (non-)displacement when grouping, ungrouping and unlinking... + TearDownTestCase(); + SetUpTestCase(); +} + +TEST_F(ObjectSetTest, unlinkRecursiveBasic) { + // This is the same as the test (ObjectSetTest, Ops), but with unlinkRecursive instead of unlink. + set->set(r1.get()); + set->add(r2.get()); + set->add(r3.get()); + EXPECT_FALSE(containsClone(set)); + set->duplicate(); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(9, _doc->getRoot()->children.size());//metadata, defs, namedview, and those 3x2 rects. + EXPECT_EQ(3, set->size()); + EXPECT_FALSE(set->includes(r1.get())); + set->deleteItems(); + EXPECT_FALSE(containsClone(set)); + EXPECT_TRUE(set->isEmpty()); + set->add(r1.get()); + set->add(r2.get()); + set->add(r3.get()); + EXPECT_FALSE(containsClone(set)); + set->group();//r1-3 are now invalid (grouping makes copies) + r1.release(); + r2.release(); + r3.release(); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(4, _doc->getRoot()->children.size()); + EXPECT_EQ(1, set->size()); + set->ungroup(); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(6, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + /* Uncomment this when toNextLayer is made desktop-independent + set->group(); + set2->add(set->singleItem()->childList(false)[0]); + EXPECT_EQ(3, set->singleItem()->children.size()); + EXPECT_EQ(4, _doc->getRoot()->children.size()); + set2->popFromGroup(); + EXPECT_EQ(2, set->singleItem()->children.size()); + EXPECT_EQ(5, _doc->getRoot()->children.size()); + set->ungroup(); + set->add(set2->singleItem()); + */ + set->clone(); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(9, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_NE(nullptr, dynamic_cast<SPUse*>(*(set->items().begin()))); + EXPECT_EQ(nullptr, dynamic_cast<SPRect*>(*(set->items().begin()))); + set->unlinkRecursive(); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(9, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_EQ(nullptr, dynamic_cast<SPUse*>(*(set->items().begin()))); + EXPECT_NE(nullptr, dynamic_cast<SPRect*>(*(set->items().begin()))); + set->clone(); //creates 3 clones + EXPECT_TRUE(containsClone(set)); + set->clone(); //creates 3 clones of clones + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(15, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_NE(nullptr, dynamic_cast<SPUse*>( ((SPUse*)(*(set->items().begin())))->get_original()));//"original is a Use" + set->unlinkRecursive(); //clone of clone of rect -> rect + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(nullptr, dynamic_cast<SPUse*>(*(set->items().begin()))); + EXPECT_NE(nullptr, dynamic_cast<SPRect*>(*(set->items().begin()))); + set->clone(); + EXPECT_TRUE(containsClone(set)); + set->set(*(set->items().begin())); + set->cloneOriginal();//get clone original + EXPECT_EQ(18, _doc->getRoot()->children.size()); + EXPECT_EQ(1, set->size()); + EXPECT_NE(nullptr, dynamic_cast<SPRect*>(*(set->items().begin()))); + TearDownTestCase(); + SetUpTestCase(); +} + +TEST_F(ObjectSetTest, unlinkRecursiveAdvanced) { + set->set(r1.get()); + set->add(r2.get()); + set->add(r3.get()); + set->group();//r1-3 are now invalid (grouping makes copies) + r1.release(); + r2.release(); + r3.release(); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(1, set->size()); + SPItem* original = set->singleItem(); + set->clone(); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(1, set->size()); + set->add(original); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(2, set->size()); + set->group(); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(1, set->size()); + original = set->singleItem(); + set->clone(); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(1, set->size()); + set->add(original); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(2, set->size()); + set->group(); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(1, set->size()); + original = set->singleItem(); + set->clone(); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(1, set->size()); + set->add(original); + EXPECT_TRUE(containsClone(set)); + EXPECT_EQ(2, set->size()); + set->unlinkRecursive(); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(2, set->size()); + + TearDownTestCase(); + SetUpTestCase(); +} + +TEST_F(ObjectSetTest, ZOrder) { + //sp_object_compare_position_bool == true iff "r1<r2" iff r1 is "before" r2 in the file, ie r1 is lower than r2 + EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r2.get())); + EXPECT_TRUE(sp_object_compare_position_bool(r2.get(),r3.get())); + EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r3.get())); + EXPECT_FALSE(sp_object_compare_position_bool(r2.get(),r1.get())); + EXPECT_FALSE(sp_object_compare_position_bool(r3.get(),r1.get())); + EXPECT_FALSE(sp_object_compare_position_bool(r3.get(),r2.get())); + //1 2 3 + set->set(r2.get()); + set->raise(); + //1 3 2 + EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r3.get())); + EXPECT_TRUE(sp_object_compare_position_bool(r3.get(),r2.get()));//! + set->set(r3.get()); + set->lower(); + //3 1 2 + EXPECT_TRUE(sp_object_compare_position_bool(r3.get(),r1.get())); + EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r2.get())); + set->raiseToTop(); + //1 2 3 + EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r2.get())); + EXPECT_TRUE(sp_object_compare_position_bool(r2.get(),r3.get())); + set->lowerToBottom(); + //3 1 2 + EXPECT_TRUE(sp_object_compare_position_bool(r3.get(),r1.get())); + EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r2.get())); +} + +TEST_F(ObjectSetTest, Combine) { + set->add(r1.get()); + set->add(r2.get()); + set->combine(); + r1.release(); + r2.release(); + EXPECT_EQ(1, set->size()); + EXPECT_EQ(5, _doc->getRoot()->children.size()); + set->breakApart(); + EXPECT_EQ(2, set->size()); + EXPECT_EQ(6, _doc->getRoot()->children.size()); + set->deleteItems(); + set->set(r3.get()); + set->toCurves(); + r3.release(); + auto x = set->singleItem(); + EXPECT_NE(nullptr,dynamic_cast<SPPath*>(x)); + EXPECT_EQ(nullptr,dynamic_cast<SPRect*>(x)); + set->deleteItems(); +} + +TEST_F(ObjectSetTest, Moves) { + set->add(r1.get()); + set->moveRelative(15,15); + EXPECT_EQ(15,r1->x.value); + Geom::Point p(20,20); + Geom::Scale s(2); + set->setScaleRelative(p,s); + EXPECT_EQ(10,r1->x.value); + EXPECT_EQ(20,r1->width.value); + set->toCurves(); + r1.release(); + auto x = set->singleItem(); + EXPECT_EQ(20,(*(x->documentVisualBounds()))[0].extent()); + set->rotate90(true); + set->rotate90(true); + EXPECT_EQ(20,(*(x->documentVisualBounds()))[0].extent()); + set->deleteItems(); +} diff --git a/testfiles/src/object-style-test.cpp b/testfiles/src/object-style-test.cpp new file mode 100644 index 0000000..25d9268 --- /dev/null +++ b/testfiles/src/object-style-test.cpp @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Combination style and object testing for cascading and flags. + *//* + * + * Authors: + * Martin Owens + * + * Copyright (C) 2018 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include <gtest/gtest.h> +#include <doc-per-case-test.h> + +#include <src/style.h> +#include <src/object/sp-root.h> +#include <src/object/sp-rect.h> + +using namespace Inkscape; +using namespace Inkscape::XML; + +class ObjectTest: public DocPerCaseTest { +public: + ObjectTest() { + char const *docString = "\ +<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>\ +<style>\ +rect { fill: #808080; opacity:0.5; }\ +.extra { opacity:1.0; }\ +.overload { fill: #d0d0d0 !important; stroke: #c0c0c0 !important; }\ +.font { font: italic bold 12px/30px Georgia, serif; }\ +.exsize { stroke-width: 1ex; }\ +.fosize { font-size: 15px; }\ +</style>\ +<g style='fill:blue; stroke-width:2px;font-size: 14px;'>\ + <rect id='one' style='fill:red; stroke:green;'/>\ + <rect id='two' style='stroke:green; stroke-width:4px;'/>\ + <rect id='three' class='extra' style='fill: #cccccc;'/>\ + <rect id='four' class='overload' style='fill:green;stroke:red !important;'/>\ + <rect id='five' class='font' style='font: 15px arial, sans-serif;'/>/\ + <rect id='six' style='stroke-width:1em;'/>\ + <rect id='seven' class='exsize'/>\ + <rect id='eight' class='fosize' style='stroke-width: 50%;'/>\ +</g>\ +</svg>"; + doc = SPDocument::createNewDocFromMem(docString, static_cast<int>(strlen(docString)), false); + } + + ~ObjectTest() override { + doc->doUnref(); + } + + SPDocument *doc; +}; + +/* + * Test basic cascade values, that they are set correctly as we'd want to see them. + */ +TEST_F(ObjectTest, Styles) { + ASSERT_TRUE(doc != nullptr); + ASSERT_TRUE(doc->getRoot() != nullptr); + + SPRoot *root = doc->getRoot(); + ASSERT_TRUE(root->getRepr() != nullptr); + ASSERT_TRUE(root->hasChildren()); + + SPRect *one = dynamic_cast<SPRect *>(doc->getObjectById("one")); + ASSERT_TRUE(one != nullptr); + + // TODO: Fix when Inkscape preserves colour names (i.e. 'red') + EXPECT_EQ(one->style->fill.get_value(), Glib::ustring("#ff0000")); + EXPECT_EQ(one->style->stroke.get_value(), Glib::ustring("#008000")); + EXPECT_EQ(one->style->opacity.get_value(), Glib::ustring("0.5")); + EXPECT_EQ(one->style->stroke_width.get_value(), Glib::ustring("2px")); + + SPRect *two = dynamic_cast<SPRect *>(doc->getObjectById("two")); + ASSERT_TRUE(two != nullptr); + + EXPECT_EQ(two->style->fill.get_value(), Glib::ustring("#808080")); + EXPECT_EQ(two->style->stroke.get_value(), Glib::ustring("#008000")); + EXPECT_EQ(two->style->opacity.get_value(), Glib::ustring("0.5")); + EXPECT_EQ(two->style->stroke_width.get_value(), Glib::ustring("4px")); + + SPRect *three = dynamic_cast<SPRect *>(doc->getObjectById("three")); + ASSERT_TRUE(three != nullptr); + + EXPECT_EQ(three->style->fill.get_value(), Glib::ustring("#cccccc")); + EXPECT_EQ(three->style->stroke.get_value(), Glib::ustring("")); + EXPECT_EQ(three->style->opacity.get_value(), Glib::ustring("1")); + EXPECT_EQ(three->style->stroke_width.get_value(), Glib::ustring("2px")); + + SPRect *four = dynamic_cast<SPRect *>(doc->getObjectById("four")); + ASSERT_TRUE(four != nullptr); + + EXPECT_EQ(four->style->fill.get_value(), Glib::ustring("#d0d0d0")); + EXPECT_EQ(four->style->stroke.get_value(), Glib::ustring("#ff0000")); + EXPECT_EQ(four->style->opacity.get_value(), Glib::ustring("0.5")); + EXPECT_EQ(four->style->stroke_width.get_value(), Glib::ustring("2px")); +} + +/* + * Test the origin flag for each of the values, should indicate where it came from. + */ +TEST_F(ObjectTest, StyleSource) { + ASSERT_TRUE(doc != nullptr); + ASSERT_TRUE(doc->getRoot() != nullptr); + + SPRoot *root = doc->getRoot(); + ASSERT_TRUE(root->getRepr() != nullptr); + ASSERT_TRUE(root->hasChildren()); + + SPRect *one = dynamic_cast<SPRect *>(doc->getObjectById("one")); + ASSERT_TRUE(one != nullptr); + + EXPECT_EQ(one->style->fill.style_src, SP_STYLE_SRC_STYLE_PROP); + EXPECT_EQ(one->style->stroke.style_src, SP_STYLE_SRC_STYLE_PROP); + EXPECT_EQ(one->style->opacity.style_src, SP_STYLE_SRC_STYLE_SHEET); + EXPECT_EQ(one->style->stroke_width.style_src, SP_STYLE_SRC_STYLE_PROP); + + SPRect *two = dynamic_cast<SPRect *>(doc->getObjectById("two")); + ASSERT_TRUE(two != nullptr); + + EXPECT_EQ(two->style->fill.style_src, SP_STYLE_SRC_STYLE_SHEET); + EXPECT_EQ(two->style->stroke.style_src, SP_STYLE_SRC_STYLE_PROP); + EXPECT_EQ(two->style->opacity.style_src, SP_STYLE_SRC_STYLE_SHEET); + EXPECT_EQ(two->style->stroke_width.style_src, SP_STYLE_SRC_STYLE_PROP); + + SPRect *three = dynamic_cast<SPRect *>(doc->getObjectById("three")); + ASSERT_TRUE(three != nullptr); + + EXPECT_EQ(three->style->fill.style_src, SP_STYLE_SRC_STYLE_PROP); + EXPECT_EQ(three->style->stroke.style_src, SP_STYLE_SRC_STYLE_PROP); + EXPECT_EQ(three->style->opacity.style_src, SP_STYLE_SRC_STYLE_SHEET); + EXPECT_EQ(three->style->stroke_width.style_src, SP_STYLE_SRC_STYLE_PROP); + + SPRect *four = dynamic_cast<SPRect *>(doc->getObjectById("four")); + ASSERT_TRUE(four != nullptr); + + EXPECT_EQ(four->style->fill.style_src, SP_STYLE_SRC_STYLE_SHEET); + EXPECT_EQ(four->style->stroke.style_src, SP_STYLE_SRC_STYLE_PROP); + EXPECT_EQ(four->style->opacity.style_src, SP_STYLE_SRC_STYLE_SHEET); + EXPECT_EQ(four->style->stroke_width.style_src, SP_STYLE_SRC_STYLE_PROP); +} + +/* + * Test the breaking up of the font property and recreation into separate properties. + */ +TEST_F(ObjectTest, StyleFont) { + ASSERT_TRUE(doc != nullptr); + ASSERT_TRUE(doc->getRoot() != nullptr); + + SPRoot *root = doc->getRoot(); + ASSERT_TRUE(root->getRepr() != nullptr); + ASSERT_TRUE(root->hasChildren()); + + SPRect *five = dynamic_cast<SPRect *>(doc->getObjectById("five")); + ASSERT_TRUE(five != nullptr); + + // Font property is ALWAYS unset as it's converted into specific font css properties + EXPECT_EQ(five->style->font.get_value(), Glib::ustring("")); + EXPECT_EQ(five->style->font_size.get_value(), Glib::ustring("12px")); + EXPECT_EQ(five->style->font_weight.get_value(), Glib::ustring("bold")); + EXPECT_EQ(five->style->font_style.get_value(), Glib::ustring("italic")); + EXPECT_EQ(five->style->font_family.get_value(), Glib::ustring("arial, sans-serif")); +} + +/* + * Test the consumption of font dependent lengths in SPILength, e.g. EM, EX and % units + */ +TEST_F(ObjectTest, StyleFontSizes) { + ASSERT_TRUE(doc != nullptr); + ASSERT_TRUE(doc->getRoot() != nullptr); + + SPRoot *root = doc->getRoot(); + ASSERT_TRUE(root->getRepr() != nullptr); + ASSERT_TRUE(root->hasChildren()); + + SPRect *six = dynamic_cast<SPRect *>(doc->getObjectById("six")); + ASSERT_TRUE(six != nullptr); + + EXPECT_EQ(six->style->stroke_width.get_value(), Glib::ustring("1em")); + EXPECT_EQ(six->style->stroke_width.computed, 14); + + SPRect *seven = dynamic_cast<SPRect *>(doc->getObjectById("seven")); + ASSERT_TRUE(seven != nullptr); + + EXPECT_EQ(seven->style->stroke_width.get_value(), Glib::ustring("1ex")); + EXPECT_EQ(seven->style->stroke_width.computed, 7); + + SPRect *eight = dynamic_cast<SPRect *>(doc->getObjectById("eight")); + ASSERT_TRUE(eight != nullptr); + + EXPECT_EQ(eight->style->stroke_width.get_value(), Glib::ustring("50%")); + EXPECT_EQ(eight->style->stroke_width.computed, 1); // Is this right? +} diff --git a/testfiles/src/object-test.cpp b/testfiles/src/object-test.cpp new file mode 100644 index 0000000..ac42b30 --- /dev/null +++ b/testfiles/src/object-test.cpp @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Unit tests migrated from cxxtest + * + * Authors: + * Adrian Boguszewski + * + * Copyright (C) 2018 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <gtest/gtest.h> +#include <doc-per-case-test.h> +#include <src/object/sp-root.h> +#include <src/object/sp-path.h> + +using namespace Inkscape; +using namespace Inkscape::XML; + +class ObjectTest: public DocPerCaseTest { +public: + ObjectTest() { + // Sample document + // svg:svg + // svg:defs + // svg:path + // svg:linearGradient + // svg:stop + // svg:filter + // svg:feGaussianBlur (feel free to implement for other filters) + // svg:clipPath + // svg:rect + // svg:g + // svg:use + // svg:circle + // svg:ellipse + // svg:text + // svg:polygon + // svg:polyline + // svg:image + // svg:line + char const *docString = R"A( +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <!-- just a comment --> + <title id="title">SVG test</title> + <defs> + <path id="P" d="M -21,-4 -5,0 -18,12 -3,4 -4,21 0,5 12,17 4,2 21,3 5,-1 17,-12 2,-4 3,-21 -1,-5 -12,-18 -4,-3z"/> + <linearGradient id="LG" x1="0%" y1="0%" x2="100%" y2="0%"> + <stop offset="0%" style="stop-color:#ffff00;stop-opacity:1"/> + <stop offset="100%" style="stop-color:red;stop-opacity:1"/> + </linearGradient> + <clipPath id="clip" clipPathUnits="userSpaceOnUse"> + <rect x="10" y="10" width="100" height="100"/> + </clipPath> + <filter style="color-interpolation-filters:sRGB" id="filter" x="-0.15" width="1.34" y="0" height="1"> + <feGaussianBlur stdDeviation="4.26"/> + </filter> + </defs> + + <g id="G" transform="skewX(10.5) translate(9,5)"> + <use id="U" xlink:href="#P" opacity="0.5" fill="#1dace3" transform="rotate(4)"/> + <circle id="C" cx="45.5" cy="67" r="23" fill="#000"/> + <ellipse id="E" cx="200" cy="70" rx="85" ry="55" fill="url(#LG)"/> + <text id="T" fill="#fff" style="font-size:45;font-family:Verdana" x="150" y="86">TEST</text> + <polygon id="PG" points="60,20 100,40 100,80 60,100 20,80 20,40" clip-path="url(#clip)" filter="url(#filter)"/> + <polyline id="PL" points="0,40 40,40 40,80 80,80 80,120 120,120 120,160" style="fill:none;stroke:red;stroke-width:4"/> + <image id="I" xlink:href="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE4MCIgd2lkdGg9IjUwMCI+PHBhdGggZD0iTTAsNDAgNDAsNDAgNDAsODAgODAsODAgODAsMTIwIDEyMCwxMjAgMTIwLDE2MCIgc3R5bGU9ImZpbGw6d2hpdGU7c3Ryb2tlOnJlZDtzdHJva2Utd2lkdGg6NCIvPjwvc3ZnPgo="/> + <line id="L" x1="20" y1="100" x2="100" y2="20" stroke="black" stroke-width="2"/> + </g> +</svg> + )A"; + doc = SPDocument::createNewDocFromMem(docString, static_cast<int>(strlen(docString)), false); + } + + ~ObjectTest() override { + doc->doUnref(); + } + + SPDocument *doc; +}; + +TEST_F(ObjectTest, Clones) { + ASSERT_TRUE(doc != nullptr); + ASSERT_TRUE(doc->getRoot() != nullptr); + + SPRoot *root = doc->getRoot(); + ASSERT_TRUE(root->getRepr() != nullptr); + ASSERT_TRUE(root->hasChildren()); + + SPPath *path = dynamic_cast<SPPath *>(doc->getObjectById("P")); + ASSERT_TRUE(path != nullptr); + + Node *node = path->getRepr(); + ASSERT_TRUE(node != nullptr); + + Document *xml_doc = node->document(); + ASSERT_TRUE(xml_doc != nullptr); + + Node *parent = node->parent(); + ASSERT_TRUE(parent != nullptr); + + const size_t num_clones = 1000; + std::string href = std::string("#") + std::string(path->getId()); + std::vector<Node *> clones(num_clones, nullptr); + + // Create num_clones clones of this path and stick them in the document + for (size_t i = 0; i < num_clones; ++i) { + Node *clone = xml_doc->createElement("svg:use"); + Inkscape::GC::release(clone); + clone->setAttribute("xlink:href", href); + parent->addChild(clone, node); + clones[i] = clone; + } + + // Remove those clones + for (size_t i = 0; i < num_clones; ++i) { + parent->removeChild(clones[i]); + } +} + +TEST_F(ObjectTest, Grouping) { + ASSERT_TRUE(doc != nullptr); + ASSERT_TRUE(doc->getRoot() != nullptr); + + SPRoot *root = doc->getRoot(); + ASSERT_TRUE(root->getRepr() != nullptr); + ASSERT_TRUE(root->hasChildren()); + + SPGroup *group = dynamic_cast<SPGroup *>(doc->getObjectById("G")); + + ASSERT_TRUE(group != nullptr); + + Node *node = group->getRepr(); + ASSERT_TRUE(node != nullptr); + + Document *xml_doc = node->document(); + ASSERT_TRUE(xml_doc != nullptr); + + const size_t num_elements = 1000; + + Node *new_group = xml_doc->createElement("svg:g"); + Inkscape::GC::release(new_group); + node->addChild(new_group, nullptr); + + std::vector<Node *> elements(num_elements, nullptr); + + for (size_t i = 0; i < num_elements; ++i) { + Node *circle = xml_doc->createElement("svg:circle"); + Inkscape::GC::release(circle); + circle->setAttribute("cx", "2048"); + circle->setAttribute("cy", "1024"); + circle->setAttribute("r", "1.5"); + new_group->addChild(circle, nullptr); + elements[i] = circle; + } + + SPGroup *n_group = dynamic_cast<SPGroup *>(group->get_child_by_repr(new_group)); + ASSERT_TRUE(n_group != nullptr); + + std::vector<SPItem*> ch; + sp_item_group_ungroup(n_group, ch, false); + + // Remove those elements + for (size_t i = 0; i < num_elements; ++i) { + elements[i]->parent()->removeChild(elements[i]); + } + +} + +TEST_F(ObjectTest, Objects) { + ASSERT_TRUE(doc != nullptr); + ASSERT_TRUE(doc->getRoot() != nullptr); + + SPRoot *root = doc->getRoot(); + ASSERT_TRUE(root->getRepr() != nullptr); + ASSERT_TRUE(root->hasChildren()); + + SPPath *path = dynamic_cast<SPPath *>(doc->getObjectById("P")); + ASSERT_TRUE(path != nullptr); + + // Test parent behavior + SPObject *child = root->firstChild(); + ASSERT_TRUE(child != nullptr); + + EXPECT_EQ(root, child->parent); + EXPECT_EQ(doc, child->document); + EXPECT_TRUE(root->isAncestorOf(child)); + + // Test list behavior + SPObject *next = child->getNext(); + SPObject *prev = next; + EXPECT_EQ(child, next->getPrev()); + + prev = next; + next = next->getNext(); + while (next != nullptr) { + // Walk the list + EXPECT_EQ(prev, next->getPrev()); + prev = next; + next = next->getNext(); + } + + // Test hrefcount + EXPECT_TRUE(path->isReferenced()); +} diff --git a/testfiles/src/sp-gradient-test.cpp b/testfiles/src/sp-gradient-test.cpp new file mode 100644 index 0000000..d190f1c --- /dev/null +++ b/testfiles/src/sp-gradient-test.cpp @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Unit tests migrated from cxxtest + * + * Authors: + * Adrian Boguszewski + * + * Copyright (C) 2018 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <gtest/gtest.h> +#include <doc-per-case-test.h> +#include <src/object/sp-gradient.h> +#include <src/attributes.h> +#include <2geom/transforms.h> +#include <src/xml/node.h> +#include <src/xml/simple-document.h> +#include <src/svg/svg.h> + +using namespace Inkscape; +using namespace Inkscape::XML; + +class SPGradientTest: public DocPerCaseTest { +public: + SPGradientTest() { + DocPerCaseTest::SetUpTestCase(); + gr = new SPGradient(); + } + + ~SPGradientTest() override { + delete gr; + DocPerCaseTest::TearDownTestCase(); + } + + SPGradient *gr; +}; + +TEST_F(SPGradientTest, Init) { + ASSERT_TRUE(gr != nullptr); + EXPECT_TRUE(gr->gradientTransform.isIdentity()); + EXPECT_TRUE(Geom::are_near(Geom::identity(), gr->gradientTransform)); +} + +TEST_F(SPGradientTest, SetGradientTransform) { + SP_OBJECT(gr)->document = _doc; + + SP_OBJECT(gr)->setKeyValue(SP_ATTR_GRADIENTTRANSFORM, "translate(5, 8)"); + EXPECT_TRUE(Geom::are_near(Geom::Affine(Geom::Translate(5.0, 8.0)), gr->gradientTransform)); + + SP_OBJECT(gr)->setKeyValue(SP_ATTR_GRADIENTTRANSFORM, ""); + EXPECT_TRUE(Geom::are_near(Geom::identity(), gr->gradientTransform)); + + SP_OBJECT(gr)->setKeyValue(SP_ATTR_GRADIENTTRANSFORM, "rotate(90)"); + EXPECT_TRUE(Geom::are_near(Geom::Affine(Geom::Rotate::from_degrees(90.0)), gr->gradientTransform)); +} + +TEST_F(SPGradientTest, Write) { + SP_OBJECT(gr)->document = _doc; + + SP_OBJECT(gr)->setKeyValue(SP_ATTR_GRADIENTTRANSFORM, "matrix(0, 1, -1, 0, 0, 0)"); + Document *xml_doc = _doc->getReprDoc(); + + ASSERT_TRUE(xml_doc != nullptr); + + Node *repr = xml_doc->createElement("svg:radialGradient"); + SP_OBJECT(gr)->updateRepr(xml_doc, repr, SP_OBJECT_WRITE_ALL); + + gchar const *tr = repr->attribute("gradientTransform"); + Geom::Affine svd; + bool const valid = sp_svg_transform_read(tr, &svd); + + EXPECT_TRUE(valid); + EXPECT_TRUE(Geom::are_near(Geom::Affine(Geom::Rotate::from_degrees(90.0)), svd)); +} + +TEST_F(SPGradientTest, GetG2dGetGs2dSetGs2) { + SP_OBJECT(gr)->document = _doc; + + Geom::Affine grXform(2, 1, + 1, 3, + 4, 6); + gr->gradientTransform = grXform; + + Geom::Rect unit_rect(Geom::Point(0, 0), Geom::Point(1, 1)); + { + Geom::Affine g2d(gr->get_g2d_matrix(Geom::identity(), unit_rect)); + Geom::Affine gs2d(gr->get_gs2d_matrix(Geom::identity(), unit_rect)); + EXPECT_TRUE(Geom::are_near(Geom::identity(), g2d)); + EXPECT_TRUE(Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12)); + + gr->set_gs2d_matrix(Geom::identity(), unit_rect, gs2d); + EXPECT_TRUE(Geom::are_near(gr->gradientTransform, grXform, 1e-12)); + } + + gr->gradientTransform = grXform; + Geom::Affine funny(2, 3, + 4, 5, + 6, 7); + { + Geom::Affine g2d(gr->get_g2d_matrix(funny, unit_rect)); + Geom::Affine gs2d(gr->get_gs2d_matrix(funny, unit_rect)); + EXPECT_TRUE(Geom::are_near(funny, g2d)); + EXPECT_TRUE(Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12)); + + gr->set_gs2d_matrix(funny, unit_rect, gs2d); + EXPECT_TRUE(Geom::are_near(gr->gradientTransform, grXform, 1e-12)); + } + + gr->gradientTransform = grXform; + Geom::Rect larger_rect(Geom::Point(5, 6), Geom::Point(8, 10)); + { + Geom::Affine g2d(gr->get_g2d_matrix(funny, larger_rect)); + Geom::Affine gs2d(gr->get_gs2d_matrix(funny, larger_rect)); + EXPECT_TRUE(Geom::are_near(Geom::Affine(3, 0, + 0, 4, + 5, 6) * funny, g2d )); + EXPECT_TRUE(Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12)); + + gr->set_gs2d_matrix(funny, larger_rect, gs2d); + EXPECT_TRUE(Geom::are_near(gr->gradientTransform, grXform, 1e-12)); + + SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTUNITS, "userSpaceOnUse"); + Geom::Affine user_g2d(gr->get_g2d_matrix(funny, larger_rect)); + Geom::Affine user_gs2d(gr->get_gs2d_matrix(funny, larger_rect)); + EXPECT_TRUE(Geom::are_near(funny, user_g2d)); + EXPECT_TRUE(Geom::are_near(user_gs2d, gr->gradientTransform * user_g2d, 1e-12)); + } +} diff --git a/testfiles/src/sp-item-group-test.cpp b/testfiles/src/sp-item-group-test.cpp new file mode 100644 index 0000000..3439f54 --- /dev/null +++ b/testfiles/src/sp-item-group-test.cpp @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * SPGroup test + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include <gtest/gtest.h> +#include <src/document.h> +#include <src/inkscape.h> +#include <src/live_effects/effect.h> +#include <src/object/sp-lpe-item.h> + +using namespace Inkscape; +using namespace Inkscape::LivePathEffect; + +class SPGroupTest : public ::testing::Test { + protected: + void SetUp() override + { + // setup hidden dependency + Application::create(false); + } +}; + +TEST_F(SPGroupTest, applyingPowerClipEffectToGroupWithoutClipIsIgnored) +{ + std::string svg("\ +<svg width='100' height='100'>\ + <g id='group1'>\ + <rect id='rect1' width='100' height='50' />\ + <rect id='rect2' y='50' width='100' height='50' />\ + </g>\ +</svg>"); + + SPDocument *doc = SPDocument::createNewDocFromMem(svg.c_str(), svg.size(), true); + + auto group = dynamic_cast<SPGroup *>(doc->getObjectById("group1")); + Effect::createAndApply(POWERCLIP, doc, group); + + ASSERT_FALSE(group->hasPathEffect()); +} diff --git a/testfiles/src/sp-object-test.cpp b/testfiles/src/sp-object-test.cpp new file mode 100644 index 0000000..713b4b0 --- /dev/null +++ b/testfiles/src/sp-object-test.cpp @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Multiindex container for selection + * + * Authors: + * Adrian Boguszewski + * + * Copyright (C) 2016 Adrian Boguszewski + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include <gtest/gtest.h> +#include <src/object/sp-object.h> +#include <src/object/sp-item.h> +#include <src/xml/node.h> +#include <src/xml/text-node.h> +#include <doc-per-case-test.h> +#include <src/xml/simple-document.h> + +using namespace Inkscape; +using namespace Inkscape::XML; + +class SPObjectTest: public DocPerCaseTest { +public: + SPObjectTest() { + a = new SPItem(); + b = new SPItem(); + c = new SPItem(); + d = new SPItem(); + e = new SPItem(); + auto sd = new SimpleDocument(); + auto et = new TextNode(Util::share_string("e"), sd); + auto dt = new TextNode(Util::share_string("d"), sd); + auto ct = new TextNode(Util::share_string("c"), sd); + auto bt = new TextNode(Util::share_string("b"), sd); + auto at = new TextNode(Util::share_string("a"), sd); + e->invoke_build(_doc, et, 0); + d->invoke_build(_doc, dt, 0); + c->invoke_build(_doc, ct, 0); + b->invoke_build(_doc, bt, 0); + a->invoke_build(_doc, at, 0); + } + ~SPObjectTest() override { + delete e; + delete d; + delete c; + delete b; + delete a; + } + SPObject* a; + SPObject* b; + SPObject* c; + SPObject* d; + SPObject* e; +}; + +TEST_F(SPObjectTest, Basics) { + a->attach(c, a->lastChild()); + a->attach(b, nullptr); + a->attach(d, c); + EXPECT_TRUE(a->hasChildren()); + EXPECT_EQ(b, a->firstChild()); + EXPECT_EQ(d, a->lastChild()); + auto children = a->childList(false); + EXPECT_EQ(3, children.size()); + EXPECT_EQ(b, children[0]); + EXPECT_EQ(c, children[1]); + EXPECT_EQ(d, children[2]); + a->attach(b, a->lastChild()); + EXPECT_EQ(3, a->children.size()); + a->reorder(b, b); + EXPECT_EQ(3, a->children.size()); + EXPECT_EQ(b, &a->children.front()); + EXPECT_EQ(d, &a->children.back()); + a->reorder(b, d); + EXPECT_EQ(3, a->children.size()); + EXPECT_EQ(c, &a->children.front()); + EXPECT_EQ(b, &a->children.back()); + a->reorder(d, nullptr); + EXPECT_EQ(3, a->children.size()); + EXPECT_EQ(d, &a->children.front()); + EXPECT_EQ(b, &a->children.back()); + a->reorder(c, b); + EXPECT_EQ(3, a->children.size()); + EXPECT_EQ(d, &a->children.front()); + EXPECT_EQ(c, &a->children.back()); + a->detach(b); + EXPECT_EQ(c, a->lastChild()); + children = a->childList(false); + EXPECT_EQ(2, children.size()); + EXPECT_EQ(d, children[0]); + EXPECT_EQ(c, children[1]); + a->detach(b); + EXPECT_EQ(2, a->childList(false).size()); + a->releaseReferences(); + EXPECT_FALSE(a->hasChildren()); + EXPECT_EQ(nullptr, a->firstChild()); + EXPECT_EQ(nullptr, a->lastChild()); +} + +TEST_F(SPObjectTest, Advanced) { + a->attach(b, a->lastChild()); + a->attach(c, a->lastChild()); + a->attach(d, a->lastChild()); + a->attach(e, a->lastChild()); + EXPECT_EQ(e, a->get_child_by_repr(e->getRepr())); + EXPECT_EQ(c, a->get_child_by_repr(c->getRepr())); + EXPECT_EQ(d, e->getPrev()); + EXPECT_EQ(c, d->getPrev()); + EXPECT_EQ(b, c->getPrev()); + EXPECT_EQ(nullptr, b->getPrev()); + EXPECT_EQ(nullptr, e->getNext()); + EXPECT_EQ(e, d->getNext()); + EXPECT_EQ(d, c->getNext()); + EXPECT_EQ(c, b->getNext()); + std::vector<SPObject*> tmp = {b, c, d, e}; + int index = 0; + for(auto& child: a->children) { + EXPECT_EQ(tmp[index++], &child); + } +} diff --git a/testfiles/src/style-elem-test.cpp b/testfiles/src/style-elem-test.cpp new file mode 100644 index 0000000..c003e7b --- /dev/null +++ b/testfiles/src/style-elem-test.cpp @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Test the API to the style element, access, read and write functions. + *//* + * + * Authors: + * Martin Owens + * + * Copyright (C) 2018 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include <gtest/gtest.h> +#include <doc-per-case-test.h> + +#include <src/style.h> +#include <src/object/sp-root.h> +#include <src/object/sp-style-elem.h> + +using namespace Inkscape; +using namespace Inkscape::XML; + +class ObjectTest: public DocPerCaseTest { +public: + ObjectTest() { + char const *docString = "\ +<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>\ +<style id='style01'>\ +rect { fill: red; opacity:0.5; }\ +#id1, #id2 { fill: red; stroke: #c0c0c0; }\ +.cls1 { fill: red; opacity:1.0; }\ +</style>\ +<style id='style02'>\ +rect { fill: green; opacity:1.0; }\ +#id3, #id4 { fill: green; stroke: #606060; }\ +.cls2 { fill: green; opacity:0.5; }\ +</style>\ +</svg>"; + doc = SPDocument::createNewDocFromMem(docString, static_cast<int>(strlen(docString)), false); + } + + ~ObjectTest() override { + doc->doUnref(); + } + + SPDocument *doc; +}; + +/* + * Test sp-style-element objects created in document. + */ +TEST_F(ObjectTest, StyleElems) { + ASSERT_TRUE(doc != nullptr); + ASSERT_TRUE(doc->getRoot() != nullptr); + + SPRoot *root = doc->getRoot(); + ASSERT_TRUE(root->getRepr() != nullptr); + + SPStyleElem *one = dynamic_cast<SPStyleElem *>(doc->getObjectById("style01")); + ASSERT_TRUE(one != nullptr); + + for(auto style: one->styles) { + EXPECT_EQ(style->fill.get_value(), Glib::ustring("#ff0000")); + } + + SPStyleElem *two = dynamic_cast<SPStyleElem *>(doc->getObjectById("style02")); + ASSERT_TRUE(one != nullptr); + + for(auto style: two->styles) { + EXPECT_EQ(style->fill.get_value(), Glib::ustring("#008000")); + } +} diff --git a/testfiles/src/style-test.cpp b/testfiles/src/style-test.cpp new file mode 100644 index 0000000..fea2901 --- /dev/null +++ b/testfiles/src/style-test.cpp @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Unit test for style properties. + * + * Author: + * Tavmjong Bah <tavjong@free.fr> + * + * Copyright (C) 2017 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <string> +#include <utility> +#include <vector> + +#include "gtest/gtest.h" + +#include "style.h" + +namespace { + +class StyleRead { + +public: + StyleRead(std::string src, std::string dst, std::string uri) : + src(std::move(src)), dst(std::move(dst)), uri(std::move(uri)) + { + } + + StyleRead(std::string src, std::string dst) : + src(std::move(src)), dst(std::move(dst)), uri("") + { + } + + StyleRead(std::string const &src) : + src(src), dst(src), uri("") + { + } + + std::string src; + std::string dst; + std::string uri; + +}; + +std::vector<StyleRead> getStyleData() +{ + StyleRead all_style_data[] = { + + // Paint ----------------------------------------------- + StyleRead("fill:none"), StyleRead("fill:currentColor"), StyleRead("fill:#ff00ff"), + StyleRead("fill:rgb(100%, 0%, 100%)", "fill:#ff00ff"), StyleRead("fill:rgb(255, 0, 255)", "fill:#ff00ff"), + + // TODO - fix this to preserve the string + // StyleRead("fill:url(#painter) rgb(100%, 0%, 100%)", + // "fill:url(#painter) #ff00ff", "#painter" ), + + // TODO - fix this to preserve the string + // StyleRead("fill:url(#painter) rgb(255, 0, 255)", + // "fill:url(#painter) #ff00ff", "#painter"), + + + StyleRead("fill:#ff00ff icc-color(colorChange, 0.1, 0.5, 0.1)"), + + // StyleRead("fill:url(#painter)", "", "#painter"), + // StyleRead("fill:url(#painter) none", "", "#painter"), + // StyleRead("fill:url(#painter) currentColor", "", "#painter"), + // StyleRead("fill:url(#painter) #ff00ff", "", "#painter"), + // StyleRead("fill:url(#painter) rgb(100%, 0%, 100%)", "", "#painter"), + // StyleRead("fill:url(#painter) rgb(255, 0, 255)", "", "#painter"), + + // StyleRead("fill:url(#painter) #ff00ff icc-color(colorChange, 0.1, 0.5, 0.1)", "", "#painter"), + + // StyleRead("fill:url(#painter) inherit", "", "#painter"), + + StyleRead("fill:inherit"), + + + // General tests (in general order of appearance in sp_style_read), SPIPaint tested above + StyleRead("visibility:hidden"), // SPIEnum + StyleRead("visibility:collapse"), StyleRead("visibility:visible"), + StyleRead("display:none"), // SPIEnum + StyleRead("overflow:visible"), // SPIEnum + StyleRead("overflow:auto"), // SPIEnum + + StyleRead("color:#ff0000"), StyleRead("color:blue", "color:#0000ff"), + // StyleRead("color:currentColor"), SVG 1.1 does not allow color value 'currentColor' + + // Font shorthand + StyleRead("font:bold 12px Arial", "font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;" + "font-size:12px;line-height:normal;font-family:Arial"), + StyleRead("font:bold 12px/24px 'Times New Roman'", + "font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12px;line-" + "height:24px;font-family:\'Times New Roman\'"), + + // From CSS 3 Fonts (examples): + StyleRead("font: 12pt/15pt sans-serif", "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:" + "normal;font-size:16px;line-height:15pt;font-family:sans-serif"), + // StyleRead("font: 80% sans-serif", + // "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80%;line-height:normal;font-family:sans-serif"), + // StyleRead("font: x-large/110% 'new century schoolbook', serif", + // "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:x-large;line-height:110%;font-family:\'new + //century schoolbook\', serif"), + StyleRead("font: bold italic large Palatino, serif", + "font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:large;line-" + "height:normal;font-family:Palatino, serif"), + // StyleRead("font: normal small-caps 120%/120% fantasy", + // "font-style:normal;font-variant:small-caps;font-weight:normal;font-stretch:normal;font-size:120%;line-height:120%;font-family:fantasy"), + StyleRead("font: condensed oblique 12pt 'Helvetica Neue', serif;", + "font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:16px;" + "line-height:normal;font-family:\'Helvetica Neue\', serif"), + + StyleRead("font-family:sans-serif"), // SPIString, text_private + StyleRead("font-family:Arial"), + // StyleRead("font-variant:normal;font-stretch:normal;-inkscape-font-specification:Nimbus Roman No9 L Bold + // Italic"), + + // Needs to be fixed (quotes should be around each font-family): + StyleRead("font-family:Georgia, 'Minion Web'", "font-family:Georgia, \'Minion Web\'"), + StyleRead("font-size:12", "font-size:12px"), // SPIFontSize + StyleRead("font-size:12px"), StyleRead("font-size:12pt", "font-size:16px"), StyleRead("font-size:medium"), + StyleRead("font-size:smaller"), + StyleRead("font-style:italic"), // SPIEnum + StyleRead("font-variant:small-caps"), // SPIEnum + StyleRead("font-weight:100"), // SPIEnum + StyleRead("font-weight:normal"), StyleRead("font-weight:bolder"), + StyleRead("font-stretch:condensed"), // SPIEnum + + StyleRead("font-variant-ligatures:none"), // SPILigatures + StyleRead("font-variant-ligatures:normal"), StyleRead("font-variant-ligatures:no-common-ligatures"), + StyleRead("font-variant-ligatures:discretionary-ligatures"), + StyleRead("font-variant-ligatures:historical-ligatures"), StyleRead("font-variant-ligatures:no-contextual"), + StyleRead("font-variant-ligatures:common-ligatures", "font-variant-ligatures:normal"), + StyleRead("font-variant-ligatures:contextual", "font-variant-ligatures:normal"), + StyleRead("font-variant-ligatures:no-common-ligatures historical-ligatures"), + StyleRead("font-variant-ligatures:historical-ligatures no-contextual"), + StyleRead("font-variant-position:normal"), StyleRead("font-variant-position:sub"), + StyleRead("font-variant-position:super"), StyleRead("font-variant-caps:normal"), + StyleRead("font-variant-caps:small-caps"), StyleRead("font-variant-caps:all-small-caps"), + StyleRead("font-variant-numeric:normal"), StyleRead("font-variant-numeric:lining-nums"), + StyleRead("font-variant-numeric:oldstyle-nums"), StyleRead("font-variant-numeric:proportional-nums"), + StyleRead("font-variant-numeric:tabular-nums"), StyleRead("font-variant-numeric:diagonal-fractions"), + StyleRead("font-variant-numeric:stacked-fractions"), StyleRead("font-variant-numeric:ordinal"), + StyleRead("font-variant-numeric:slashed-zero"), StyleRead("font-variant-numeric:tabular-nums slashed-zero"), + StyleRead("font-variant-numeric:tabular-nums proportional-nums", "font-variant-numeric:proportional-nums"), + + StyleRead("font-variation-settings:'wght' 400"), + StyleRead("font-variation-settings:'wght' 400", "font-variation-settings:'wght' 400"), + StyleRead("font-variation-settings:'wght' 400, 'slnt' 0.5", "font-variation-settings:'slnt' 0.5, 'wght' 400"), + + // Should be moved down + StyleRead("text-indent:12em"), // SPILength? + StyleRead("text-align:center"), // SPIEnum + + // SPITextDecoration + // The default value for 'text-decoration-color' is 'currentColor', but + // we cannot set the default to that value yet. (We need to switch + // SPIPaint to SPIColor and then add the ability to set default.) + // StyleRead("text-decoration: underline", + // "text-decoration: underline;text-decoration-line: underline;text-decoration-color:currentColor"), + // StyleRead("text-decoration: overline underline", + // "text-decoration: underline overline;text-decoration-line: underline + // overline;text-decoration-color:currentColor"), + + StyleRead("text-decoration: underline wavy #0000ff", + "text-decoration: underline;text-decoration-line: " + "underline;text-decoration-style:wavy;text-decoration-color:#0000ff"), + StyleRead("text-decoration: double overline underline #ff0000", + "text-decoration: underline overline;text-decoration-line: underline " + "overline;text-decoration-style:double;text-decoration-color:#ff0000"), + + // SPITextDecorationLine + StyleRead("text-decoration-line: underline", "text-decoration: underline;text-decoration-line: underline"), + + // SPITextDecorationStyle + StyleRead("text-decoration-style:solid"), StyleRead("text-decoration-style:dotted"), + + // SPITextDecorationColor + StyleRead("text-decoration-color:#ff00ff"), + + // Should be moved up + StyleRead("line-height:24px"), // SPILengthOrNormal + StyleRead("line-height:1.5"), + StyleRead("letter-spacing:2px"), // SPILengthOrNormal + StyleRead("word-spacing:2px"), // SPILengthOrNormal + StyleRead("word-spacing:normal"), + StyleRead("text-transform:lowercase"), // SPIEnum + // ... + StyleRead("baseline-shift:baseline"), // SPIBaselineShift + StyleRead("baseline-shift:sub"), StyleRead("baseline-shift:12.5%"), StyleRead("baseline-shift:2px"), + + StyleRead("opacity:0.1"), // SPIScale24 + // ... + StyleRead("stroke-width:2px"), // SPILength + StyleRead("stroke-linecap:round"), // SPIEnum + StyleRead("stroke-linejoin:round"), // SPIEnum + StyleRead("stroke-miterlimit:4"), // SPIFloat + StyleRead("marker:url(#Arrow)"), // SPIString + StyleRead("marker-start:url(#Arrow)"), StyleRead("marker-mid:url(#Arrow)"), StyleRead("marker-end:url(#Arrow)"), + StyleRead("stroke-opacity:0.5"), // SPIScale24 + // Currently inkscape handle unit conversion in dasharray but need + // a active document to do it, so we can't include in any test + StyleRead("stroke-dasharray:0, 1, 0, 1"), // SPIDashArray + StyleRead("stroke-dasharray:0 1 0 1", "stroke-dasharray:0, 1, 0, 1"), + StyleRead("stroke-dasharray:0 1 2 3", "stroke-dasharray:0, 1, 2, 3"), + StyleRead("stroke-dashoffset:13"), // SPILength + StyleRead("stroke-dashoffset:10px"), + // ... + // StyleRead("filter:url(#myfilter)"), // SPIFilter segfault in read + StyleRead("filter:inherit"), + + StyleRead("opacity:0.1;fill:#ff0000;stroke:#0000ff;stroke-width:2px"), + StyleRead("opacity:0.1;fill:#ff0000;stroke:#0000ff;stroke-width:2px;stroke-dasharray:1, 2, 3, " + "4;stroke-dashoffset:15"), + + StyleRead("paint-order:stroke"), // SPIPaintOrder + StyleRead("paint-order:normal"), + StyleRead("paint-order: markers stroke fill", "paint-order:markers stroke fill"), + + // !important (in order of appearance in style-internal.h) + StyleRead("stroke-miterlimit:4 !important"), // SPIFloat + StyleRead("stroke-opacity:0.5 !important"), // SPIScale24 + StyleRead("stroke-width:2px !important"), // SPILength + StyleRead("line-height:24px !important"), // SPILengthOrNormal + StyleRead("line-height:normal !important"), + StyleRead("font-stretch:condensed !important"), // SPIEnum + StyleRead("marker:url(#Arrow) !important"), // SPIString + StyleRead("color:#0000ff !important"), // SPIColor + StyleRead("fill:none !important"), // SPIPaint + StyleRead("fill:currentColor !important"), StyleRead("fill:#ff00ff !important"), + StyleRead("paint-order:stroke !important"), // SPIPaintOrder + StyleRead("paint-order:normal !important"), + StyleRead("stroke-dasharray:0, 1, 0, 1 !important"), // SPIDashArray + StyleRead("font-size:12px !important"), // SPIFontSize + StyleRead("baseline-shift:baseline !important"), // SPIBaselineShift + StyleRead("baseline-shift:sub !important"), + // StyleRead("text-decoration-line: underline !important"), // SPITextDecorationLine + + }; + + size_t count = sizeof(all_style_data) / sizeof(all_style_data[0]); + std::vector<StyleRead> vect(all_style_data, all_style_data + count); + return vect; +} + +TEST(StyleTest, Read) { + std::vector<StyleRead> all_style = getStyleData(); + EXPECT_GT(all_style.size(), 0); + for (auto i : all_style) { + + SPStyle style; + style.mergeString (i.src.c_str()); + + if (!i.uri.empty()) { + //EXPECT_EQ (style.fill.value.href->getURI()->toString(), i.uri); + } + + std::string out = style.write(); + if (i.dst.empty()) { + // std::cout << "out: " << out << std::endl; + // std::cout << "i.src: " << i.src << std::endl; + EXPECT_EQ (out, i.src); + } else { + // std::cout << "out: " << out << std::endl; + // std::cout << "i.dst: " << i.dst << std::endl; + EXPECT_EQ (out, i.dst); + } + } +} + + +// ------------------------------------------------------------------------------------ + +class StyleMatch { + +public: + StyleMatch(std::string src, std::string dst, bool const &match) : + src(std::move(src)), dst(std::move(dst)), match(match) + { + } + + std::string src; + std::string dst; + bool match; + +}; + +std::vector<StyleMatch> getStyleMatchData() +{ + StyleMatch all_style_data[] = { + + // SPIFloat + StyleMatch("stroke-miterlimit:4", "stroke-miterlimit:4", true ), + StyleMatch("stroke-miterlimit:4", "stroke-miterlimit:2", false), + StyleMatch("stroke-miterlimit:4", "", true ), // Default + + // SPIScale24 + StyleMatch("opacity:0.3", "opacity:0.3", true ), + StyleMatch("opacity:0.3", "opacity:0.6", false), + StyleMatch("opacity:1.0", "", true ), // Default + + // SPILength + StyleMatch("text-indent:3", "text-indent:3", true ), + StyleMatch("text-indent:6", "text-indent:3", false), + StyleMatch("text-indent:6px", "text-indent:3", false), + StyleMatch("text-indent:1px", "text-indent:12pc", false), + StyleMatch("text-indent:2ex", "text-indent:2ex", false), + + // SPILengthOrNormal + StyleMatch("letter-spacing:normal", "letter-spacing:normal", true ), + StyleMatch("letter-spacing:2", "letter-spacing:normal", false), + StyleMatch("letter-spacing:normal", "letter-spacing:2", false), + StyleMatch("letter-spacing:5px", "letter-spacing:5px", true ), + StyleMatch("letter-spacing:10px", "letter-spacing:5px", false), + StyleMatch("letter-spacing:10em", "letter-spacing:10em", false), + + // SPIEnum + StyleMatch("text-anchor:start", "text-anchor:start", true ), + StyleMatch("text-anchor:start", "text-anchor:middle", false), + StyleMatch("text-anchor:start", "", true ), // Default + StyleMatch("text-anchor:start", "text-anchor:junk", true ), // Bad value + + StyleMatch("font-weight:normal", "font-weight:400", true ), + StyleMatch("font-weight:bold", "font-weight:700", true ), + + + // SPIString and SPIFontString + StyleMatch("font-family:Arial", "font-family:Arial", true ), + StyleMatch("font-family:A B", "font-family:A B", true ), + StyleMatch("font-family:A B", "font-family:A C", false), + // Default is not set by class... value is NULL which cannot be compared + // StyleMatch("font-family:sans-serif", "", true ), // Default + + // SPIColor + StyleMatch("color:blue", "color:blue", true ), + StyleMatch("color:blue", "color:red", false), + StyleMatch("color:red", "color:#ff0000", true ), + + // SPIPaint + StyleMatch("fill:blue", "fill:blue", true ), + StyleMatch("fill:blue", "fill:red", false), + StyleMatch("fill:currentColor", "fill:currentColor", true ), + StyleMatch("fill:url(#xxx)", "fill:url(#xxx)", true ), + // Needs URL defined as in test 1 + //StyleMatch("fill:url(#xxx)", "fill:url(#yyy)", false), + + // SPIPaintOrder + StyleMatch("paint-order:markers", "paint-order:markers", true ), + StyleMatch("paint-order:markers", "paint-order:stroke", false), + //StyleMatch("paint-order:fill stroke markers", "", true ), // Default + StyleMatch("paint-order:normal", "paint-order:normal", true ), + //StyleMatch("paint-order:fill stroke markers", "paint-order:normal", true ), + + // SPIDashArray + StyleMatch("stroke-dasharray:0 1 2 3","stroke-dasharray:0 1 2 3",true ), + StyleMatch("stroke-dasharray:0 1", "stroke-dasharray:0 2", false), + + // SPIFilter + + // SPIFontSize + StyleMatch("font-size:12px", "font-size:12px", true ), + StyleMatch("font-size:12px", "font-size:24px", false), + StyleMatch("font-size:12ex", "font-size:24ex", false), + StyleMatch("font-size:medium", "font-size:medium", true ), + StyleMatch("font-size:medium", "font-size:large", false), + + // SPIBaselineShift + StyleMatch("baseline-shift:baseline", "baseline-shift:baseline", true ), + StyleMatch("baseline-shift:sub", "baseline-shift:sub", true ), + StyleMatch("baseline-shift:sub", "baseline-shift:super", false), + StyleMatch("baseline-shift:baseline", "baseline-shift:sub", false), + StyleMatch("baseline-shift:10px", "baseline-shift:10px", true ), + StyleMatch("baseline-shift:10px", "baseline-shift:12px", false), + + + // SPITextDecorationLine + StyleMatch("text-decoration-line:underline", "text-decoration-line:underline", true ), + StyleMatch("text-decoration-line:underline", "text-decoration-line:overline", false), + StyleMatch("text-decoration-line:underline overline", "text-decoration-line:underline overline", true ), + StyleMatch("text-decoration-line:none", "", true ), // Default + + + // SPITextDecorationStyle + StyleMatch("text-decoration-style:solid", "text-decoration-style:solid", true ), + StyleMatch("text-decoration-style:dotted", "text-decoration-style:solid", false), + StyleMatch("text-decoration-style:solid", "", true ), // Default + + // SPITextDecoration + StyleMatch("text-decoration:underline", "text-decoration:underline", true ), + StyleMatch("text-decoration:underline", "text-decoration:overline", false), + StyleMatch("text-decoration:underline overline","text-decoration:underline overline",true ), + StyleMatch("text-decoration:overline underline","text-decoration:underline overline",true ), + // StyleMatch("text-decoration:none", "text-decoration-color:currentColor", true ), // Default + + }; + + size_t count = sizeof(all_style_data) / sizeof(all_style_data[0]); + std::vector<StyleMatch> vect(all_style_data, all_style_data + count); + return vect; +} + +TEST(StyleTest, Match) { + std::vector<StyleMatch> all_style = getStyleMatchData(); + EXPECT_GT(all_style.size(), 0); + for (auto i : all_style) { + + SPStyle style_src; + SPStyle style_dst; + + style_src.mergeString( i.src.c_str() ); + style_dst.mergeString( i.dst.c_str() ); + + // std::cout << "Test:" << std::endl; + // std::cout << " C: |" << i.src + // << "| |" << i.dst << "|" << std::endl; + // std::cout << " S: |" << style_src.write( SP_STYLE_FLAG_IFSET ) + // << "| |" << style_dst.write( SP_STYLE_FLAG_IFSET ) << "|" <<std::endl; + + EXPECT_TRUE( (style_src == style_dst) == i.match ); + } +} + +// ------------------------------------------------------------------------------------ + +class StyleCascade { + +public: + StyleCascade(std::string parent, std::string child, std::string result) : + parent(std::move(parent)), child(std::move(child)), result(std::move(result)) + { + } + + std::string parent; + std::string child; + std::string result; + +}; + +std::vector<StyleCascade> getStyleCascadeData() +{ + + StyleCascade all_style_data[] = { + + // SPIFloat + StyleCascade("stroke-miterlimit:6", "stroke-miterlimit:2", "stroke-miterlimit:2" ), + StyleCascade("stroke-miterlimit:6", "", "stroke-miterlimit:6" ), + StyleCascade("", "stroke-miterlimit:2", "stroke-miterlimit:2" ), + + // SPIScale24 + StyleCascade("opacity:0.3", "opacity:0.3", "opacity:0.3" ), + StyleCascade("opacity:0.3", "opacity:0.6", "opacity:0.6" ), + // 'opacity' does not inherit + StyleCascade("opacity:0.3", "", "opacity:1.0" ), + StyleCascade("", "opacity:0.3", "opacity:0.3" ), + StyleCascade("opacity:0.5", "opacity:inherit", "opacity:0.5" ), + StyleCascade("", "", "opacity:1.0" ), + + // SPILength + StyleCascade("text-indent:3", "text-indent:3", "text-indent:3" ), + StyleCascade("text-indent:6", "text-indent:3", "text-indent:3" ), + StyleCascade("text-indent:6px", "text-indent:3", "text-indent:3" ), + StyleCascade("text-indent:1px", "text-indent:12pc", "text-indent:12pc" ), + // ex, em cannot be equal + //StyleCascade("text-indent:2ex", "text-indent:2ex", "text-indent:2ex" ), + StyleCascade("text-indent:3", "", "text-indent:3" ), + StyleCascade("text-indent:3", "text-indent:inherit", "text-indent:3" ), + + // SPILengthOrNormal + StyleCascade("letter-spacing:normal", "letter-spacing:normal", "letter-spacing:normal" ), + StyleCascade("letter-spacing:2", "letter-spacing:normal", "letter-spacing:normal" ), + StyleCascade("letter-spacing:normal", "letter-spacing:2", "letter-spacing:2" ), + StyleCascade("letter-spacing:5px", "letter-spacing:5px", "letter-spacing:5px" ), + StyleCascade("letter-spacing:10px", "letter-spacing:5px", "letter-spacing:5px" ), + // ex, em cannot be equal + // StyleCascade("letter-spacing:10em", "letter-spacing:10em", "letter-spacing:10em" ), + + // SPIEnum + StyleCascade("text-anchor:start", "text-anchor:start", "text-anchor:start" ), + StyleCascade("text-anchor:start", "text-anchor:middle", "text-anchor:middle" ), + StyleCascade("text-anchor:start", "", "text-anchor:start" ), + StyleCascade("text-anchor:start", "text-anchor:junk", "text-anchor:start" ), + StyleCascade("text-anchor:end", "text-anchor:inherit", "text-anchor:end" ), + + StyleCascade("font-weight:400", "font-weight:400", "font-weight:400" ), + StyleCascade("font-weight:400", "font-weight:700", "font-weight:700" ), + StyleCascade("font-weight:400", "font-weight:bolder", "font-weight:700" ), + StyleCascade("font-weight:700", "font-weight:bolder", "font-weight:900" ), + StyleCascade("font-weight:400", "font-weight:lighter", "font-weight:100" ), + StyleCascade("font-weight:200", "font-weight:lighter", "font-weight:100" ), + + StyleCascade("font-stretch:condensed","font-stretch:expanded", "font-stretch:expanded" ), + StyleCascade("font-stretch:condensed","font-stretch:wider", "font-stretch:semi-condensed" ), + + // SPIString and SPIFontString + + StyleCascade("font-variation-settings:'wght' 400", "", "font-variation-settings:'wght' 400"), + StyleCascade("font-variation-settings:'wght' 100", + "font-variation-settings:'wght' 400", + "font-variation-settings:'wght' 400"), + + // SPIPaint + + // SPIPaintOrder + + // SPIDashArray + + // SPIFilter + + // SPIFontSize + + // SPIBaselineShift + + + // SPITextDecorationLine + StyleCascade("text-decoration-line:overline", "text-decoration-line:underline", + "text-decoration-line:underline" ), + + // SPITextDecorationStyle + + // SPITextDecoration + }; + + size_t count = sizeof(all_style_data) / sizeof(all_style_data[0]); + std::vector<StyleCascade> vect(all_style_data, all_style_data + count); + return vect; + +} + +TEST(StyleTest, Cascade) { + std::vector<StyleCascade> all_style = getStyleCascadeData(); + EXPECT_GT(all_style.size(), 0); + for (auto i : all_style) { + + SPStyle style_parent; + SPStyle style_child; + SPStyle style_result; + + style_parent.mergeString( i.parent.c_str() ); + style_child.mergeString( i.child.c_str() ); + style_result.mergeString( i.result.c_str() ); + + // std::cout << "Test:" << std::endl; + // std::cout << " Input: "; + // std::cout << " Parent: " << i.parent + // << " Child: " << i.child + // << " Result: " << i.result << std::endl; + // std::cout << " Write: "; + // std::cout << " Parent: " << style_parent.write( SP_STYLE_FLAG_IFSET ) + // << " Child: " << style_child.write( SP_STYLE_FLAG_IFSET ) + // << " Result: " << style_result.write( SP_STYLE_FLAG_IFSET ) << std::endl; + + style_child.cascade( &style_parent ); + + EXPECT_TRUE(style_child == style_result ); + } +} + + +} // namespace + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/testfiles/src/svg-stringstream-test.cpp b/testfiles/src/svg-stringstream-test.cpp new file mode 100644 index 0000000..636b018 --- /dev/null +++ b/testfiles/src/svg-stringstream-test.cpp @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * Test CSSOStringStream and SVGOStringStream + */ +/* + * Authors: + * Thomas Holder + * + * Copyright (C) 2019 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "2geom/point.h" +#include "svg/css-ostringstream.h" +#include "svg/stringstream.h" + +#include "gtest/gtest.h" +#include <glibmm/ustring.h> + +template <typename S, typename T> +static void assert_tostring_eq(T value, const char *expected) +{ + S os; + + // default of /options/svgoutput/numericprecision + os.precision(8); + + os << value; + ASSERT_EQ(os.str(), expected); +} + +#define TEST_STRING "Hello & <World>" + +template <typename S> +void test_tostring() +{ + assert_tostring_eq<S, char>('A', "A"); + assert_tostring_eq<S, signed char>('A', "A"); + assert_tostring_eq<S, unsigned char>('A', "A"); + + assert_tostring_eq<S, short>(0x7FFF, "32767"); + assert_tostring_eq<S, short>(-30000, "-30000"); + assert_tostring_eq<S, unsigned short>(0xFFFFu, "65535"); + assert_tostring_eq<S, int>(0x7FFFFFFF, "2147483647"); + assert_tostring_eq<S, int>(-2000000000, "-2000000000"); + assert_tostring_eq<S, unsigned int>(0xFFFFFFFFu, "4294967295"); + + // long is 32bit on Windows, 64bit on Linux + assert_tostring_eq<S, long>(0x7FFFFFFFL, "2147483647"); + assert_tostring_eq<S, long>(-2000000000L, "-2000000000"); + assert_tostring_eq<S, unsigned long>(0xFFFFFFFFuL, "4294967295"); + + assert_tostring_eq<S>((char const *)TEST_STRING, TEST_STRING); + assert_tostring_eq<S>((signed char const *)TEST_STRING, TEST_STRING); + assert_tostring_eq<S>((unsigned char const *)TEST_STRING, TEST_STRING); + assert_tostring_eq<S, std::string>(TEST_STRING, TEST_STRING); + assert_tostring_eq<S, Glib::ustring>(TEST_STRING, TEST_STRING); +} + +TEST(CSSOStringStreamTest, tostring) +{ + using S = Inkscape::CSSOStringStream; + + test_tostring<S>(); + + // float has 6 significant digits + assert_tostring_eq<S, float>(0.0, "0"); + assert_tostring_eq<S, float>(4.5, "4.5"); + assert_tostring_eq<S, float>(-4.0, "-4"); + assert_tostring_eq<S, float>(0.001, "0.001"); + assert_tostring_eq<S, float>(0.00123456, "0.00123456"); + assert_tostring_eq<S, float>(-0.00123456, "-0.00123456"); + assert_tostring_eq<S, float>(-1234560.0, "-1234560"); + + // double has 15 significant digits + assert_tostring_eq<S, double>(0.0, "0"); + assert_tostring_eq<S, double>(4.5, "4.5"); + assert_tostring_eq<S, double>(-4.0, "-4"); + assert_tostring_eq<S, double>(0.001, "0.001"); + + // 9 significant digits + assert_tostring_eq<S, double>(1.23456789, "1.23456789"); + assert_tostring_eq<S, double>(-1.23456789, "-1.23456789"); + assert_tostring_eq<S, double>(12345678.9, "12345678.9"); + assert_tostring_eq<S, double>(-12345678.9, "-12345678.9"); + + assert_tostring_eq<S, double>(1.234e-12, "0"); + assert_tostring_eq<S, double>(3e9, "3000000000"); + assert_tostring_eq<S, double>(-3.5e9, "-3500000000"); +} + +TEST(SVGOStringStreamTest, tostring) +{ + using S = Inkscape::SVGOStringStream; + + test_tostring<S>(); + + assert_tostring_eq<S>(Geom::Point(12, 3.4), "12,3.4"); + + // float has 6 significant digits + assert_tostring_eq<S, float>(0.0, "0"); + assert_tostring_eq<S, float>(4.5, "4.5"); + assert_tostring_eq<S, float>(-4.0, "-4"); + assert_tostring_eq<S, float>(0.001, "0.001"); + assert_tostring_eq<S, float>(0.00123456, "0.00123456"); + assert_tostring_eq<S, float>(-0.00123456, "-0.00123456"); + assert_tostring_eq<S, float>(-1234560.0, "-1234560"); + + // double has 15 significant digits + assert_tostring_eq<S, double>(0.0, "0"); + assert_tostring_eq<S, double>(4.5, "4.5"); + assert_tostring_eq<S, double>(-4.0, "-4"); + assert_tostring_eq<S, double>(0.001, "0.001"); + + // 8 significant digits + assert_tostring_eq<S, double>(1.23456789, "1.2345679"); + assert_tostring_eq<S, double>(-1.23456789, "-1.2345679"); + assert_tostring_eq<S, double>(12345678.9, "12345679"); + assert_tostring_eq<S, double>(-12345678.9, "-12345679"); + + assert_tostring_eq<S, double>(1.234e-12, "1.234e-12"); + assert_tostring_eq<S, double>(3e9, "3e+09"); + assert_tostring_eq<S, double>(-3.5e9, "-3.5e+09"); +} + +template <typename S> +void test_concat() +{ + S s; + s << "hello, "; + s << -53.5; + ASSERT_EQ(s.str(), std::string("hello, -53.5")); +} + +TEST(CSSOStringStreamTest, concat) +{ // + test_concat<Inkscape::CSSOStringStream>(); +} + +TEST(SVGOStringStreamTest, concat) +{ // + test_concat<Inkscape::SVGOStringStream>(); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/uri-test.cpp b/testfiles/src/uri-test.cpp new file mode 100644 index 0000000..91af2e7 --- /dev/null +++ b/testfiles/src/uri-test.cpp @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * Test Inkscape::URI + */ +/* + * Authors: + * Thomas Holder + * + * Copyright (C) 2018 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "object/uri.h" +#include "gtest/gtest.h" + +using Inkscape::URI; + +#define BASE64_HELLO_WORLD_P1 "SGVsbG8g" +#define BASE64_HELLO_WORLD_P2 "V29ybGQ=" +#define DATA_BASE64_HEADER "data:text/plain;charset=utf-8;base64," +char const *DATA_BASE64_HELLO_WORLD = DATA_BASE64_HEADER BASE64_HELLO_WORLD_P1 BASE64_HELLO_WORLD_P2; +char const *DATA_BASE64_HELLO_WORLD_WRAPPED = DATA_BASE64_HEADER BASE64_HELLO_WORLD_P1 "\n" BASE64_HELLO_WORLD_P2; + +char const *win_url_unc = "file://laptop/My%20Documents/FileSchemeURIs.doc"; +char const *win_url_local = "file:///C:/Documents%20and%20Settings/davris/FileSchemeURIs.doc"; +char const *win_filename_local = "C:\\Documents and Settings\\davris\\FileSchemeURIs.doc"; + +TEST(UriTest, Malformed) +{ + ASSERT_ANY_THROW(URI(nullptr)); + ASSERT_ANY_THROW(URI("nonhex-%XX")); +} + +TEST(UriTest, GetPath) +{ + ASSERT_STREQ(URI().getPath(), nullptr); + ASSERT_STREQ(URI("foo.svg").getPath(), "foo.svg"); + ASSERT_STREQ(URI("foo.svg#bar").getPath(), "foo.svg"); + ASSERT_STREQ(URI("#bar").getPath(), nullptr); + ASSERT_STREQ(URI("scheme://host").getPath(), nullptr); + ASSERT_STREQ(URI("scheme://host/path").getPath(), "/path"); + ASSERT_STREQ(URI("scheme://host/path?query").getPath(), "/path"); + ASSERT_STREQ(URI("scheme:/path").getPath(), "/path"); +} + +TEST(UriTest, FromDir) +{ +#ifdef _WIN32 + ASSERT_EQ(URI::from_dirname("C:\\tmp").str(), "file:///C:/tmp/"); + ASSERT_EQ(URI::from_dirname("C:\\").str(), "file:///C:/"); + ASSERT_EQ(URI::from_href_and_basedir("uri.svg", "C:\\tmp").str(), "file:///C:/tmp/uri.svg"); +#else + ASSERT_EQ(URI::from_dirname("/").str(), "file:///"); + ASSERT_EQ(URI::from_dirname("/tmp").str(), "file:///tmp/"); + ASSERT_EQ(URI::from_href_and_basedir("uri.svg", "/tmp").str(), "file:///tmp/uri.svg"); +#endif +} + +TEST(UriTest, Str) +{ + ASSERT_EQ(URI().str(), ""); + ASSERT_EQ(URI("").str(), ""); + ASSERT_EQ(URI("", "http://a/b").str(), "http://a/b"); + + ASSERT_EQ(URI("uri.svg").str(), "uri.svg"); + ASSERT_EQ(URI("tmp/uri.svg").str(), "tmp/uri.svg"); + ASSERT_EQ(URI("/tmp/uri.svg").str(), "/tmp/uri.svg"); + ASSERT_EQ(URI("../uri.svg").str(), "../uri.svg"); + + ASSERT_EQ(URI("file:///tmp/uri.svg").str(), "file:///tmp/uri.svg"); + ASSERT_EQ(URI("uri.svg", "file:///tmp/").str(), "file:///tmp/uri.svg"); + ASSERT_EQ(URI("file:///tmp/uri.svg").str("file:///tmp/"), "uri.svg"); + ASSERT_EQ(URI("file:///tmp/up/uri.svg").str("file:///tmp/"), "up/uri.svg"); + ASSERT_EQ(URI("file:///tmp/uri.svg").str("file:///tmp/up/"), "../uri.svg"); + ASSERT_EQ(URI("file:///tmp/uri.svg").str("http://web/url"), "file:///tmp/uri.svg"); + ASSERT_EQ(URI("file:///tmp/uri.svg").str("http://web/url"), "file:///tmp/uri.svg"); + ASSERT_EQ(URI("foo/uri.svg", "http://web/a/b/c").str(), "http://web/a/b/foo/uri.svg"); + ASSERT_EQ(URI("foo/uri.svg", "http://web/a/b/c").str("http://web/a/"), "b/foo/uri.svg"); + ASSERT_EQ(URI("foo/uri.svg", "http://web/a/b/c").str("http://other/a/"), "http://web/a/b/foo/uri.svg"); + + ASSERT_EQ(URI("http://web/").str("http://web/"), ""); + ASSERT_EQ(URI("http://web/").str("http://web/url"), "./"); + + // special case: don't cross filesystem root + ASSERT_EQ(URI("file:///a").str("file:///"), "a"); + ASSERT_EQ(URI("file:///ax/b").str("file:///ay/"), "file:///ax/b"); // special case + ASSERT_EQ(URI("file:///C:/b").str("file:///D:/"), "file:///C:/b"); // special case + ASSERT_EQ(URI("file:///C:/a/b").str("file:///C:/b/"), "../a/b"); + + ASSERT_EQ(URI(win_url_unc).str(), win_url_unc); + ASSERT_EQ(URI(win_url_unc).str("file://laptop/My%20Documents/"), "FileSchemeURIs.doc"); + ASSERT_EQ(URI(win_url_local).str(), win_url_local); + ASSERT_EQ(URI(win_url_local).str("file:///C:/Documents%20and%20Settings/"), "davris/FileSchemeURIs.doc"); + ASSERT_EQ(URI(win_url_local).str(win_url_unc), win_url_local); +#ifdef _WIN32 + ASSERT_EQ(URI(win_url_local).toNativeFilename(), win_filename_local); +#else + ASSERT_EQ(URI("file:///tmp/uri.svg").toNativeFilename(), "/tmp/uri.svg"); + ASSERT_EQ(URI("file:///tmp/x%20y.svg").toNativeFilename(), "/tmp/x y.svg"); + ASSERT_EQ(URI("file:///a/b#hash").toNativeFilename(), "/a/b"); +#endif + + ASSERT_ANY_THROW(URI("http://a/b").toNativeFilename()); +} + +TEST(UriTest, StrDataScheme) +{ + ASSERT_EQ(URI("data:,text").str(), "data:,text"); + ASSERT_EQ(URI("data:,white%20space").str(), "data:,white%20space"); + ASSERT_EQ(URI("data:,umlaut-%C3%96").str(), "data:,umlaut-%C3%96"); + ASSERT_EQ(URI(DATA_BASE64_HELLO_WORLD).str(), DATA_BASE64_HELLO_WORLD); +} + +TEST(UriTest, Escape) +{ + ASSERT_EQ(URI("data:,white space").str(), "data:,white%20space"); + ASSERT_EQ(URI("data:,white\nspace").str(), "data:,white%0Aspace"); + ASSERT_EQ(URI("data:,umlaut-\xC3\x96").str(), "data:,umlaut-%C3%96"); +} + +TEST(UriTest, GetContents) +{ + ASSERT_EQ(URI("data:,white space").getContents(), "white space"); + ASSERT_EQ(URI("data:,white%20space").getContents(), "white space"); + ASSERT_EQ(URI("data:,white\nspace").getContents(), "white\nspace"); + ASSERT_EQ(URI("data:,white%0Aspace").getContents(), "white\nspace"); + ASSERT_EQ(URI("data:,umlaut-%C3%96").getContents(), "umlaut-\xC3\x96"); + ASSERT_EQ(URI(DATA_BASE64_HELLO_WORLD).getContents(), "Hello World"); + ASSERT_EQ(URI(DATA_BASE64_HELLO_WORLD_WRAPPED).getContents(), "Hello World"); + + ASSERT_ANY_THROW(URI().getContents()); +} + +TEST(UriTest, CssStr) +{ + ASSERT_EQ(URI("file:///tmp/uri.svg").cssStr(), "url(file:///tmp/uri.svg)"); + ASSERT_EQ(URI("uri.svg").cssStr(), "url(uri.svg)"); +} + +TEST(UriTest, GetMimeType) +{ + ASSERT_EQ(URI("data:image/png;base64,").getMimeType(), "image/png"); + ASSERT_EQ(URI("data:text/plain,xxx").getMimeType(), "text/plain"); + ASSERT_EQ(URI("file:///tmp/uri.png").getMimeType(), "image/png"); + ASSERT_EQ(URI("uri.png").getMimeType(), "image/png"); + ASSERT_EQ(URI("uri.svg").getMimeType(), "image/svg+xml"); + + // can be "text/plain" or "text/*" + ASSERT_EQ(URI("file:///tmp/uri.txt").getMimeType().substr(0, 5), "text/"); +} + +TEST(UriTest, HasScheme) +{ + ASSERT_FALSE(URI().hasScheme("file")); + ASSERT_FALSE(URI("uri.svg").hasScheme("file")); + ASSERT_FALSE(URI("uri.svg").hasScheme("data")); + + ASSERT_TRUE(URI("file:///uri.svg").hasScheme("file")); + ASSERT_TRUE(URI("FILE:///uri.svg").hasScheme("file")); + ASSERT_FALSE(URI("file:///uri.svg").hasScheme("data")); + + ASSERT_TRUE(URI("data:,").hasScheme("data")); + ASSERT_TRUE(URI("DaTa:,").hasScheme("data")); + ASSERT_FALSE(URI("data:,").hasScheme("file")); + + ASSERT_TRUE(URI("http://web/").hasScheme("http")); + ASSERT_FALSE(URI("http://web/").hasScheme("file")); + + ASSERT_TRUE(URI::from_href_and_basedir("data:,white\nspace", "/tmp").hasScheme("data")); +} + +TEST(UriTest, isOpaque) +{ + ASSERT_FALSE(URI().isOpaque()); + ASSERT_FALSE(URI("file:///uri.svg").isOpaque()); + ASSERT_FALSE(URI("/uri.svg").isOpaque()); + ASSERT_FALSE(URI("uri.svg").isOpaque()); + ASSERT_FALSE(URI("foo://bar/baz").isOpaque()); + ASSERT_FALSE(URI("foo://bar").isOpaque()); + ASSERT_FALSE(URI("foo:/bar").isOpaque()); + + ASSERT_TRUE(URI("foo:bar").isOpaque()); + ASSERT_TRUE(URI("mailto:user@host.xy").isOpaque()); + ASSERT_TRUE(URI("news:comp.lang.java").isOpaque()); +} + +TEST(UriTest, isRelative) +{ + ASSERT_TRUE(URI().isRelative()); + + ASSERT_FALSE(URI("http://web/uri.svg").isRelative()); + ASSERT_FALSE(URI("file:///uri.svg").isRelative()); + ASSERT_FALSE(URI("mailto:user@host.xy").isRelative()); + ASSERT_FALSE(URI("data:,").isRelative()); + + ASSERT_TRUE(URI("//web/uri.svg").isRelative()); + ASSERT_TRUE(URI("/uri.svg").isRelative()); + ASSERT_TRUE(URI("uri.svg").isRelative()); + ASSERT_TRUE(URI("./uri.svg").isRelative()); + ASSERT_TRUE(URI("../uri.svg").isRelative()); +} + +TEST(UriTest, isNetPath) +{ + ASSERT_FALSE(URI().isNetPath()); + ASSERT_FALSE(URI("http://web/uri.svg").isNetPath()); + ASSERT_FALSE(URI("file:///uri.svg").isNetPath()); + ASSERT_FALSE(URI("/uri.svg").isNetPath()); + ASSERT_FALSE(URI("uri.svg").isNetPath()); + + ASSERT_TRUE(URI("//web/uri.svg").isNetPath()); +} + +TEST(UriTest, isRelativePath) +{ + ASSERT_FALSE(URI("foo:bar").isRelativePath()); + ASSERT_TRUE(URI("foo%3Abar").isRelativePath()); + + ASSERT_FALSE(URI("http://web/uri.svg").isRelativePath()); + ASSERT_FALSE(URI("//web/uri.svg").isRelativePath()); + ASSERT_FALSE(URI("/uri.svg").isRelativePath()); + + ASSERT_TRUE(URI("uri.svg").isRelativePath()); + ASSERT_TRUE(URI("./uri.svg").isRelativePath()); + ASSERT_TRUE(URI("../uri.svg").isRelativePath()); +} + +TEST(UriTest, isAbsolutePath) +{ + ASSERT_FALSE(URI().isAbsolutePath()); + ASSERT_FALSE(URI("http://web/uri.svg").isAbsolutePath()); + ASSERT_FALSE(URI("//web/uri.svg").isAbsolutePath()); + ASSERT_FALSE(URI("uri.svg").isAbsolutePath()); + ASSERT_FALSE(URI("../uri.svg").isAbsolutePath()); + + ASSERT_TRUE(URI("/uri.svg").isAbsolutePath()); +} + +TEST(UriTest, getScheme) +{ + ASSERT_STREQ(URI().getScheme(), nullptr); + + ASSERT_STREQ(URI("https://web/uri.svg").getScheme(), "https"); + ASSERT_STREQ(URI("file:///uri.svg").getScheme(), "file"); + ASSERT_STREQ(URI("data:,").getScheme(), "data"); + + ASSERT_STREQ(URI("data").getScheme(), nullptr); +} + +TEST(UriTest, getQuery) +{ + ASSERT_STREQ(URI().getQuery(), nullptr); + ASSERT_STREQ(URI("uri.svg?a=b&c=d").getQuery(), "a=b&c=d"); + ASSERT_STREQ(URI("?a=b&c=d#hash").getQuery(), "a=b&c=d"); +} + +TEST(UriTest, getFragment) +{ + ASSERT_STREQ(URI().getFragment(), nullptr); + ASSERT_STREQ(URI("uri.svg").getFragment(), nullptr); + ASSERT_STREQ(URI("uri.svg#hash").getFragment(), "hash"); + ASSERT_STREQ(URI("?a=b&c=d#hash").getFragment(), "hash"); + ASSERT_STREQ(URI("urn:isbn:096139210x#hash").getFragment(), "hash"); +} + +TEST(UriTest, getOpaque) +{ + ASSERT_STREQ(URI().getOpaque(), nullptr); + ASSERT_STREQ(URI("urn:isbn:096139210x#hash").getOpaque(), "isbn:096139210x"); + ASSERT_STREQ(URI("data:,foo").getOpaque(), ",foo"); +} + +TEST(UriTest, from_native_filename) +{ +#ifdef _WIN32 + ASSERT_EQ(URI::from_native_filename(win_filename_local).str(), win_url_local); +#else + ASSERT_EQ(URI::from_native_filename("/tmp/uri.svg").str(), "file:///tmp/uri.svg"); + ASSERT_EQ(URI::from_native_filename("/tmp/x y.svg").str(), "file:///tmp/x%20y.svg"); +#endif +} + +TEST(UriTest, uri_to_iri) +{ + // unescape UTF-8 (U+00D6) + ASSERT_EQ(Inkscape::uri_to_iri("data:,umlaut-%C3%96"), "data:,umlaut-\xC3\x96"); + // don't unescape ASCII (U+003A) + ASSERT_EQ(Inkscape::uri_to_iri("foo%3Abar"), "foo%3Abar"); + // sequence (U+00D6 U+1F37A U+003A) + ASSERT_EQ(Inkscape::uri_to_iri("%C3%96%F0%9F%8D%BA%3A"), "\xC3\x96\xF0\x9F\x8D\xBA%3A"); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/unittest.cpp b/testfiles/unittest.cpp new file mode 100644 index 0000000..5002466 --- /dev/null +++ b/testfiles/unittest.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Unit test main. + * + * Author: + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtest/gtest.h" + +#include <gtkmm.h> + +#include "inkgc/gc-core.h" +#include "inkscape.h" + +int main(int argc, char **argv) { + + // setup general environment +#if !GLIB_CHECK_VERSION(2,36,0) + g_type_init(); +#endif + + // If possible, unit tests shouldn't require a GUI session + // since this won't generally be available in auto-builders + // int tmpArgc = 1; + // char const *tmp[] = {"foo", ""}; + // char **tmpArgv = const_cast<char **>(tmp); + // Gtk::Main(tmpArgc, tmpArgv); + + Inkscape::GC::init(); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : |