From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- testfiles/CMakeLists.txt | 126 ++ testfiles/CTestCustom.cmake.in | 5 + testfiles/cli_tests/CMakeLists.txt | 844 +++++++ testfiles/cli_tests/check_output.sh | 78 + testfiles/cli_tests/compare.sh | 13 + testfiles/cli_tests/identify.sh | 11 + testfiles/cli_tests/match_regex.sh | 13 + testfiles/cli_tests/match_regex_fail.sh | 13 + .../testcases/actions-file-open_expected.png | Bin 0 -> 1502 bytes .../testcases/actions-object-align_expected.png | Bin 0 -> 417 bytes .../actions-object-distribute_expected.png | Bin 0 -> 492 bytes .../actions-object-set-attribute_expected.png | Bin 0 -> 1082 bytes .../actions-object-simplify-path_expected.png | Bin 0 -> 12781 bytes .../actions-object-stroke-to-path_expected.png | Bin 0 -> 723 bytes .../actions-object-unlink-clones_expected.png | Bin 0 -> 1269 bytes .../testcases/actions-open-page_expected.png | Bin 0 -> 20119 bytes .../testcases/actions-transform-grow_expected.png | Bin 0 -> 1086 bytes .../actions-transform-remove_expected.png | Bin 0 -> 1131 bytes .../actions-transform-rotate_expected.png | Bin 0 -> 1969 bytes .../actions-transform-translate_expected.png | Bin 0 -> 1086 bytes testfiles/cli_tests/testcases/areas.svg | 10 + testfiles/cli_tests/testcases/empty.svg | 3 + .../testcases/export-area-drawing_expected.emf | Bin 0 -> 1856 bytes .../testcases/export-area-drawing_expected.eps | 443 ++++ .../testcases/export-area-drawing_expected.pdf | Bin 0 -> 1338 bytes .../testcases/export-area-drawing_expected.png | Bin 0 -> 13995 bytes .../testcases/export-area-drawing_expected.ps | 480 ++++ .../testcases/export-area-drawing_expected.svg | 65 + .../testcases/export-area-drawing_expected.wmf | Bin 0 -> 1006 bytes .../testcases/export-area-page_expected.emf | Bin 0 -> 1856 bytes .../testcases/export-area-page_expected.eps | 443 ++++ .../testcases/export-area-page_expected.pdf | Bin 0 -> 1350 bytes .../testcases/export-area-page_expected.png | Bin 0 -> 15117 bytes .../testcases/export-area-page_expected.ps | 482 ++++ .../testcases/export-area-page_expected.svg | 61 + .../testcases/export-area-page_expected.wmf | Bin 0 -> 1006 bytes .../testcases/export-area-page_export-id.pdf | 69 + .../testcases/export-area-page_export-id.png | Bin 0 -> 10167 bytes .../testcases/export-area-page_export-id.ps | 130 ++ .../testcases/export-area-page_export-id.svg | 52 + .../testcases/export-area-snap_expected.png | Bin 0 -> 1048 bytes .../cli_tests/testcases/export-area_expected.png | Bin 0 -> 5778 bytes .../export-background-opacity_expected.eps | 86 + .../export-background-opacity_expected.pdf | Bin 0 -> 1174 bytes .../export-background-opacity_expected.png | Bin 0 -> 428 bytes .../export-background-opacity_expected.ps | 123 + .../export-background-opacity_expected.svg | 54 + .../testcases/export-background_expected.emf | Bin 0 -> 1144 bytes .../testcases/export-background_expected.eps | 86 + .../testcases/export-background_expected.pdf | Bin 0 -> 1140 bytes .../testcases/export-background_expected.png | Bin 0 -> 421 bytes .../testcases/export-background_expected.ps | 123 + .../testcases/export-background_expected.svg | 52 + .../testcases/export-background_expected.wmf | Bin 0 -> 488 bytes .../export-default-background_expected.eps | 86 + .../export-default-background_expected.pdf | 70 + .../export-default-background_expected.png | Bin 0 -> 435 bytes .../export-default-background_expected.ps | 123 + .../export-default-background_expected.svg | 54 + .../cli_tests/testcases/export-dpi_expected.eps | 272 +++ .../cli_tests/testcases/export-dpi_expected.pdf | Bin 0 -> 2193 bytes .../cli_tests/testcases/export-dpi_expected.png | Bin 0 -> 763 bytes .../cli_tests/testcases/export-dpi_expected.ps | 319 +++ .../cli_tests/testcases/export-height_expected.png | Bin 0 -> 248 bytes .../cli_tests/testcases/export-id_expected.emf | Bin 0 -> 788 bytes .../cli_tests/testcases/export-id_expected.eps | 82 + .../cli_tests/testcases/export-id_expected.pdf | Bin 0 -> 940 bytes .../cli_tests/testcases/export-id_expected.png | Bin 0 -> 388 bytes .../cli_tests/testcases/export-id_expected.ps | 119 + .../cli_tests/testcases/export-id_expected.svg | 110 + .../cli_tests/testcases/export-id_expected.wmf | Bin 0 -> 884 bytes .../export-id_export-id-only_expected.emf | Bin 0 -> 664 bytes .../export-id_export-id-only_expected.eps | 80 + .../export-id_export-id-only_expected.pdf | Bin 0 -> 1099 bytes .../export-id_export-id-only_expected.png | Bin 0 -> 371 bytes .../testcases/export-id_export-id-only_expected.ps | 117 + .../export-id_export-id-only_expected.svg | 47 + .../export-id_export-id-only_expected.wmf | Bin 0 -> 290 bytes ...export-id-only_export-area-drawing_expected.emf | Bin 0 -> 704 bytes ...export-id-only_export-area-drawing_expected.eps | 80 + ...export-id-only_export-area-drawing_expected.pdf | Bin 0 -> 932 bytes ...export-id-only_export-area-drawing_expected.png | Bin 0 -> 730 bytes ..._export-id-only_export-area-drawing_expected.ps | 117 + ...export-id-only_export-area-drawing_expected.svg | 47 + ...export-id-only_export-area-drawing_expected.wmf | Bin 0 -> 290 bytes ...id_export-id-only_export-area-page_expected.emf | Bin 0 -> 700 bytes ...id_export-id-only_export-area-page_expected.eps | 80 + ...id_export-id-only_export-area-page_expected.pdf | Bin 0 -> 1109 bytes ...id_export-id-only_export-area-page_expected.png | Bin 0 -> 979 bytes ...-id_export-id-only_export-area-page_expected.ps | 117 + ...id_export-id-only_export-area-page_expected.svg | 47 + ...id_export-id-only_export-area-page_expected.wmf | Bin 0 -> 290 bytes .../testcases/export-ignore-filters_expected.emf | Bin 0 -> 816 bytes .../testcases/export-ignore-filters_expected.eps | 82 + .../testcases/export-ignore-filters_expected.pdf | Bin 0 -> 1105 bytes .../testcases/export-ignore-filters_expected.png | Bin 0 -> 402 bytes .../testcases/export-ignore-filters_expected.ps | 119 + .../testcases/export-ignore-filters_expected.svg | 54 + .../testcases/export-ignore-filters_expected.wmf | Bin 0 -> 356 bytes .../testcases/export-margin_drawing_expected.emf | Bin 0 -> 812 bytes .../testcases/export-margin_drawing_expected.eps | 82 + .../testcases/export-margin_drawing_expected.pdf | Bin 0 -> 940 bytes .../testcases/export-margin_drawing_expected.png | Bin 0 -> 508 bytes .../testcases/export-margin_drawing_expected.ps | 119 + .../testcases/export-margin_drawing_expected.svg | 58 + .../testcases/export-margin_drawing_expected.wmf | Bin 0 -> 356 bytes .../export-margin_export-area_expected.png | Bin 0 -> 356 bytes .../testcases/export-margin_export-id_expected.emf | Bin 0 -> 832 bytes .../testcases/export-margin_export-id_expected.eps | 82 + .../testcases/export-margin_export-id_expected.pdf | Bin 0 -> 943 bytes .../testcases/export-margin_export-id_expected.png | Bin 0 -> 485 bytes .../testcases/export-margin_export-id_expected.ps | 119 + .../testcases/export-margin_export-id_expected.svg | 58 + .../testcases/export-margin_export-id_expected.wmf | Bin 0 -> 356 bytes ...rt-margin_export-id_export-id-only_expected.emf | Bin 0 -> 692 bytes ...rt-margin_export-id_export-id-only_expected.eps | 80 + ...rt-margin_export-id_export-id-only_expected.pdf | Bin 0 -> 933 bytes ...rt-margin_export-id_export-id-only_expected.png | Bin 0 -> 482 bytes ...ort-margin_export-id_export-id-only_expected.ps | 117 + ...rt-margin_export-id_export-id-only_expected.svg | 51 + ...rt-margin_export-id_export-id-only_expected.wmf | Bin 0 -> 290 bytes .../testcases/export-margin_mm_expected.emf | Bin 0 -> 824 bytes .../testcases/export-margin_mm_expected.eps | 82 + .../testcases/export-margin_mm_expected.pdf | Bin 0 -> 1152 bytes .../testcases/export-margin_mm_expected.png | Bin 0 -> 6068 bytes .../testcases/export-margin_mm_expected.ps | 119 + .../testcases/export-margin_mm_expected.svg | 58 + .../testcases/export-margin_mm_expected.wmf | Bin 0 -> 356 bytes .../export-margin_mm_viewbox_drawing_expected.emf | Bin 0 -> 856 bytes .../export-margin_mm_viewbox_drawing_expected.eps | 82 + .../export-margin_mm_viewbox_drawing_expected.pdf | Bin 0 -> 974 bytes .../export-margin_mm_viewbox_drawing_expected.png | Bin 0 -> 3222 bytes .../export-margin_mm_viewbox_drawing_expected.ps | 119 + .../export-margin_mm_viewbox_drawing_expected.svg | 64 + .../export-margin_mm_viewbox_drawing_expected.wmf | Bin 0 -> 356 bytes .../export-margin_mm_viewbox_id_expected.emf | Bin 0 -> 844 bytes .../export-margin_mm_viewbox_id_expected.eps | 82 + .../export-margin_mm_viewbox_id_expected.pdf | Bin 0 -> 972 bytes .../export-margin_mm_viewbox_id_expected.png | Bin 0 -> 2664 bytes .../export-margin_mm_viewbox_id_expected.ps | 119 + .../export-margin_mm_viewbox_id_expected.svg | 50 + .../export-margin_mm_viewbox_id_expected.wmf | Bin 0 -> 356 bytes .../export-margin_mm_viewbox_page_expected.emf | Bin 0 -> 824 bytes .../export-margin_mm_viewbox_page_expected.eps | 82 + .../export-margin_mm_viewbox_page_expected.pdf | Bin 0 -> 1152 bytes .../export-margin_mm_viewbox_page_expected.png | Bin 0 -> 6068 bytes .../export-margin_mm_viewbox_page_expected.ps | 119 + .../export-margin_mm_viewbox_page_expected.svg | 64 + .../export-margin_mm_viewbox_page_expected.wmf | Bin 0 -> 356 bytes .../testcases/export-margin_px_expected.emf | Bin 0 -> 820 bytes .../testcases/export-margin_px_expected.eps | 82 + .../testcases/export-margin_px_expected.pdf | Bin 0 -> 943 bytes .../testcases/export-margin_px_expected.png | Bin 0 -> 737 bytes .../testcases/export-margin_px_expected.ps | 119 + .../testcases/export-margin_px_expected.svg | 58 + .../testcases/export-margin_px_expected.wmf | Bin 0 -> 356 bytes .../export-png-color-mode-gray-8_expected.png | Bin 0 -> 6386 bytes .../export-png-color-mode-rgb-8_expected.png | Bin 0 -> 11485 bytes .../export-png-color-mode-rgba-8_expected.png | Bin 0 -> 15278 bytes .../testcases/export-ps-level-2_expected.ps | 2366 ++++++++++++++++++++ .../testcases/export-ps-level-3_expected.ps | 134 ++ .../cli_tests/testcases/export-width_expected.png | Bin 0 -> 644 bytes .../testcases/export-with-filters_expected.emf | Bin 0 -> 800 bytes .../testcases/export-with-filters_expected.eps | 122 + .../testcases/export-with-filters_expected.pdf | Bin 0 -> 2206 bytes .../testcases/export-with-filters_expected.png | Bin 0 -> 402 bytes .../testcases/export-with-filters_expected.ps | 159 ++ .../testcases/export-with-filters_expected.svg | 68 + .../testcases/export-with-filters_expected.wmf | Bin 0 -> 356 bytes testfiles/cli_tests/testcases/export_hints.svg | 7 + testfiles/cli_tests/testcases/filter.svg | 9 + testfiles/cli_tests/testcases/gradient.svg | 10 + .../cli_tests/testcases/lambda-background.svg | 7 + testfiles/cli_tests/testcases/lambda.svg | 6 + .../testcases/librevenge_formats/corel_draw.cdr | Bin 0 -> 13873 bytes .../testcases/librevenge_formats/corel_draw2.cdr | Bin 0 -> 19596 bytes .../librevenge_formats/corel_draw2_expected.png | Bin 0 -> 30971 bytes .../librevenge_formats/corel_draw_expected.png | Bin 0 -> 15577 bytes .../testcases/librevenge_formats/visio.vsd | Bin 0 -> 52224 bytes .../librevenge_formats/visio.vsd_expected.png | Bin 0 -> 21469 bytes .../testcases/librevenge_formats/visio.vsdx | Bin 0 -> 24693 bytes .../librevenge_formats/visio.vsdx_expected.png | Bin 0 -> 2947 bytes .../testcases/librevenge_formats/word_perfect.wpg | Bin 0 -> 2525 bytes .../librevenge_formats/word_perfect_expected.png | Bin 0 -> 708 bytes .../cli_tests/testcases/multiline-anchoring.svg | 29 + testfiles/cli_tests/testcases/offset.svg | 10 + testfiles/cli_tests/testcases/path.svg | 39 + testfiles/cli_tests/testcases/pdf-mesh.pdf | Bin 0 -> 1728 bytes testfiles/cli_tests/testcases/pdf-pages.pdf | Bin 0 -> 15382 bytes testfiles/cli_tests/testcases/pyramids.svg | 22 + testfiles/cli_tests/testcases/rects.svg | 6 + testfiles/cli_tests/testcases/regression-1364.svg | 20 + .../cli_tests/testcases/regression-1364_script.py | 31 + testfiles/cli_tests/testcases/regression-2602.svg | 9 + .../cli_tests/testcases/regression-2602_script.py | 10 + testfiles/cli_tests/testcases/regression-2797.svg | 22 + .../cli_tests/testcases/regression-2797_script.py | 17 + testfiles/cli_tests/testcases/shapes.svg | 8 + testfiles/cli_tests/testcases/shapes_expected.emf | Bin 0 -> 1540 bytes testfiles/cli_tests/testcases/shapes_expected.eps | 109 + testfiles/cli_tests/testcases/shapes_expected.pdf | Bin 0 -> 1333 bytes testfiles/cli_tests/testcases/shapes_expected.png | Bin 0 -> 13382 bytes testfiles/cli_tests/testcases/shapes_expected.ps | 146 ++ testfiles/cli_tests/testcases/shapes_expected.wmf | Bin 0 -> 1120 bytes testfiles/cli_tests/testcases/shapes_expected.xaml | 17 + testfiles/cli_tests/testcases/square_mm.svg | 5 + .../cli_tests/testcases/square_mm_viewbox.svg | 10 + testfiles/cli_tests/testcases/square_px.svg | 5 + .../testcases/stroke-to-path-variations.svg | 131 ++ testfiles/cli_tests/testcases/systemLanguage.svg | 20 + .../cli_tests/testcases/systemLanguage_RDF.svg | 15 + .../cli_tests/testcases/systemLanguage_de.png | Bin 0 -> 516 bytes .../cli_tests/testcases/systemLanguage_default.png | Bin 0 -> 516 bytes .../cli_tests/testcases/systemLanguage_en.png | Bin 0 -> 519 bytes .../cli_tests/testcases/systemLanguage_fr.png | Bin 0 -> 518 bytes .../cli_tests/testcases/systemLanguage_pt.png | Bin 0 -> 516 bytes testfiles/cli_tests/testcases/text.svg | 4 + testfiles/cli_tests/testcases/theta.svg | 14 + testfiles/doc-per-case-test.cpp | 50 + testfiles/doc-per-case-test.h | 44 + testfiles/fuzzer.cpp | 22 + testfiles/fuzzer.dict | 526 +++++ testfiles/lpe_tests/AttachPath_0_92_5_mixed.svg | 81 + testfiles/lpe_tests/AttachPath_mm_1_0_2.svg | 85 + testfiles/lpe_tests/AttachPath_px_1_0_2.svg | 85 + testfiles/lpe_tests/BSpline_mixed_0_92_5.svg | 113 + testfiles/lpe_tests/BSpline_mm_1_0_2.svg | 121 + testfiles/lpe_tests/BSpline_px_1_0_2.svg | 121 + testfiles/lpe_tests/Bendpath_mixed_0_92_5.svg | 106 + testfiles/lpe_tests/Bendpath_multiGroup_1_0_2.svg | 136 ++ .../lpe_tests/Bendpath_shapeClipPath_1_0_2.svg | 50 + testfiles/lpe_tests/Bendpath_shape_1_0_2.svg | 40 + .../lpe_tests/Bendpath_stackNested_mm_1_0_2.svg | 122 + .../lpe_tests/Bendpath_stackNested_px_1_0_2.svg | 124 + testfiles/lpe_tests/Bool_multi_mm_1_1.svg | 253 +++ testfiles/lpe_tests/Bool_multi_px_1_1.svg | 260 +++ testfiles/lpe_tests/BoundingBox_mixed_0_92_5.svg | 36 + testfiles/lpe_tests/BoundingBox_mm_1_0_2.svg | 37 + testfiles/lpe_tests/BoundingBox_px_1_0_2.svg | 37 + testfiles/lpe_tests/CMakeLists.txt | 3 + testfiles/lpe_tests/CloneOriginal_boken_1_0_2.svg | 257 +++ testfiles/lpe_tests/CloneOriginal_mixed_0_92_5.svg | 37 + testfiles/lpe_tests/CloneOriginal_mixed_mm_1_1.svg | 260 +++ testfiles/lpe_tests/CloneOriginal_mixed_px_1_1.svg | 257 +++ testfiles/lpe_tests/ConstructGrid_mixed_0_92_5.svg | 63 + testfiles/lpe_tests/ConstructGrid_mm_1_0_2.svg | 60 + testfiles/lpe_tests/ConstructGrid_px_1_0_2.svg | 60 + .../lpe_tests/DashedStroke_multi_mm_1_0_2.svg | 164 ++ .../lpe_tests/DashedStroke_multi_px_1_0_2.svg | 165 ++ .../lpe_tests/Ellipse5pts_ellipse_mm_1_0_2.svg | 29 + .../lpe_tests/Ellipse5pts_ellipse_px_1_0_2.svg | 28 + testfiles/lpe_tests/Ellipse5pts_path_0_92_5.svg | 33 + .../lpe_tests/EllipseFromPoints_multi_mm_1_0_2.svg | 496 ++++ .../lpe_tests/EllipseFromPoints_multi_px_1_0_2.svg | 497 ++++ .../lpe_tests/EnvelopeDeformation_multi_0_92_5.svg | 111 + .../EnvelopeDeformation_multi_mm_1_0_2.svg | 142 ++ .../EnvelopeDeformation_multi_px_1_0_2.svg | 146 ++ .../lpe_tests/FillBetweenMany_multi_0_92_5.svg | 69 + .../lpe_tests/FillBetweenMany_multi_mm_1_0_2.svg | 129 ++ .../lpe_tests/FillBetweenMany_multi_px_1_0_2.svg | 166 ++ .../lpe_tests/FillBetweenStrokes_path_0_92_5.svg | 78 + .../FillBetweenStrokes_path_multi_mm_1_0_2.svg | 65 + .../FillBetweenStrokes_path_multi_px_1_0_2.svg | 65 + .../lpe_tests/FilletChamfer_multi_mm_1_0_2.svg | 164 ++ .../lpe_tests/FilletChamfer_multi_px_1_0_2.svg | 165 ++ testfiles/lpe_tests/Gears_multi_mm_1_0_2.svg | 40 + testfiles/lpe_tests/Gears_multi_px_1_0_2.svg | 40 + testfiles/lpe_tests/Gears_path_0_92_5.svg | 40 + .../lpe_tests/InterpolatePoints_multi_mm_1_0_2.svg | 96 + .../lpe_tests/InterpolatePoints_multi_px_1_0_2.svg | 96 + .../lpe_tests/InterpolatePoints_path_0_92_5.svg | 91 + testfiles/lpe_tests/Interpolate_multi_mm_1_0_2.svg | 59 + testfiles/lpe_tests/Interpolate_multi_px_1_0_2.svg | 59 + testfiles/lpe_tests/Interpolate_path_0_92_5.svg | 38 + testfiles/lpe_tests/JoinType_multi_mm_1_0_2.svg | 110 + testfiles/lpe_tests/JoinType_multi_px_1_0_2.svg | 110 + testfiles/lpe_tests/Knot_multi_mm_1_0_2.svg | 214 ++ testfiles/lpe_tests/Knot_multi_px_1_0_2.svg | 209 ++ testfiles/lpe_tests/Knot_path_0_92_5.svg | 59 + testfiles/lpe_tests/Lattice2_multi_mm_1_0_2.svg | 255 +++ testfiles/lpe_tests/Lattice2_multi_px_1_0_2.svg | 257 +++ testfiles/lpe_tests/Lattice2_path_0_92_5.svg | 151 ++ .../lpe_tests/MeasureSegments_multi_mm_1_0_2.svg | 782 +++++++ .../lpe_tests/MeasureSegments_multi_px_1_0_2.svg | 748 +++++++ .../lpe_tests/MirrorSymmetry_multi_mm_1_0_2.svg | 301 +++ .../lpe_tests/MirrorSymmetry_multi_px_1_0_2.svg | 301 +++ testfiles/lpe_tests/MirrorSymmetry_path_0_92_5.svg | 208 ++ testfiles/lpe_tests/Offset_multi_mm_1_0_2.svg | 261 +++ testfiles/lpe_tests/Offset_multi_px_1_0_2.svg | 261 +++ testfiles/lpe_tests/Offset_multi_px_1_1.svg | 247 ++ .../lpe_tests/PatternAlongPath_mixed_0_92_5.svg | 117 + .../PatternAlongPath_multiple_mm_1_0_2.svg | 100 + .../PatternAlongPath_multiple_px_1_0_2.svg | 100 + .../lpe_tests/PatternAlongPath_path_1_0_2.svg | 87 + .../lpe_tests/PatternAlongPath_shape_1_0_2.svg | 45 + .../lpe_tests/PerspectiveEnvelope_mixed_0_92_5.svg | 175 ++ .../PerspectiveEnvelope_multi_mm_1_0_2.svg | 142 ++ .../PerspectiveEnvelope_multi_px_1_0_2.svg | 142 ++ testfiles/lpe_tests/PowerClip_multi_mm_1_0_2.svg | 279 +++ testfiles/lpe_tests/PowerClip_multi_px_1_0_2.svg | 280 +++ testfiles/lpe_tests/PowerMask_multi_mm_1_0_2.svg | 356 +++ testfiles/lpe_tests/PowerMask_multi_px_1_0_2.svg | 357 +++ testfiles/lpe_tests/PowerStroke_multi_mm_1_0_2.svg | 167 ++ testfiles/lpe_tests/PowerStroke_multi_px_1_0_2.svg | 174 ++ testfiles/lpe_tests/README | 8 + .../lpe_tests/RotateCopies_multi_mm_1_0_2.svg | 407 ++++ .../lpe_tests/RotateCopies_multi_px_1_0_2.svg | 443 ++++ .../lpe_tests/RoughHatches_multi_mm_1_0_2.svg | 136 ++ .../lpe_tests/RoughHatches_multi_px_1_0_2.svg | 136 ++ testfiles/lpe_tests/RoughHatches_path_0_92_5.svg | 209 ++ testfiles/lpe_tests/Roughen_path_1_1.svg | 172 ++ testfiles/lpe_tests/Ruler_multi_mm_1_0_2.svg | 134 ++ testfiles/lpe_tests/Ruler_multi_px_1_0_2.svg | 135 ++ testfiles/lpe_tests/Ruler_path_0_92_5.svg | 133 ++ testfiles/lpe_tests/ShowHandles_multi_mm_1_0_2.svg | 133 ++ testfiles/lpe_tests/ShowHandles_multi_px_1_0_2.svg | 140 ++ testfiles/lpe_tests/ShowHandles_path_0_92_5.svg | 130 ++ testfiles/lpe_tests/Simplify_multi_mm_1_0_2.svg | 148 ++ testfiles/lpe_tests/Simplify_multi_px_1_0_2.svg | 148 ++ testfiles/lpe_tests/Simplify_path_0_92_5.svg | 143 ++ testfiles/lpe_tests/Sketch_multi_mm_1_0_2.svg | 192 ++ testfiles/lpe_tests/Sketch_multi_px_1_0_2.svg | 193 ++ testfiles/lpe_tests/Sketch_path_0_92_5.svg | 152 ++ testfiles/lpe_tests/Slice_multi_mm_1_1.svg | 372 +++ testfiles/lpe_tests/Slice_multi_px_1_1.svg | 374 ++++ testfiles/lpe_tests/Spiro_mixed_0_92_5.svg | 119 + testfiles/lpe_tests/Spiro_mm_1_0_2.svg | 126 ++ testfiles/lpe_tests/Spiro_px_1_0_2.svg | 133 ++ .../lpe_tests/StitchSubPaths_multi_mm_1_0_2.svg | 116 + .../lpe_tests/StitchSubPaths_multi_px_1_0_2.svg | 117 + testfiles/lpe_tests/StitchSubPaths_path_0_92_5.svg | 112 + testfiles/lpe_tests/TaperStroke_multi_mm_1_0_2.svg | 123 + testfiles/lpe_tests/TaperStroke_multi_px_1_0_2.svg | 124 + .../lpe_tests/Transform2Points_multi_mm_1_0_2.svg | 261 +++ .../lpe_tests/Transform2Points_multi_px_1_0_2.svg | 151 ++ .../lpe_tests/Transform2Points_path_0_92_5.svg | 126 ++ testfiles/lpe_tests/VonCoch_multi_mm_1_0_2.svg | 142 ++ testfiles/lpe_tests/VonCoch_multi_px_1_0_2.svg | 143 ++ testfiles/lpe_tests/VonCoch_path_0_92_5.svg | 141 ++ testfiles/lpespaths-test.h | 194 ++ testfiles/rendering_tests/CMakeLists.txt | 68 + testfiles/rendering_tests/README | 26 + .../expected_rendering/multi-style.png | Bin 0 -> 1433 bytes .../selector-important-002-large.png | Bin 0 -> 11306 bytes .../expected_rendering/selector-important-002.png | Bin 0 -> 921 bytes .../selector-important-003-large.png | Bin 0 -> 11308 bytes .../expected_rendering/selector-important-003.png | Bin 0 -> 925 bytes .../expected_rendering/style-parsing.png | Bin 0 -> 765 bytes .../symbol-svg2-geometry-properties.png | Bin 0 -> 1073 bytes .../test-baseline-shift-large.png | Bin 0 -> 97340 bytes .../expected_rendering/test-baseline-shift.png | Bin 0 -> 20024 bytes .../expected_rendering/test-dont-crash.png | Bin 0 -> 453 bytes .../expected_rendering/test-empty-large.png | Bin 0 -> 69082 bytes .../expected_rendering/test-empty.png | Bin 0 -> 6920 bytes .../expected_rendering/test-glyph-y-pos-large.png | Bin 0 -> 115278 bytes .../expected_rendering/test-glyph-y-pos.png | Bin 0 -> 22881 bytes .../test-powerstroke-join-large.png | Bin 0 -> 8037 bytes .../expected_rendering/test-powerstroke-join.png | Bin 0 -> 1796 bytes .../expected_rendering/test-rtl-vertical-large.png | Bin 0 -> 87221 bytes .../expected_rendering/test-rtl-vertical.png | Bin 0 -> 17482 bytes .../expected_rendering/test-use-large.png | Bin 0 -> 6452 bytes .../expected_rendering/test-use.png | Bin 0 -> 1204 bytes .../text-glyphs-combining-large.png | Bin 0 -> 172004 bytes .../expected_rendering/text-glyphs-combining.png | Bin 0 -> 35443 bytes .../text-glyphs-vertical-large.png | Bin 0 -> 106286 bytes .../expected_rendering/text-glyphs-vertical.png | Bin 0 -> 22834 bytes .../expected_rendering/text-gzipped-svg-glyph.png | Bin 0 -> 646 bytes .../expected_rendering/text-shaping-large.png | Bin 0 -> 83064 bytes .../expected_rendering/text-shaping.png | Bin 0 -> 33675 bytes testfiles/rendering_tests/fonts/Estedad-Medium.ttf | Bin 0 -> 60832 bytes .../rendering_tests/fonts/GeomTest-Regular.otf | Bin 0 -> 2984 bytes .../fonts/GeomTest-gzipped-SVG-glyphs.otf | Bin 0 -> 3424 bytes testfiles/rendering_tests/fonts/LICENSES | 10 + testfiles/rendering_tests/fonts/Lohit-Telugu.ttf | Bin 0 -> 341752 bytes .../rendering_tests/fonts/NotoSans-Regular.ttf | Bin 0 -> 468584 bytes .../fonts/NotoSansCJKjp-Regular.otf | Bin 0 -> 16427228 bytes .../fonts/NotoSansHebrew-Regular.ttf | Bin 0 -> 27696 bytes testfiles/rendering_tests/multi-style-import-1.css | 9 + testfiles/rendering_tests/multi-style-import-2.css | 7 + testfiles/rendering_tests/multi-style.svg | 94 + .../rendering_tests/selector-important-002.svg | 58 + .../rendering_tests/selector-important-003.svg | 57 + testfiles/rendering_tests/style-parsing.svg | 16 + .../symbol-svg2-geometry-properties.svg | 83 + testfiles/rendering_tests/test-baseline-shift.svg | 33 + testfiles/rendering_tests/test-dont-crash.svg | 22 + testfiles/rendering_tests/test-empty.svg | 65 + testfiles/rendering_tests/test-glyph-y-pos.svg | 32 + .../rendering_tests/test-powerstroke-join.svg | 6 + testfiles/rendering_tests/test-rtl-vertical.svg | 39 + testfiles/rendering_tests/test-use-ref.svg | 89 + testfiles/rendering_tests/test-use.svg | 18 + testfiles/rendering_tests/test.sh | 46 + .../rendering_tests/text-glyphs-combining.svg | 36 + testfiles/rendering_tests/text-glyphs-vertical.svg | 53 + .../rendering_tests/text-gzipped-svg-glyph.svg | 25 + testfiles/rendering_tests/text-shaping.svg | 93 + testfiles/src/2geom-characterization-test.cpp | 31 + testfiles/src/attributes-test.cpp | 659 ++++++ testfiles/src/cairo-utils-test.cpp | 51 + testfiles/src/color-profile-test.cpp | 127 ++ testfiles/src/curve-test.cpp | 292 +++ testfiles/src/cxxtests-to-migrate/marker-test.h | 42 + testfiles/src/cxxtests-to-migrate/mod360-test.h | 65 + .../src/cxxtests-to-migrate/preferences-test.h | 139 ++ .../src/cxxtests-to-migrate/sp-style-elem-test.h | 166 ++ testfiles/src/cxxtests-to-migrate/test-helpers.h | 71 + testfiles/src/cxxtests-to-migrate/verbs-test.h | 95 + testfiles/src/dir-util-test.cpp | 64 + testfiles/src/drag-and-drop-svgz.cpp | 70 + testfiles/src/extract-uri-test.cpp | 75 + testfiles/src/lpe-test.cpp | 165 ++ testfiles/src/lpe64-test.cpp | 54 + testfiles/src/object-set-test.cpp | 706 ++++++ testfiles/src/object-style-test.cpp | 199 ++ testfiles/src/object-test.cpp | 204 ++ testfiles/src/path-boolop-test.cpp | 86 + testfiles/src/rebase-hrefs-test.cpp | 135 ++ testfiles/src/sp-glyph-kerning-test.cpp | 26 + testfiles/src/sp-gradient-test.cpp | 130 ++ testfiles/src/sp-item-group-test.cpp | 46 + testfiles/src/sp-object-test.cpp | 122 + testfiles/src/style-elem-test.cpp | 71 + testfiles/src/style-internal-test.cpp | 44 + testfiles/src/style-test.cpp | 604 +++++ testfiles/src/svg-affine-test.cpp | 226 ++ testfiles/src/svg-color-test.cpp | 112 + testfiles/src/svg-extension-test.cpp | 80 + testfiles/src/svg-length-test.cpp | 187 ++ testfiles/src/svg-path-geom-test.cpp | 499 +++++ testfiles/src/svg-stringstream-test.cpp | 156 ++ testfiles/src/uri-test.cpp | 304 +++ testfiles/src/util-test.cpp | 82 + testfiles/src/xml-test.cpp | 84 + testfiles/unittest.cpp | 49 + 435 files changed, 38920 insertions(+) create mode 100644 testfiles/CMakeLists.txt create mode 100644 testfiles/CTestCustom.cmake.in create mode 100644 testfiles/cli_tests/CMakeLists.txt create mode 100644 testfiles/cli_tests/check_output.sh create mode 100644 testfiles/cli_tests/compare.sh create mode 100644 testfiles/cli_tests/identify.sh create mode 100644 testfiles/cli_tests/match_regex.sh create mode 100644 testfiles/cli_tests/match_regex_fail.sh create mode 100644 testfiles/cli_tests/testcases/actions-file-open_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-object-align_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-object-distribute_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-object-set-attribute_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-object-simplify-path_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-object-stroke-to-path_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-object-unlink-clones_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-open-page_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-transform-grow_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-transform-remove_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-transform-rotate_expected.png create mode 100644 testfiles/cli_tests/testcases/actions-transform-translate_expected.png create mode 100644 testfiles/cli_tests/testcases/areas.svg create mode 100644 testfiles/cli_tests/testcases/empty.svg create mode 100644 testfiles/cli_tests/testcases/export-area-drawing_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-area-drawing_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-area-drawing_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-area-drawing_expected.png create mode 100644 testfiles/cli_tests/testcases/export-area-drawing_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-area-drawing_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-area-drawing_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-area-page_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-area-page_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-area-page_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-area-page_expected.png create mode 100644 testfiles/cli_tests/testcases/export-area-page_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-area-page_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-area-page_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-area-page_export-id.pdf create mode 100644 testfiles/cli_tests/testcases/export-area-page_export-id.png create mode 100644 testfiles/cli_tests/testcases/export-area-page_export-id.ps create mode 100644 testfiles/cli_tests/testcases/export-area-page_export-id.svg create mode 100644 testfiles/cli_tests/testcases/export-area-snap_expected.png create mode 100644 testfiles/cli_tests/testcases/export-area_expected.png create mode 100644 testfiles/cli_tests/testcases/export-background-opacity_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-background-opacity_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-background-opacity_expected.png create mode 100644 testfiles/cli_tests/testcases/export-background-opacity_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-background-opacity_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-background_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-background_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-background_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-background_expected.png create mode 100644 testfiles/cli_tests/testcases/export-background_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-background_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-background_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-default-background_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-default-background_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-default-background_expected.png create mode 100644 testfiles/cli_tests/testcases/export-default-background_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-default-background_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-dpi_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-dpi_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-dpi_expected.png create mode 100644 testfiles/cli_tests/testcases/export-dpi_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-height_expected.png create mode 100644 testfiles/cli_tests/testcases/export-id_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-id_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-id_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-id_expected.png create mode 100644 testfiles/cli_tests/testcases/export-id_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-id_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-id_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_expected.png create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.png create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.png create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-ignore-filters_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-ignore-filters_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-ignore-filters_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-ignore-filters_expected.png create mode 100644 testfiles/cli_tests/testcases/export-ignore-filters_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-ignore-filters_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-ignore-filters_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-margin_drawing_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-margin_drawing_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-margin_drawing_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-margin_drawing_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_drawing_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-margin_drawing_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-margin_drawing_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-margin_export-area_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-margin_px_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-margin_px_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-margin_px_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-margin_px_expected.png create mode 100644 testfiles/cli_tests/testcases/export-margin_px_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-margin_px_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-margin_px_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export-png-color-mode-gray-8_expected.png create mode 100644 testfiles/cli_tests/testcases/export-png-color-mode-rgb-8_expected.png create mode 100644 testfiles/cli_tests/testcases/export-png-color-mode-rgba-8_expected.png create mode 100644 testfiles/cli_tests/testcases/export-ps-level-2_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-ps-level-3_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-width_expected.png create mode 100644 testfiles/cli_tests/testcases/export-with-filters_expected.emf create mode 100644 testfiles/cli_tests/testcases/export-with-filters_expected.eps create mode 100644 testfiles/cli_tests/testcases/export-with-filters_expected.pdf create mode 100644 testfiles/cli_tests/testcases/export-with-filters_expected.png create mode 100644 testfiles/cli_tests/testcases/export-with-filters_expected.ps create mode 100644 testfiles/cli_tests/testcases/export-with-filters_expected.svg create mode 100644 testfiles/cli_tests/testcases/export-with-filters_expected.wmf create mode 100644 testfiles/cli_tests/testcases/export_hints.svg create mode 100644 testfiles/cli_tests/testcases/filter.svg create mode 100644 testfiles/cli_tests/testcases/gradient.svg create mode 100644 testfiles/cli_tests/testcases/lambda-background.svg create mode 100644 testfiles/cli_tests/testcases/lambda.svg create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/corel_draw.cdr create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/corel_draw2.cdr create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/corel_draw2_expected.png create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/corel_draw_expected.png create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/visio.vsd create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/visio.vsd_expected.png create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx_expected.png create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/word_perfect.wpg create mode 100644 testfiles/cli_tests/testcases/librevenge_formats/word_perfect_expected.png create mode 100644 testfiles/cli_tests/testcases/multiline-anchoring.svg create mode 100644 testfiles/cli_tests/testcases/offset.svg create mode 100644 testfiles/cli_tests/testcases/path.svg create mode 100644 testfiles/cli_tests/testcases/pdf-mesh.pdf create mode 100644 testfiles/cli_tests/testcases/pdf-pages.pdf create mode 100644 testfiles/cli_tests/testcases/pyramids.svg create mode 100644 testfiles/cli_tests/testcases/rects.svg create mode 100644 testfiles/cli_tests/testcases/regression-1364.svg create mode 100644 testfiles/cli_tests/testcases/regression-1364_script.py create mode 100644 testfiles/cli_tests/testcases/regression-2602.svg create mode 100644 testfiles/cli_tests/testcases/regression-2602_script.py create mode 100644 testfiles/cli_tests/testcases/regression-2797.svg create mode 100644 testfiles/cli_tests/testcases/regression-2797_script.py create mode 100644 testfiles/cli_tests/testcases/shapes.svg create mode 100644 testfiles/cli_tests/testcases/shapes_expected.emf create mode 100644 testfiles/cli_tests/testcases/shapes_expected.eps create mode 100644 testfiles/cli_tests/testcases/shapes_expected.pdf create mode 100644 testfiles/cli_tests/testcases/shapes_expected.png create mode 100644 testfiles/cli_tests/testcases/shapes_expected.ps create mode 100644 testfiles/cli_tests/testcases/shapes_expected.wmf create mode 100644 testfiles/cli_tests/testcases/shapes_expected.xaml create mode 100644 testfiles/cli_tests/testcases/square_mm.svg create mode 100644 testfiles/cli_tests/testcases/square_mm_viewbox.svg create mode 100644 testfiles/cli_tests/testcases/square_px.svg create mode 100644 testfiles/cli_tests/testcases/stroke-to-path-variations.svg create mode 100644 testfiles/cli_tests/testcases/systemLanguage.svg create mode 100644 testfiles/cli_tests/testcases/systemLanguage_RDF.svg create mode 100644 testfiles/cli_tests/testcases/systemLanguage_de.png create mode 100644 testfiles/cli_tests/testcases/systemLanguage_default.png create mode 100644 testfiles/cli_tests/testcases/systemLanguage_en.png create mode 100644 testfiles/cli_tests/testcases/systemLanguage_fr.png create mode 100644 testfiles/cli_tests/testcases/systemLanguage_pt.png create mode 100644 testfiles/cli_tests/testcases/text.svg create mode 100644 testfiles/cli_tests/testcases/theta.svg create mode 100644 testfiles/doc-per-case-test.cpp create mode 100644 testfiles/doc-per-case-test.h create mode 100644 testfiles/fuzzer.cpp create mode 100644 testfiles/fuzzer.dict create mode 100644 testfiles/lpe_tests/AttachPath_0_92_5_mixed.svg create mode 100644 testfiles/lpe_tests/AttachPath_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/AttachPath_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/BSpline_mixed_0_92_5.svg create mode 100644 testfiles/lpe_tests/BSpline_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/BSpline_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Bendpath_mixed_0_92_5.svg create mode 100644 testfiles/lpe_tests/Bendpath_multiGroup_1_0_2.svg create mode 100644 testfiles/lpe_tests/Bendpath_shapeClipPath_1_0_2.svg create mode 100644 testfiles/lpe_tests/Bendpath_shape_1_0_2.svg create mode 100644 testfiles/lpe_tests/Bendpath_stackNested_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Bendpath_stackNested_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Bool_multi_mm_1_1.svg create mode 100644 testfiles/lpe_tests/Bool_multi_px_1_1.svg create mode 100644 testfiles/lpe_tests/BoundingBox_mixed_0_92_5.svg create mode 100644 testfiles/lpe_tests/BoundingBox_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/BoundingBox_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/CMakeLists.txt create mode 100644 testfiles/lpe_tests/CloneOriginal_boken_1_0_2.svg create mode 100644 testfiles/lpe_tests/CloneOriginal_mixed_0_92_5.svg create mode 100644 testfiles/lpe_tests/CloneOriginal_mixed_mm_1_1.svg create mode 100644 testfiles/lpe_tests/CloneOriginal_mixed_px_1_1.svg create mode 100644 testfiles/lpe_tests/ConstructGrid_mixed_0_92_5.svg create mode 100644 testfiles/lpe_tests/ConstructGrid_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/ConstructGrid_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/DashedStroke_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/DashedStroke_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Ellipse5pts_ellipse_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Ellipse5pts_ellipse_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Ellipse5pts_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/EllipseFromPoints_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/EllipseFromPoints_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/EnvelopeDeformation_multi_0_92_5.svg create mode 100644 testfiles/lpe_tests/EnvelopeDeformation_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/EnvelopeDeformation_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/FillBetweenMany_multi_0_92_5.svg create mode 100644 testfiles/lpe_tests/FillBetweenMany_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/FillBetweenMany_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/FillBetweenStrokes_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/FillBetweenStrokes_path_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/FillBetweenStrokes_path_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/FilletChamfer_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/FilletChamfer_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Gears_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Gears_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Gears_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/InterpolatePoints_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/InterpolatePoints_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/InterpolatePoints_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/Interpolate_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Interpolate_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Interpolate_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/JoinType_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/JoinType_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Knot_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Knot_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Knot_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/Lattice2_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Lattice2_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Lattice2_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/MeasureSegments_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/MeasureSegments_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/MirrorSymmetry_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/MirrorSymmetry_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/MirrorSymmetry_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/Offset_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Offset_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Offset_multi_px_1_1.svg create mode 100644 testfiles/lpe_tests/PatternAlongPath_mixed_0_92_5.svg create mode 100644 testfiles/lpe_tests/PatternAlongPath_multiple_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/PatternAlongPath_multiple_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/PatternAlongPath_path_1_0_2.svg create mode 100644 testfiles/lpe_tests/PatternAlongPath_shape_1_0_2.svg create mode 100644 testfiles/lpe_tests/PerspectiveEnvelope_mixed_0_92_5.svg create mode 100644 testfiles/lpe_tests/PerspectiveEnvelope_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/PerspectiveEnvelope_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/PowerClip_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/PowerClip_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/PowerMask_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/PowerMask_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/PowerStroke_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/PowerStroke_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/README create mode 100644 testfiles/lpe_tests/RotateCopies_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/RotateCopies_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/RoughHatches_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/RoughHatches_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/RoughHatches_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/Roughen_path_1_1.svg create mode 100644 testfiles/lpe_tests/Ruler_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Ruler_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Ruler_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/ShowHandles_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/ShowHandles_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/ShowHandles_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/Simplify_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Simplify_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Simplify_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/Sketch_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Sketch_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Sketch_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/Slice_multi_mm_1_1.svg create mode 100644 testfiles/lpe_tests/Slice_multi_px_1_1.svg create mode 100644 testfiles/lpe_tests/Spiro_mixed_0_92_5.svg create mode 100644 testfiles/lpe_tests/Spiro_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Spiro_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/StitchSubPaths_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/StitchSubPaths_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/StitchSubPaths_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/TaperStroke_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/TaperStroke_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Transform2Points_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/Transform2Points_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/Transform2Points_path_0_92_5.svg create mode 100644 testfiles/lpe_tests/VonCoch_multi_mm_1_0_2.svg create mode 100644 testfiles/lpe_tests/VonCoch_multi_px_1_0_2.svg create mode 100644 testfiles/lpe_tests/VonCoch_path_0_92_5.svg create mode 100644 testfiles/lpespaths-test.h create mode 100644 testfiles/rendering_tests/CMakeLists.txt create mode 100644 testfiles/rendering_tests/README create mode 100644 testfiles/rendering_tests/expected_rendering/multi-style.png create mode 100644 testfiles/rendering_tests/expected_rendering/selector-important-002-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/selector-important-002.png create mode 100644 testfiles/rendering_tests/expected_rendering/selector-important-003-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/selector-important-003.png create mode 100644 testfiles/rendering_tests/expected_rendering/style-parsing.png create mode 100644 testfiles/rendering_tests/expected_rendering/symbol-svg2-geometry-properties.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-baseline-shift-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-baseline-shift.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-dont-crash.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-empty-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-empty.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-glyph-y-pos-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-glyph-y-pos.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-powerstroke-join-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-powerstroke-join.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-rtl-vertical-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-rtl-vertical.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-use-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-use.png create mode 100644 testfiles/rendering_tests/expected_rendering/text-glyphs-combining-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/text-glyphs-combining.png create mode 100644 testfiles/rendering_tests/expected_rendering/text-glyphs-vertical-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/text-glyphs-vertical.png create mode 100644 testfiles/rendering_tests/expected_rendering/text-gzipped-svg-glyph.png create mode 100644 testfiles/rendering_tests/expected_rendering/text-shaping-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/text-shaping.png create mode 100644 testfiles/rendering_tests/fonts/Estedad-Medium.ttf create mode 100644 testfiles/rendering_tests/fonts/GeomTest-Regular.otf create mode 100755 testfiles/rendering_tests/fonts/GeomTest-gzipped-SVG-glyphs.otf create mode 100644 testfiles/rendering_tests/fonts/LICENSES create mode 100644 testfiles/rendering_tests/fonts/Lohit-Telugu.ttf create mode 100644 testfiles/rendering_tests/fonts/NotoSans-Regular.ttf create mode 100644 testfiles/rendering_tests/fonts/NotoSansCJKjp-Regular.otf create mode 100644 testfiles/rendering_tests/fonts/NotoSansHebrew-Regular.ttf create mode 100644 testfiles/rendering_tests/multi-style-import-1.css create mode 100644 testfiles/rendering_tests/multi-style-import-2.css create mode 100644 testfiles/rendering_tests/multi-style.svg create mode 100644 testfiles/rendering_tests/selector-important-002.svg create mode 100644 testfiles/rendering_tests/selector-important-003.svg create mode 100644 testfiles/rendering_tests/style-parsing.svg create mode 100644 testfiles/rendering_tests/symbol-svg2-geometry-properties.svg create mode 100644 testfiles/rendering_tests/test-baseline-shift.svg create mode 100644 testfiles/rendering_tests/test-dont-crash.svg create mode 100644 testfiles/rendering_tests/test-empty.svg create mode 100644 testfiles/rendering_tests/test-glyph-y-pos.svg create mode 100644 testfiles/rendering_tests/test-powerstroke-join.svg create mode 100644 testfiles/rendering_tests/test-rtl-vertical.svg create mode 100644 testfiles/rendering_tests/test-use-ref.svg create mode 100644 testfiles/rendering_tests/test-use.svg create mode 100755 testfiles/rendering_tests/test.sh create mode 100644 testfiles/rendering_tests/text-glyphs-combining.svg create mode 100644 testfiles/rendering_tests/text-glyphs-vertical.svg create mode 100644 testfiles/rendering_tests/text-gzipped-svg-glyph.svg create mode 100644 testfiles/rendering_tests/text-shaping.svg create mode 100644 testfiles/src/2geom-characterization-test.cpp create mode 100644 testfiles/src/attributes-test.cpp create mode 100644 testfiles/src/cairo-utils-test.cpp create mode 100644 testfiles/src/color-profile-test.cpp create mode 100644 testfiles/src/curve-test.cpp create mode 100644 testfiles/src/cxxtests-to-migrate/marker-test.h create mode 100644 testfiles/src/cxxtests-to-migrate/mod360-test.h create mode 100644 testfiles/src/cxxtests-to-migrate/preferences-test.h create mode 100644 testfiles/src/cxxtests-to-migrate/sp-style-elem-test.h create mode 100644 testfiles/src/cxxtests-to-migrate/test-helpers.h create mode 100644 testfiles/src/cxxtests-to-migrate/verbs-test.h create mode 100644 testfiles/src/dir-util-test.cpp create mode 100644 testfiles/src/drag-and-drop-svgz.cpp create mode 100644 testfiles/src/extract-uri-test.cpp create mode 100644 testfiles/src/lpe-test.cpp create mode 100644 testfiles/src/lpe64-test.cpp create mode 100644 testfiles/src/object-set-test.cpp create mode 100644 testfiles/src/object-style-test.cpp create mode 100644 testfiles/src/object-test.cpp create mode 100644 testfiles/src/path-boolop-test.cpp create mode 100644 testfiles/src/rebase-hrefs-test.cpp create mode 100644 testfiles/src/sp-glyph-kerning-test.cpp create mode 100644 testfiles/src/sp-gradient-test.cpp create mode 100644 testfiles/src/sp-item-group-test.cpp create mode 100644 testfiles/src/sp-object-test.cpp create mode 100644 testfiles/src/style-elem-test.cpp create mode 100644 testfiles/src/style-internal-test.cpp create mode 100644 testfiles/src/style-test.cpp create mode 100644 testfiles/src/svg-affine-test.cpp create mode 100644 testfiles/src/svg-color-test.cpp create mode 100644 testfiles/src/svg-extension-test.cpp create mode 100644 testfiles/src/svg-length-test.cpp create mode 100644 testfiles/src/svg-path-geom-test.cpp create mode 100644 testfiles/src/svg-stringstream-test.cpp create mode 100644 testfiles/src/uri-test.cpp create mode 100644 testfiles/src/util-test.cpp create mode 100644 testfiles/src/xml-test.cpp create mode 100644 testfiles/unittest.cpp (limited to 'testfiles') diff --git a/testfiles/CMakeLists.txt b/testfiles/CMakeLists.txt new file mode 100644 index 0000000..9185c3c --- /dev/null +++ b/testfiles/CMakeLists.txt @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# ----------------------------------------------------------------------------- + +# custom "check" target with proper dependencies (builds inkscape and tests) +file(TO_NATIVE_PATH "/" _separator) +ADD_DEFINITIONS(-DINKSCAPE_TESTS_DIR="${CMAKE_SOURCE_DIR}/testfiles") +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 + +if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) + set(LPE_TESTS_64bit + #0.92 or lower LPEs + # (test not stable on 32bit Windows) + lpe64-test + ) +endif() + +set(TEST_SOURCES + uri-test + util-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 + path-boolop-test + rebase-hrefs-test + style-elem-test + style-internal-test + style-test + svg-affine-test + svg-color-test + svg-length-test + svg-stringstream-test + sp-gradient-test + svg-path-geom-test + object-test + sp-glyph-kerning-test + cairo-utils-test + svg-extension-test + curve-test + 2geom-characterization-test + xml-test + sp-item-group-test + lpe-test + ${LPE_TESTS_64bit} + ) + +add_library(cpp_test_static_library SHARED unittest.cpp doc-per-case-test.cpp lpespaths-test.h) +target_link_libraries(cpp_test_static_library PUBLIC ${GTEST_LIBRARIES} inkscape_base) + +add_custom_target(tests) +foreach(test_source ${TEST_SOURCES}) + string(REPLACE "-test" "" testname "test_${test_source}") + add_executable(${testname} src/${test_source}.cpp) + target_include_directories(${testname} SYSTEM PRIVATE ${GTEST_INCLUDE_DIRS}) + target_link_libraries(${testname} cpp_test_static_library 2Geom::2geom) + 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 rendering tests and LPE +add_subdirectory(cli_tests) +add_subdirectory(rendering_tests) +add_subdirectory(lpe_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..e40a982 --- /dev/null +++ b/testfiles/cli_tests/CMakeLists.txt @@ -0,0 +1,844 @@ +# 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}) + + #disable dithering + set(ARG_PARAMETERS ${ARG_PARAMETERS} "--export-png-use-dithering=false") + + if(DEFINED ARG_OUTPUT_FILENAME) + # for actions: if an export-do is present do not append export-filename option to prevent + if(NOT ARG_PARAMETERS MATCHES "export-do") + set(ARG_PARAMETERS ${ARG_PARAMETERS} "--export-filename=${ARG_OUTPUT_FILENAME}") + endif() + 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 "file-close$file-open:${CMAKE_CURRENT_SOURCE_DIR}/testcases/theta.svg$export-filename:actions-file-close.svg$export-do + TEST_SCRIPT match_regex.sh actions-file-close.svg "id=\"purple-cover\"") + +# file-new +add_cli_test(actions-file-new1 PARAMETERS --actions=file-new$export-filename:actions-file-new1.svg$export-do + TEST_SCRIPT match_regex.sh actions-file-new1.svg "viewBox=\"0 0 210 297\"") +add_cli_test(actions-file-new2 PARAMETERS --actions=file-new:${CMAKE_CURRENT_SOURCE_DIR}/testcases/theta.svg$export-filename:actions-file-new2.svg$export-do + TEST_SCRIPT match_regex.sh actions-file-new2.svg "id=\"purple-cover\"") + +# file-open +add_cli_test(actions-file-open PARAMETERS --actions=file-open:${CMAKE_CURRENT_SOURCE_DIR}/testcases/theta.svg$export-filename:actions-file-open.png$export-do + OUTPUT_FILENAME actions-file-open.png + REFERENCE_FILENAME actions-file-open_expected.png) + +# inkscape-version +add_cli_test(actions-inkscape-version PARAMETERS --actions=inkscape-version + PASS_FOR_OUTPUT "Inkscape [0-9]+\\.[0-9]+") + +# no-convert-baseline +# object-align +add_cli_test(actions-object-align INPUT_FILENAME lambda.svg + PARAMETERS --actions=select-by-id:green$object-align:left\ page + OUTPUT_FILENAME actions-object-align.png + REFERENCE_FILENAME actions-object-align_expected.png) + +# object-distribute +add_cli_test(actions-object-distribute INPUT_FILENAME rects.svg + PARAMETERS --actions=select-by-element:rect$object-distribute:vgap + OUTPUT_FILENAME actions-object-distribute.png + REFERENCE_FILENAME actions-object-distribute_expected.png) + +# object-set-attribute +add_cli_test(actions-object-set-attribute INPUT_FILENAME rects.svg + PARAMETERS --actions=select-by-id:rect1$object-set-attribute:rx,15 + OUTPUT_FILENAME actions-object-set-attribute.png + REFERENCE_FILENAME actions-object-set-attribute_expected.png) + +# object-set-property +add_cli_test(actions-object-set-property INPUT_FILENAME areas.svg + PARAMETERS --actions=select-by-id:MyRect$object-set-property:fill,gold + OUTPUT_FILENAME actions-object-set-property.svg + TEST_SCRIPT match_regex.sh actions-object-set-property.svg "style=\"fill:gold\"") + +# path-simplify +add_cli_test(actions-path-simplify INPUT_FILENAME path.svg + PARAMETERS --actions=select-by-id:gates$path-simplify$export-id:gates$export-id-only + OUTPUT_FILENAME actions-object-simplify-path.png + REFERENCE_FILENAME actions-object-simplify-path_expected.png) + +# object-stroke-to-path +add_cli_test(actions-object-stroke-to-path INPUT_FILENAME path.svg + PARAMETERS --actions=select-by-id:cross$object-stroke-to-path$select-by-selector:path\:nth-of-type\(2\)$object-set-attribute:stroke,red$export-id:cross$export-id-only + OUTPUT_FILENAME actions-object-stroke-to-path.png + REFERENCE_FILENAME actions-object-stroke-to-path_expected.png) + +add_cli_test(action_stroke-to-path_varied + INPUT_FILENAME stroke-to-path-variations.svg + PARAMETERS --actions=select-all:all$object-stroke-to-path$export-filename:stroke-to-path-variations_out.svg$export-do + EXPECTED_FILES stroke-to-path-variations_out.svg + TEST_SCRIPT match_regex_fail.sh stroke-to-path-variations_out.svg "(#mixed)|(#fillet)|(object-to-path$export-id:MyRect$export-id-only + OUTPUT_FILENAME actions-object-to-path.svg + TEST_SCRIPT match_regex.sh actions-object-to-path.svg "object-unlink-clones$object-set-attribute:fill,red$export-id:clone$export-id-only + OUTPUT_FILENAME actions-object-unlink-clones.png + REFERENCE_FILENAME actions-object-unlink-clones_expected.png) +# open-page +add_cli_test(actions-open-page PARAMETERS --actions=open-page:3$file-open:${CMAKE_CURRENT_SOURCE_DIR}/testcases/pdf-pages.pdf$export-filename:actions-open-page.png$export-do + OUTPUT_FILENAME actions-open-page.png + REFERENCE_FILENAME actions-open-page_expected.png) + +# query-all: test = query-all +add_cli_test(actions-query-all INPUT_FILENAME rects.svg PARAMETERS --actions=select-by-id:rect2$query-all PASS_FOR_OUTPUT ${query_all_expected}) + +# query-height: test = query-height +add_cli_test(actions-query-height INPUT_FILENAME rects.svg PARAMETERS --actions=select-by-id:rect2$query-height PASS_FOR_OUTPUT 70) + +# query-width: test = query-width +add_cli_test(actions-query-width INPUT_FILENAME rects.svg PARAMETERS --actions=select-by-id:rect2$query-width PASS_FOR_OUTPUT 80) + +# query-x: test = query-x +add_cli_test(actions-query-x INPUT_FILENAME rects.svg PARAMETERS --actions=select-by-id:rect2$query-x PASS_FOR_OUTPUT 110) + +# query-y: test = query-y +add_cli_test(actions-query-y INPUT_FILENAME rects.svg PARAMETERS --actions=select-by-id:rect2$query-y PASS_FOR_OUTPUT 20) + +# quit-inkscape +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-quit-inkscape PARAMETERS --actions=quit-inkscape FAIL_FOR_OUTPUT ".+") + +# select: it is deprecated +# select-all +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-select-all INPUT_FILENAME path.svg PARAMETERS --actions=select-all$select-list +# PASS_FOR_OUTPUT "^heart .+\nbottom-left-corner .+\nsquare .+\ntop-right-corner .+\narc-big .+\narc-small .+\ngates .+\ncross .+\nclone .+$") + +# select-by-class +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-select-by-class INPUT_FILENAME path.svg PARAMETERS --actions=select-by-class:corner$select-list +# PASS_FOR_OUTPUT "^bottom-left-corner .+\ntop-right-corner .+$") + +# select-by-element +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-select-by-element INPUT_FILENAME path.svg PARAMETERS --actions=select-by-element:use$select-list +# PASS_FOR_OUTPUT "^clone .+$") + +# select-by-id +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-select-by-id INPUT_FILENAME path.svg PARAMETERS --actions=select-by-id:top-right-corner$select-list +# PASS_FOR_OUTPUT "^top-right-corner .+$") + +# select-by-selector = svg > path:nth-child(2n) ~ *[fill=red]:nth-of-type(even) +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-select-by-selector INPUT_FILENAME path.svg PARAMETERS --actions=select-by-selector:svg\ >\ path:nth-child\(2n\)\ ~\ *\[fill\=red\]:nth-of-type\(even\)$select-list +# PASS_FOR_OUTPUT "^arc-big .+\nclone .+$") + +# select-clear +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-select-clear INPUT_FILENAME path.svg PARAMETERS --actions=select-by-element:path$select-clear$select-by-id:cross$select-list +# PASS_FOR_OUTPUT "^cross .+$") + +# select-invert +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-select-invert INPUT_FILENAME path.svg PARAMETERS --actions=select-by-selector:path:nth-of-type\(2n\)$select-invert:all$select-list +# PASS_FOR_OUTPUT "^heart .+\nsquare .+\narc-big .+\ngates .+\nclone .+$") + +# select-list +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-select-list INPUT_FILENAME path.svg PARAMETERS --actions=select-by-selector:*[stroke-width]:nth-child\(3n+3\)$select-list +# PASS_FOR_OUTPUT "^gates cloned: false ref: 1 href: 0 total href: 0\n$") + +# system-data-directory: test = system-data-directory +add_cli_test(actions-system-data-directory PARAMETERS --actions=system-data-directory ENVIRONMENT unset PASS_FOR_OUTPUT "inkscape\n$") + +# transform-remove +add_cli_test(actions-transform-remove INPUT_FILENAME pyramids.svg + PARAMETERS --actions=select-by-id:quad_snapped_4$transform-rotate:2$transform-remove + OUTPUT_FILENAME actions-transform-remove.png + REFERENCE_FILENAME actions-transform-remove_expected.png) + +# transform-rotate +add_cli_test(actions-transform-rotate INPUT_FILENAME pyramids.svg + PARAMETERS --actions=select-by-id:rect_snapped_4$transform-rotate:45 + OUTPUT_FILENAME actions-transform-rotate.png + REFERENCE_FILENAME actions-transform-rotate_expected.png) + +# transform-scale +add_cli_test(actions-transform-grow INPUT_FILENAME pyramids.svg + PARAMETERS --actions=select-by-id:quad_snapped_1$transform-grow:10 + OUTPUT_FILENAME actions-transform-grow.png + REFERENCE_FILENAME actions-transform-grow_expected.png) + +# transform-translate +add_cli_test(actions-transform-translate INPUT_FILENAME pyramids.svg + PARAMETERS --actions=select-by-id:quad_snapped_1$transform-translate:-5,-5 + OUTPUT_FILENAME actions-transform-translate.png + REFERENCE_FILENAME actions-transform-translate_expected.png) + +# unselect: it is deprecated +# unselect-by-id +# Failed because of https://gitlab.com/inkscape/inkscape/-/issues/1565 +# add_cli_test(actions-unselect-by-id INPUT_FILENAME path.svg PARAMETERS --actions=select-by-element:path$unselect-by-id:heart,bottom-left-corner,square,top-right-corner,arc-big,arc-small,gates$select-list +# PASS_FOR_OUTPUT "^cross .+$") + +# user-data-directory: test = user-data-directory +add_cli_test(actions-user-data-directory PARAMETERS --actions=user-data-directory ENVIRONMENT unset PASS_FOR_OUTPUT "inkscape\n$") + +# vacuum-defs +# window-close +# window-open + +# tests x/y values are not swapped in tspans. +add_cli_test(action_test_multiline_anchoring + INPUT_FILENAME multiline-anchoring.svg + PARAMETERS --actions=select-by-id:grouped_text$transform-translate:10,0$transform-translate:-10,0$export-filename:multiline-anchoring_out.svg$export-plain-svg$export-do + EXPECTED_FILES multiline-anchoring_out.svg + TEST_SCRIPT match_regex_fail.sh multiline-anchoring_out.svg "(x=\"[3-9][0-9]{2}\")|(x=\"[12][0-9]{3}\")|(y=\"[0-9]{2}\")|(y=\"1[0-9]{2}\")") + +########################### +### 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) # check png size is correct + 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..06da1fa --- /dev/null +++ b/testfiles/cli_tests/check_output.sh @@ -0,0 +1,78 @@ +#!/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 + + case ${script} in + *.py) + interpreter=python3 + ;; + *) + interpreter=sh + ;; + esac + + if ! $interpreter ${script} "${arguments_array[@]}"; then + echo "Error: Additional test script failed." + echo "Full call: $interpreter ${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/identify.sh b/testfiles/cli_tests/identify.sh new file mode 100644 index 0000000..57bacb7 --- /dev/null +++ b/testfiles/cli_tests/identify.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later + +file1=$1 +PATTERN='$2' + +test -f "${file1}" || { echo "identify.sh: File '${file1}' not found."; exit 1; } +if ! $(identify "${file1}" | grep -q -e ${PATTERN} - ); then + echo "expected $2 but got" `identify "${file1}"` + 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/actions-file-open_expected.png b/testfiles/cli_tests/testcases/actions-file-open_expected.png new file mode 100644 index 0000000..c030bb6 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-file-open_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-object-align_expected.png b/testfiles/cli_tests/testcases/actions-object-align_expected.png new file mode 100644 index 0000000..e836df8 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-object-align_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-object-distribute_expected.png b/testfiles/cli_tests/testcases/actions-object-distribute_expected.png new file mode 100644 index 0000000..c20de15 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-object-distribute_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-object-set-attribute_expected.png b/testfiles/cli_tests/testcases/actions-object-set-attribute_expected.png new file mode 100644 index 0000000..c4ce8d3 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-object-set-attribute_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-object-simplify-path_expected.png b/testfiles/cli_tests/testcases/actions-object-simplify-path_expected.png new file mode 100644 index 0000000..4b0f4e2 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-object-simplify-path_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-object-stroke-to-path_expected.png b/testfiles/cli_tests/testcases/actions-object-stroke-to-path_expected.png new file mode 100644 index 0000000..23ebe57 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-object-stroke-to-path_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-object-unlink-clones_expected.png b/testfiles/cli_tests/testcases/actions-object-unlink-clones_expected.png new file mode 100644 index 0000000..9ad52b3 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-object-unlink-clones_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-open-page_expected.png b/testfiles/cli_tests/testcases/actions-open-page_expected.png new file mode 100644 index 0000000..301804f Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-open-page_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-transform-grow_expected.png b/testfiles/cli_tests/testcases/actions-transform-grow_expected.png new file mode 100644 index 0000000..4bcf5aa Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-transform-grow_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-transform-remove_expected.png b/testfiles/cli_tests/testcases/actions-transform-remove_expected.png new file mode 100644 index 0000000..f0cbc56 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-transform-remove_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-transform-rotate_expected.png b/testfiles/cli_tests/testcases/actions-transform-rotate_expected.png new file mode 100644 index 0000000..ce66cc6 Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-transform-rotate_expected.png differ diff --git a/testfiles/cli_tests/testcases/actions-transform-translate_expected.png b/testfiles/cli_tests/testcases/actions-transform-translate_expected.png new file mode 100644 index 0000000..ef3c5ad Binary files /dev/null and b/testfiles/cli_tests/testcases/actions-transform-translate_expected.png differ 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 @@ + + + + + + + + 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 @@ + + + diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.emf b/testfiles/cli_tests/testcases/export-area-drawing_expected.emf new file mode 100644 index 0000000..5f64188 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-drawing_expected.emf differ 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,]L#qUH]rg8Q\:I]joW(", + UT5GOfW;#Y*)i!>1tE8h,\O.4@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%u=\1nfi>Dt1^ + m\2+-c]BBi2i`IYj`'T"^oUP>:.?sfTqd:L\ArYrL#)c4@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$/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@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[ + /@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_Jpia0O8LA]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\/@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. + 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]3RRI5kY^>2]rrrtQef`SM6o')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+A>!I_dVMNgPbo]l#JE5!M'Zlih^"h8gAF26EQqNH@\[+;>T + A>K:p51oNcoDC8aRT_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>+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.!tcdFCkEm\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^-WKiCIpoF4KUjJ>R-nG@"p?u?t0[_InDt-e\RR\kW,0ep?6t$*! + `VuCH#/g@rmNipRYcHZIPE^I-=@mN+N@FNZ<_K + >?UaRboK$4FWs + 8)KhR0W=;[Hgq*4!fpA[goOa0*Nr;4YQ.og[X4=VP]"k8`9WU2,!,+c*agq4\XUWH.p4@XY + Mc1[!*hPX`_;!sm9EkPV^Jr)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\:(XWJ^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?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:<`h)!V9*&PI3rQ]4A2gf>>:/.8\D5]ZeR*gLVJp1b%u6m`!.8`nha2t; + ;lP,"B*'\kdClV/WVk8Y87[@N@K"`cCiX-q/;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"R+@\*c2a/N%CD0$CuB'OliOV%==V5[YUXCQ?6l + \Z%ZJ[f@I`d-]-CiHA."Y]E_8Vi?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``JAMA,iT.Er#1j%eMct$c%Hp> + :1dZapRbhnKAEGcF)U74]&ek/XNO4q3I!l'Gc3,Vm[k`)n&S('VFk#Jh+F!86'a(fFg?cq/ + $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)`Fa\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@: + 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.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-/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%4uTI[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+JnBbYDs5Y7"4>#^7hb2'"@&f$A63]lG<$Y + &+C$^"d$7-7YSOK#K[K>^c)rC5iVJYaYkR676NnbkQ/DkYQ,=tI\ + :'-u)&2e-mO(6k!8gUT!/\lZ\C@1UjgqYnci\Y_@0%W+kJ.^__H,kanj=tI\Gc:@)\ + i"'mNk*i!8gUT!/]I&ZcJfD=*7=7Ta1@I_?*9`JUIn8$@m$4@trLYag9luh,aIcpgHl)t$^hl\sUrsG^MT]b?6+1"KDa'uHp_@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\_X8.\+,6jGZD"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+O`6QLrlsel!5aZ2!XW=s"G"!Y=+: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,hr9Z`;)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#$1hgZL$r7_7V9I/8)hQ/rr4\oZ'1f + =](=0[B7.=Yh+4I0'WK(OT9?)+:DC[^A?A]B0Yq)YQ4i(iY,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[QJ.=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!>fC*;V + _u]PB;#=hkn-WKi(bB*rE?8,"qp;$6XFq(\[F]e_g/A\:4C(q4ol@W^mVC3'#Wo$Yk+TESgS[:+`3A7\LL'&MWb@70HR- + U;dCjF;kmG4l=G:U0^4"fuIXDr-L2UFqQ7MW@dYU8JQ_HEN:\SD'@nUIZY%R^e,LK9crD5:mli4NNH.?&hkM0=C#n.H?=n*-LMoWd++Rfm#B(Ok4q* + WcWI\G9VRuo74^GfJ.mLm-^1[CWGZ+XIkX##NGKCkg&6tb3mBob'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"[mdI8Bgi6rd797H"E$>J3\q*Yha"DN;RC3f''>Sr,`$fA5]?,NINc)"=32Z:=s]Yd@]g:=4j>d8no + jKMo^QbHl54eQpGC(,Jaj-p].=3G/=ETbrNl..#l + sDS'_\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@6\4KHt6AT0EQeT[XII_,VO.23Pko5aK&!L_*g4T,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'ArJYV:PX+@Ig9ggF.$6:Cl+-nGqY,: + `]aa?gX;Ds@!RJ0:Mh5Wf\Trm(Ok>l&jX+:'AH&T.AFl>j + =mr8>*-nLIYQ]rDii]O8So&Ul7sTs0&oT3&%FMW]*-;Wl_!!Mfu.$Wupb($ + BjaZ1PXLJ3PG5@*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'haLKreJtLq:E + A$HJce)o(8<-H9en+_ECa]3)E_m+3RVGB@b!r%k;Cr!^3PgpZ%hn+Qt4)i/]NAeOd`$IdlM + f@RdfF=ZrKGpMS@FjN6"'edX]=n]%kR23^9Dh<'6Qb*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\:hkHrioahMM/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<$4FrORSm9McmQ@8;mS@mI*GY]$s/ + !/g?/.`@gWd)f"IP5aPQBeK_6 + \?B%!EIV&ZOUTd"VHpGY5)&[.T0!2E#fbR&R + 8X>Xg@)D-P-rF"TiA-MKqDbnKB*1D:Pr)6KE\]jgqYnn-!3pYWr3eSr.gip[?Ja]KnH]/aB + LBnp,N"3B^VrGQKTs=ENrC[C=cE#/jB$l0U1i]>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+5NtWZbW6HdA: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!nNONcDXu6))[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>#8P3-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^VqOe%"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*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'87H6TXLDsIOY;0bl['-I#=;iU5319Yu,9t4?6de/N + a_?-G%'c$Fo)J!RpX]Vl'kc[>Mb;.mII/oe"(WJst1K`sg),o-$qTANR0Kc[3U + ]@^Lp(?eWT@it]+/sdF;19[%)5@j!n94@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.AXZ2p3Kq/.d8/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 + e>15RVcM'%ld'B&RD[Q99=uU]b@TMMAR<]s0u\E0LqbJi/.a.8="7L`I0L2J+?`V5'YcH[? + kesn^>_GpSXeS_>imn^bCmImX2JA,'G^tBc`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%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=it_-nV>%iCiQ,P5i@&rWHP_@#:P\5iD<81!aX=L#U)_5Eq + e1B/$oTohb/_-+EJlONY;.c^>N)K];%Do2'G^t_5>j5^Zt\?l-V8hF2m,BOa^g--lR_Q=,piF2_K`VC3u,?sei*CVi)Ec\CZ\$\#%fo!$e$G:pDDX- + ?:1l$b8VHLB%Wbt[/&V*\UA!;i"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* + *77: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 + EZA`D6Qs`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 new file mode 100644 index 0000000..17e19ec Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-drawing_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.png b/testfiles/cli_tests/testcases/export-area-drawing_expected.png new file mode 100644 index 0000000..8c8ef62 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-drawing_expected.png differ 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,]L#qUH]rg8Q\:I]joW(", + UT5GOfW;#Y*)i!>1tE8h,\O.4@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%u=\1nfi>Dt1^ + m\2+-c]BBi2i`IYj`'T"^oUP>:.?sfTqd:L\ArYrL#)c4@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$/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@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[ + /@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_Jpia0O8LA]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\/@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. + 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]3RRI5kY^>2]rrrtQef`SM6o')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+A>!I_dVMNgPbo]l#JE5!M'Zlih^"h8gAF26EQqNH@\[+;>T + A>K:p51oNcoDC8aRT_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>+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.!tcdFCkEm\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^-WKiCIpoF4KUjJ>R-nG@"p?u?t0[_InDt-e\RR\kW,0ep?6t$*! + `VuCH#/g@rmNipRYcHZIPE^I-=@mN+N@FNZ<_K + >?UaRboK$4FWs + 8)KhR0W=;[Hgq*4!fpA[goOa0*Nr;4YQ.og[X4=VP]"k8`9WU2,!,+c*agq4\XUWH.p4@XY + Mc1[!*hPX`_;!sm9EkPV^Jr)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\:(XWJ^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?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:<`h)!V9*&PI3rQ]4A2gf>>:/.8\D5]ZeR*gLVJp1b%u6m`!.8`nha2t; + ;lP,"B*'\kdClV/WVk8Y87[@N@K"`cCiX-q/;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"R+@\*c2a/N%CD0$CuB'OliOV%==V5[YUXCQ?6l + \Z%ZJ[f@I`d-]-CiHA."Y]E_8Vi?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``JAMA,iT.Er#1j%eMct$c%Hp> + :1dZapRbhnKAEGcF)U74]&ek/XNO4q3I!l'Gc3,Vm[k`)n&S('VFk#Jh+F!86'a(fFg?cq/ + $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)`Fa\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@: + 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.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-/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%4uTI[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+JnBbYDs5Y7"4>#^7hb2'"@&f$A63]lG<$Y + &+C$^"d$7-7YSOK#K[K>^c)rC5iVJYaYkR676NnbkQ/DkYQ,=tI\ + :'-u)&2e-mO(6k!8gUT!/\lZ\C@1UjgqYnci\Y_@0%W+kJ.^__H,kanj=tI\Gc:@)\ + i"'mNk*i!8gUT!/]I&ZcJfD=*7=7Ta1@I_?*9`JUIn8$@m$4@trLYag9luh,aIcpgHl)t$^hl\sUrsG^MT]b?6+1"KDa'uHp_@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\_X8.\+,6jGZD"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+O`6QLrlsel!5aZ2!XW=s"G"!Y=+: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,hr9Z`;)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#$1hgZL$r7_7V9I/8)hQ/rr4\oZ'1f + =](=0[B7.=Yh+4I0'WK(OT9?)+:DC[^A?A]B0Yq)YQ4i(iY,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[QJ.=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!>fC*;V + _u]PB;#=hkn-WKi(bB*rE?8,"qp;$6XFq(\[F]e_g/A\:4C(q4ol@W^mVC3'#Wo$Yk+TESgS[:+`3A7\LL'&MWb@70HR- + U;dCjF;kmG4l=G:U0^4"fuIXDr-L2UFqQ7MW@dYU8JQ_HEN:\SD'@nUIZY%R^e,LK9crD5:mli4NNH.?&hkM0=C#n.H?=n*-LMoWd++Rfm#B(Ok4q* + WcWI\G9VRuo74^GfJ.mLm-^1[CWGZ+XIkX##NGKCkg&6tb3mBob'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"[mdI8Bgi6rd797H"E$>J3\q*Yha"DN;RC3f''>Sr,`$fA5]?,NINc)"=32Z:=s]Yd@]g:=4j>d8no + jKMo^QbHl54eQpGC(,Jaj-p].=3G/=ETbrNl..#l + sDS'_\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@6\4KHt6AT0EQeT[XII_,VO.23Pko5aK&!L_*g4T,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'ArJYV:PX+@Ig9ggF.$6:Cl+-nGqY,: + `]aa?gX;Ds@!RJ0:Mh5Wf\Trm(Ok>l&jX+:'AH&T.AFl>j + =mr8>*-nLIYQ]rDii]O8So&Ul7sTs0&oT3&%FMW]*-;Wl_!!Mfu.$Wupb($ + BjaZ1PXLJ3PG5@*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'haLKreJtLq:E + A$HJce)o(8<-H9en+_ECa]3)E_m+3RVGB@b!r%k;Cr!^3PgpZ%hn+Qt4)i/]NAeOd`$IdlM + f@RdfF=ZrKGpMS@FjN6"'edX]=n]%kR23^9Dh<'6Qb*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\:hkHrioahMM/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<$4FrORSm9McmQ@8;mS@mI*GY]$s/ + !/g?/.`@gWd)f"IP5aPQBeK_6 + \?B%!EIV&ZOUTd"VHpGY5)&[.T0!2E#fbR&R + 8X>Xg@)D-P-rF"TiA-MKqDbnKB*1D:Pr)6KE\]jgqYnn-!3pYWr3eSr.gip[?Ja]KnH]/aB + LBnp,N"3B^VrGQKTs=ENrC[C=cE#/jB$l0U1i]>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+5NtWZbW6HdA: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!nNONcDXu6))[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>#8P3-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^VqOe%"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*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'87H6TXLDsIOY;0bl['-I#=;iU5319Yu,9t4?6de/N + a_?-G%'c$Fo)J!RpX]Vl'kc[>Mb;.mII/oe"(WJst1K`sg),o-$qTANR0Kc[3U + ]@^Lp(?eWT@it]+/sdF;19[%)5@j!n94@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.AXZ2p3Kq/.d8/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 + e>15RVcM'%ld'B&RD[Q99=uU]b@TMMAR<]s0u\E0LqbJi/.a.8="7L`I0L2J+?`V5'YcH[? + kesn^>_GpSXeS_>imn^bCmImX2JA,'G^tBc`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%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=it_-nV>%iCiQ,P5i@&rWHP_@#:P\5iD<81!aX=L#U)_5Eq + e1B/$oTohb/_-+EJlONY;.c^>N)K];%Do2'G^t_5>j5^Zt\?l-V8hF2m,BOa^g--lR_Q=,piF2_K`VC3u,?sei*CVi)Ec\CZ\$\#%fo!$e$G:pDDX- + ?:1l$b8VHLB%Wbt[/&V*\UA!;i"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* + *77: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 + EZA`D6Qs`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..4c5abe8 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-area-drawing_expected.svg @@ -0,0 +1,65 @@ + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-area-drawing_expected.wmf b/testfiles/cli_tests/testcases/export-area-drawing_expected.wmf new file mode 100644 index 0000000..07f7e13 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-drawing_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.emf b/testfiles/cli_tests/testcases/export-area-page_expected.emf new file mode 100644 index 0000000..1a8b98c Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-page_expected.emf differ 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-__?-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=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;abPp0MhH9,SQVo3fS + s\u.k)kt>XMp#fQ$3d:mHO%;XO/V0]Z-aI_3GWUlAh'GdjFYQ4#L[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:;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%.;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>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 + 'd\@j--nG?+hVL+AhXomnn`!-RRp.Blb#h5tKIAAO$dS+/)K0ijof2 + K5hTJpTcYd:>793<>6CXc`5.j9l!Ea='V3X;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 + =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]K2[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'GMc=&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\ZqE.rC+KcXb`Z + FO0e?HZ\$SYQBU@0&?.pui?CH%&0m&FWTF%lf8WgW%@eGFddY/#h$4FY3UB_kt(uSE*O*I$)$nEe)LVa+3jOf$;#,D'MmOb$ + +`)EFX=C4X>iQs,V;G^Hq,*'G6JAL$Delguq8k,Zp%\e*]12N+02VcYl'*]EJDJ;PP(LOPnCWTro*iW]X + mRg5TnMUK8rBq7F'>#X>F*,-nA<Ip;KJ,`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[rS0YK;Hu1@X/.O25PoQ7Yg!X%'Gc4eZeHhG4*$8P8F_r&?5ds@rKS(DZQ#p.CF)D + JrVFtrm!dpP(Ok$6LD1MSR<)R[`]J*3oEauITG&nG5^*,& + 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=@'!4k31bm#*\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#MscI;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/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%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]?^KcVX,pAf,.=9(f#+'iVXfIM8ur7hCe6"'d23HAY + e6")9dJ,-V[G_HP6mk8rOj$4FYjnM_4#'_\El.6mP,D + bsO97S^T[hk722\qg4="2$p.!>mieqE0DIf';\oEt@aEK`tlFjD/fG$7 + I:H[n%'/-$om?Ckk-fOg[$5PG.r:fm]e:@4T\:tUk)Oe6uN2^g3W,H(902^iJmKgkR*YQ0W + PhEmig;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%HS4S%m@]a'G`t3%NSng:tW + s;OSmH-4@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"%Hp*MQkob7K=rX7( + `&:1qW^;5G>;H'"D)Q]O7)f'o7(VeJ#+L!IW]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!egfjFY^cF.B8;q2B"Q4J< + (9iZZ&cgcW@0'#)RQ"9=>Bk%dMf!$d":ugm(9i?Q&cgdL_?/#i1i9r5C4Z+TVAZ@OllKL(QZjbp".(IOT9um_?08>;7\T6k@?Mi?.gG'"l,=J/TdQ;*Y-(?TLUn^`sg&jTp#Ye[ + qtYXd]9*l87P+>H_qTHbNEOXOb$"H_7a/9$rFjic=%!Pg,k)o#3_oT: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;$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-2*^uke>5e?("RK'ZB + XXT<.Cb4M\rGCfSCtKALfW4WEGA`-LCa+r^XjMs-lA"s1tpWdXR.!:B1?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`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=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`MYmW4Lo5F@[<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_rm#'"PF?gZ)>n[V + nV6:1\.SfAQYmJ+oRiS:/e*>M15%5_,-:NfECnIh#':Y9RDhZF$BQg4ZWTs48BkhjB?BktF(G=2+f^WHO%-aU[e7G@Sil$3crqGcP + ']oGnWXL''sA[#T03[sE'2@78):F + igunj.@&kPiksqB&237fn4EF]d:6Omb2W?[NZH\u`p^HMkro4m\lNdLYem@!)8l&V + 9Z_s$kW)TcP4"2WD9,gmu^Iqp.!-"k0_MZZAi//=f,s5+FRf%!/6+k[=&+V].uH(`i/fB8mbg'OrT10T7'A3a + i`uBmA[O2OhSO0,Voc8s*H`2"XX/3P+nQGW+pTTqC2T/S1#oiiM.C6@#Y.F>AUb=P)8V + k5-.))n7El7@iNZY8rr=A..%7%4mYR$OJ.+M*2S=X$:f'c7=D?,h,KgjqtF_#iBr$O'rrVT + =:A1,r'Z9SN9.'*&P>=9R7-,#9qRs*SpNWr&R`V$A.%;-3tTdn3>7#%um + ?W=0Nn8P<'uIRUPi]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<m'Qu$4Ff3Br)$5(f0TAWp!O4QSnh`'GcMPf9GR#@Q]PqX60GD^:F?dU9HoL5+uFMJ+H7rW + uHR?$4Fd`M2Li!Vl9b_QG1-8#bnOg>dc%%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;)+YT^?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$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#?<X&H:k0>.dBSs;;6Rag.>gX?3/-BY^jc[X'!ZffCsG + jfQR(:r$=M%@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^2ei;H1$/[<6OmA)4`^Ko=9l3_d8e + GN46<^n4G*5hq]*/Eb]!-aXVs>sn;=MDGVIG"iPZlePZL!Dln6(P\ofB@sGkc-;a7(YQ#hB + N*a;&*r$Yp"1d@5_JJK5OJN4;-:UE5+l@F>0jgmYjGV_2r6)iIdupoF'IbDHF + LnoUTf8EbZ7 + 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 + >[73\F + RcBfND<%)B;2DEIjV17Dmjmmn!5&@TMM]X/jD%@\56;C=#R(W-R + 0ktlIC%.,Pu+leG=94`L'7\TS[U:+t+iji%*\c.TJo#^\ZIh4$oaImh5Rm + <.uAA5Dt[?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.14iFJu0f^"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(;(nm[q + !s]TupX-OK3l<>uea#p)TaJ0%YWu%'n//cEs*BEE+0?sHRr)!SCV$/9:^,QM=$15?ECo'G^t9;(CkQcX/+B7k8=)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+$O"Ze.dC0FXM8utXU/jigG-fXZJEm@`.p7&ihl/.7U@Mp&2$f@G0%rh=!,sB2[]M_iSG_W8tVlD3YT#9D;J(J4`iDufPL + _"J"flc,ke\"d^+F*V4sR=rcY/`(@Wj7K>HrEKUX$r)D7Ke'"VSYLOW*0CqeEJ`->S(%j]gpaGYZ>'KtRBa,gMMB3m(gYiBT0 + :/?95U(GX76R:Alj3,(>'K)P!sU!Q=H=/gm1]U'sB=Y+hMC*Z?LL7-e$F2s,!6Gq8TcmO:?\+f/>>($[L`Dagkk0/@gl2Jp*0QANU#aH9#356Z*[Er4+m":sjtNtT&'oFgU+L/?*;R,G+;Wj3 + ;:!t("3#'>LJhFftbmO?dO`F*Lgf6tSm5MT;C1G(/EW*!Ksj[rs45l&-O + HKNN?,Mk`\>WOUk?ufT'pPI4G\>huq3aXL:RCgi2bE]pGJb$1*H58*t-f./`gaHHC0KJatp + fW"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=#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'pU/R!BBS + SONQ07KdQ_:QJn3*SASfdleR+`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;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 + IplQjV$abhHtJLQ0@Ot_?.QY8OYeaYa"p2MI)]c0Rg4jI + c:sU]eo%3$d0iR]Nd'T@=`r5UnXIDa7=>!HX]ghp28R[1#l)m'3?+Qi?Zttns.KYM%:H'-0'mcNt:iN= + %SWWAg\O;k,EX<'\"PI._W+Wu#*mu9%7ciiPDo+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=!_-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^!7MpRY>]:VV>rd_j!>W\5nZR+Q\1Hq:/kV^EA3lc_K3b9^mQ93f^LckDKi/DtluqXMJ$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\5RB + ;&?KKOqlI&sf7H;";H$4HXZ)AVqhR*eQQLA4j'YrN$K]hAqOO&U' + Ul1>$?f&7'SU'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> +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 new file mode 100644 index 0000000..4a510aa Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-page_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.png b/testfiles/cli_tests/testcases/export-area-page_expected.png new file mode 100644 index 0000000..8bdc9e9 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-page_expected.png differ 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-__?-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=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;abPp0MhH9,SQVo3fS + s\u.k)kt>XMp#fQ$3d:mHO%;XO/V0]Z-aI_3GWUlAh'GdjFYQ4#L[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:;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%.;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>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 + 'd\@j--nG?+hVL+AhXomnn`!-RRp.Blb#h5tKIAAO$dS+/)K0ijof2 + K5hTJpTcYd:>793<>6CXc`5.j9l!Ea='V3X;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 + =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]K2[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'GMc=&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\ZqE.rC+KcXb`Z + FO0e?HZ\$SYQBU@0&?.pui?CH%&0m&FWTF%lf8WgW%@eGFddY/#h$4FY3UB_kt(uSE*O*I$)$nEe)LVa+3jOf$;#,D'MmOb$ + +`)EFX=C4X>iQs,V;G^Hq,*'G6JAL$Delguq8k,Zp%\e*]12N+02VcYl'*]EJDJ;PP(LOPnCWTro*iW]X + mRg5TnMUK8rBq7F'>#X>F*,-nA<Ip;KJ,`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[rS0YK;Hu1@X/.O25PoQ7Yg!X%'Gc4eZeHhG4*$8P8F_r&?5ds@rKS(DZQ#p.CF)D + JrVFtrm!dpP(Ok$6LD1MSR<)R[`]J*3oEauITG&nG5^*,& + 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=@'!4k31bm#*\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#MscI;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/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%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]?^KcVX,pAf,.=9(f#+'iVXfIM8ur7hCe6"'d23HAY + e6")9dJ,-V[G_HP6mk8rOj$4FYjnM_4#'_\El.6mP,D + bsO97S^T[hk722\qg4="2$p.!>mieqE0DIf';\oEt@aEK`tlFjD/fG$7 + I:H[n%'/-$om?Ckk-fOg[$5PG.r:fm]e:@4T\:tUk)Oe6uN2^g3W,H(902^iJmKgkR*YQ0W + PhEmig;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%HS4S%m@]a'G`t3%NSng:tW + s;OSmH-4@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"%Hp*MQkob7K=rX7( + `&:1qW^;5G>;H'"D)Q]O7)f'o7(VeJ#+L!IW]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!egfjFY^cF.B8;q2B"Q4J< + (9iZZ&cgcW@0'#)RQ"9=>Bk%dMf!$d":ugm(9i?Q&cgdL_?/#i1i9r5C4Z+TVAZ@OllKL(QZjbp".(IOT9um_?08>;7\T6k@?Mi?.gG'"l,=J/TdQ;*Y-(?TLUn^`sg&jTp#Ye[ + qtYXd]9*l87P+>H_qTHbNEOXOb$"H_7a/9$rFjic=%!Pg,k)o#3_oT: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;$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-2*^uke>5e?("RK'ZB + XXT<.Cb4M\rGCfSCtKALfW4WEGA`-LCa+r^XjMs-lA"s1tpWdXR.!:B1?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`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=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`MYmW4Lo5F@[<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_rm#'"PF?gZ)>n[V + nV6:1\.SfAQYmJ+oRiS:/e*>M15%5_,-:NfECnIh#':Y9RDhZF$BQg4ZWTs48BkhjB?BktF(G=2+f^WHO%-aU[e7G@Sil$3crqGcP + ']oGnWXL''sA[#T03[sE'2@78):F + igunj.@&kPiksqB&237fn4EF]d:6Omb2W?[NZH\u`p^HMkro4m\lNdLYem@!)8l&V + 9Z_s$kW)TcP4"2WD9,gmu^Iqp.!-"k0_MZZAi//=f,s5+FRf%!/6+k[=&+V].uH(`i/fB8mbg'OrT10T7'A3a + i`uBmA[O2OhSO0,Voc8s*H`2"XX/3P+nQGW+pTTqC2T/S1#oiiM.C6@#Y.F>AUb=P)8V + k5-.))n7El7@iNZY8rr=A..%7%4mYR$OJ.+M*2S=X$:f'c7=D?,h,KgjqtF_#iBr$O'rrVT + =:A1,r'Z9SN9.'*&P>=9R7-,#9qRs*SpNWr&R`V$A.%;-3tTdn3>7#%um + ?W=0Nn8P<'uIRUPi]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<m'Qu$4Ff3Br)$5(f0TAWp!O4QSnh`'GcMPf9GR#@Q]PqX60GD^:F?dU9HoL5+uFMJ+H7rW + uHR?$4Fd`M2Li!Vl9b_QG1-8#bnOg>dc%%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;)+YT^?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$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#?<X&H:k0>.dBSs;;6Rag.>gX?3/-BY^jc[X'!ZffCsG + jfQR(:r$=M%@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^2ei;H1$/[<6OmA)4`^Ko=9l3_d8e + GN46<^n4G*5hq]*/Eb]!-aXVs>sn;=MDGVIG"iPZlePZL!Dln6(P\ofB@sGkc-;a7(YQ#hB + N*a;&*r$Yp"1d@5_JJK5OJN4;-:UE5+l@F>0jgmYjGV_2r6)iIdupoF'IbDHF + LnoUTf8EbZ7 + 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 + >[73\F + RcBfND<%)B;2DEIjV17Dmjmmn!5&@TMM]X/jD%@\56;C=#R(W-R + 0ktlIC%.,Pu+leG=94`L'7\TS[U:+t+iji%*\c.TJo#^\ZIh4$oaImh5Rm + <.uAA5Dt[?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.14iFJu0f^"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(;(nm[q + !s]TupX-OK3l<>uea#p)TaJ0%YWu%'n//cEs*BEE+0?sHRr)!SCV$/9:^,QM=$15?ECo'G^t9;(CkQcX/+B7k8=)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+$O"Ze.dC0FXM8utXU/jigG-fXZJEm@`.p7&ihl/.7U@Mp&2$f@G0%rh=!,sB2[]M_iSG_W8tVlD3YT#9D;J(J4`iDufPL + _"J"flc,ke\"d^+F*V4sR=rcY/`(@Wj7K>HrEKUX$r)D7Ke'"VSYLOW*0CqeEJ`->S(%j]gpaGYZ>'KtRBa,gMMB3m(gYiBT0 + :/?95U(GX76R:Alj3,(>'K)P!sU!Q=H=/gm1]U'sB=Y+hMC*Z?LL7-e$F2s,!6Gq8TcmO:?\+f/>>($[L`Dagkk0/@gl2Jp*0QANU#aH9#356Z*[Er4+m":sjtNtT&'oFgU+L/?*;R,G+;Wj3 + ;:!t("3#'>LJhFftbmO?dO`F*Lgf6tSm5MT;C1G(/EW*!Ksj[rs45l&-O + HKNN?,Mk`\>WOUk?ufT'pPI4G\>huq3aXL:RCgi2bE]pGJb$1*H58*t-f./`gaHHC0KJatp + fW"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=#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'pU/R!BBS + SONQ07KdQ_:QJn3*SASfdleR+`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;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 + IplQjV$abhHtJLQ0@Ot_?.QY8OYeaYa"p2MI)]c0Rg4jI + c:sU]eo%3$d0iR]Nd'T@=`r5UnXIDa7=>!HX]ghp28R[1#l)m'3?+Qi?Zttns.KYM%:H'-0'mcNt:iN= + %SWWAg\O;k,EX<'\"PI._W+Wu#*mu9%7ciiPDo+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=!_-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^!7MpRY>]:VV>rd_j!>W\5nZR+Q\1Hq:/kV^EA3lc_K3b9^mQ93f^LckDKi/DtluqXMJ$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\5RB + ;&?KKOqlI&sf7H;";H$4HXZ)AVqhR*eQQLA4j'YrN$K]hAqOO&U' + Ul1>$?f&7'SU'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> +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 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-area-page_expected.wmf b/testfiles/cli_tests/testcases/export-area-page_expected.wmf new file mode 100644 index 0000000..92421b3 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-page_expected.wmf differ 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ëé³ýn´’ÎÒ×ï‚ó7 7ÑèÿÊ—#*[Kø!ÁSÆ'½¾e‡àDÏX±í9mtÖ1 QÙn0sÎH \uà:•´€•Áâ“xg‘–„Ô„kIÔ³ÙÊlʵ‘ÄâoL9Ì°¼&0Í#;T> + >> +>> +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 + /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 new file mode 100644 index 0000000..6bf9b04 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-page_export-id.png differ 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 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-area-snap_expected.png b/testfiles/cli_tests/testcases/export-area-snap_expected.png new file mode 100644 index 0000000..f35894b Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area-snap_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-area_expected.png b/testfiles/cli_tests/testcases/export-area_expected.png new file mode 100644 index 0000000..c9ded26 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-area_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-background-opacity_expected.eps b/testfiles/cli_tests/testcases/export-background-opacity_expected.eps new file mode 100644 index 0000000..4f5eb82 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-background-opacity_expected.eps @@ -0,0 +1,86 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Sat Apr 11 20:06:29 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 113 75 +%%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 75 +%%EndPageSetup +q 0 0 113 75 rectclip +1 0 0 -1 0 75 cm q +1 1 0.5 rg +0 0 112.5 75 re f +1 0 0 rg +0 37.5 37.5 37.5 re f +0 0.501961 0 rg +37.5 0 37.5 37.5 re f +0 0 1 rg +75 37.5 37.5 37.5 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-background-opacity_expected.pdf b/testfiles/cli_tests/testcases/export-background-opacity_expected.pdf new file mode 100644 index 0000000..26bdf75 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-background-opacity_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-background-opacity_expected.png b/testfiles/cli_tests/testcases/export-background-opacity_expected.png new file mode 100644 index 0000000..9c19536 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-background-opacity_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-background-opacity_expected.ps b/testfiles/cli_tests/testcases/export-background-opacity_expected.ps new file mode 100644 index 0000000..0afec8e --- /dev/null +++ b/testfiles/cli_tests/testcases/export-background-opacity_expected.ps @@ -0,0 +1,123 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Sat Apr 11 20:07:25 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 40x26mm 113 75 0 () () +%%BoundingBox: 0 0 113 75 +%%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: 40x26mm +%%PageBoundingBox: 0 0 113 75 +113 75 cairo_set_page_size +%%EndPageSetup +q 0 0 113 75 rectclip +1 0 0 -1 0 75 cm q +1 1 0.5 rg +0 0 112.5 75 re f +1 0 0 rg +0 37.5 37.5 37.5 re f +0 0.501961 0 rg +37.5 0 37.5 37.5 re f +0 0 1 rg +75 37.5 37.5 37.5 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-background-opacity_expected.svg b/testfiles/cli_tests/testcases/export-background-opacity_expected.svg new file mode 100644 index 0000000..e478c6f --- /dev/null +++ b/testfiles/cli_tests/testcases/export-background-opacity_expected.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-background_expected.emf b/testfiles/cli_tests/testcases/export-background_expected.emf new file mode 100644 index 0000000..6263304 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-background_expected.emf differ diff --git a/testfiles/cli_tests/testcases/export-background_expected.eps b/testfiles/cli_tests/testcases/export-background_expected.eps new file mode 100644 index 0000000..f58830e --- /dev/null +++ b/testfiles/cli_tests/testcases/export-background_expected.eps @@ -0,0 +1,86 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Sat Apr 11 19:29:54 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 113 75 +%%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 75 +%%EndPageSetup +q 0 0 113 75 rectclip +1 0 0 -1 0 75 cm q +1 1 0 rg +0 0 112.5 75 re f +1 0 0 rg +0 37.5 37.5 37.5 re f +0 0.501961 0 rg +37.5 0 37.5 37.5 re f +0 0 1 rg +75 37.5 37.5 37.5 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-background_expected.pdf b/testfiles/cli_tests/testcases/export-background_expected.pdf new file mode 100644 index 0000000..a5887b7 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-background_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-background_expected.png b/testfiles/cli_tests/testcases/export-background_expected.png new file mode 100644 index 0000000..1a3a34f Binary files /dev/null and b/testfiles/cli_tests/testcases/export-background_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-background_expected.ps b/testfiles/cli_tests/testcases/export-background_expected.ps new file mode 100644 index 0000000..5055f6b --- /dev/null +++ b/testfiles/cli_tests/testcases/export-background_expected.ps @@ -0,0 +1,123 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Sat Apr 11 19:30:09 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 40x26mm 113 75 0 () () +%%BoundingBox: 0 0 113 75 +%%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: 40x26mm +%%PageBoundingBox: 0 0 113 75 +113 75 cairo_set_page_size +%%EndPageSetup +q 0 0 113 75 rectclip +1 0 0 -1 0 75 cm q +1 1 0 rg +0 0 112.5 75 re f +1 0 0 rg +0 37.5 37.5 37.5 re f +0 0.501961 0 rg +37.5 0 37.5 37.5 re f +0 0 1 rg +75 37.5 37.5 37.5 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-background_expected.svg b/testfiles/cli_tests/testcases/export-background_expected.svg new file mode 100644 index 0000000..7e49fab --- /dev/null +++ b/testfiles/cli_tests/testcases/export-background_expected.svg @@ -0,0 +1,52 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-background_expected.wmf b/testfiles/cli_tests/testcases/export-background_expected.wmf new file mode 100644 index 0000000..3a6d0f4 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-background_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-default-background_expected.eps b/testfiles/cli_tests/testcases/export-default-background_expected.eps new file mode 100644 index 0000000..6aca4538 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-default-background_expected.eps @@ -0,0 +1,86 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Sat Apr 11 19:05:42 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 113 75 +%%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 75 +%%EndPageSetup +q 0 0 113 75 rectclip +1 0 0 -1 0 75 cm q +1 0.814948 0.847259 rg +0 0 112.5 75 re f +1 0 0 rg +0 37.5 37.5 37.5 re f +0 0.501961 0 rg +37.5 0 37.5 37.5 re f +0 0 1 rg +75 37.5 37.5 37.5 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-default-background_expected.pdf b/testfiles/cli_tests/testcases/export-default-background_expected.pdf new file mode 100644 index 0000000..720134d --- /dev/null +++ b/testfiles/cli_tests/testcases/export-default-background_expected.pdf @@ -0,0 +1,70 @@ +%PDF-1.5 +%µí®û +4 0 obj +<< /Length 5 0 R + /Filter /FlateDecode +>> +stream +xœmÌÁ €0 Ð{§ÈÖ¤šÆŽá"Ú“ëþ`’¼È‡Oà?B€š´„a¿ÂôŽÂ©Ì~”Œ²@«0nõ ƉRdóí€Ó¼Æu1‰Î_¹R©dêØüQ@6 ÿ~Yà ´ð$Í +endstream +endobj +5 0 obj + 102 +endobj +3 0 obj +<< + /ExtGState << + /a0 << /CA 0.74902 /ca 0.74902 >> + /a1 << /CA 1 /ca 1 >> + >> +>> +endobj +2 0 obj +<< /Type /Page % 1 + /Parent 1 0 R + /MediaBox [ 0 0 112.5 75 ] + /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.15.10 (http://cairographics.org)) + /Creator + /CreationDate (D:20200411190529+02'00) +>> +endobj +7 0 obj +<< /Type /Catalog + /Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000000547 00000 n +0000000328 00000 n +0000000216 00000 n +0000000015 00000 n +0000000194 00000 n +0000000612 00000 n +0000000899 00000 n +trailer +<< /Size 8 + /Root 7 0 R + /Info 6 0 R +>> +startxref +951 +%%EOF diff --git a/testfiles/cli_tests/testcases/export-default-background_expected.png b/testfiles/cli_tests/testcases/export-default-background_expected.png new file mode 100644 index 0000000..bd530a8 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-default-background_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-default-background_expected.ps b/testfiles/cli_tests/testcases/export-default-background_expected.ps new file mode 100644 index 0000000..2ea710b --- /dev/null +++ b/testfiles/cli_tests/testcases/export-default-background_expected.ps @@ -0,0 +1,123 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Sat Apr 11 19:05:53 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 40x26mm 113 75 0 () () +%%BoundingBox: 0 0 113 75 +%%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: 40x26mm +%%PageBoundingBox: 0 0 113 75 +113 75 cairo_set_page_size +%%EndPageSetup +q 0 0 113 75 rectclip +1 0 0 -1 0 75 cm q +1 0.814948 0.847259 rg +0 0 112.5 75 re f +1 0 0 rg +0 37.5 37.5 37.5 re f +0 0.501961 0 rg +37.5 0 37.5 37.5 re f +0 0 1 rg +75 37.5 37.5 37.5 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-default-background_expected.svg b/testfiles/cli_tests/testcases/export-default-background_expected.svg new file mode 100644 index 0000000..9f328c2 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-default-background_expected.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + + + 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..c86b4ed --- /dev/null +++ b/testfiles/cli_tests/testcases/export-dpi_expected.eps @@ -0,0 +1,272 @@ +%!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 1 173 92 +%%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 1 173 92 +%%EndPageSetup +q 0 1 173 91 rectclip +1 0 0 -1 0 93 cm q +0.9 0.950196 0.9 rg +90 46.5 m 90 71.352 69.852 91.5 45 91.5 c 20.148 91.5 0 71.352 0 46.5 c + 0 21.648 20.148 1.5 45 1.5 c 69.852 1.5 90 21.648 90 46.5 c h +90 46.5 m f +0 0.501961 0 rg +82.5 46.5 m 82.5 67.211 65.711 84 45 84 c 24.289 84 7.5 67.211 7.5 46.5 + c 7.5 25.789 24.289 9 45 9 c 65.711 9 82.5 25.789 82.5 46.5 c h +82.5 46.5 m f +Q q +81 1 92 91 re W n +q +81 1 92 91 re W n +% Fallback Image: x=81 y=1 w=92 h=91 res=300ppi size=437760 +[ 92.16 0 0 -91.2 81 92.2 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 384 + /Height 380 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 384 0 0 -380 0 380 ] +>> +cairo_image + Gb"0WH$n-7S]>_85[9ZQO@)YU%>]^W[&XK"U[)Z!CXq7KgMM)8?pR2Z=ug-('?D1,EY-)"m + Mg0g&-<.`+TV^4mZ9^%0Y*C8*&Ee2mO+"[]"='Jr'%k;hjNB7hiHC,5C]EO4QefMK\p/:MI + @?V@2O`-hl``\UV4")?ZTGXcCe[EeSD3hW[aJgR;&*HA_OG1>regc.qm,pl0_Pb/!sp\3-AN#^8Rj + $KNW;CEJ:Qi\ttiuqf0N!Hen-Ar#U'?,*&,a73%K=-bpk+DAr..*%#88ui"+T5>->N#Trk + KULeDLl8JNoO#_&rFSIkX`P5O\pW@%mjTi",b%7*TcMd2KCacO*rH72%U(W49*7L)PqB)bZ + T]5FNon9kt1o,,i&S=WW&Ri"'E3laYj"f$VKukbrF%VZR>T\jDgfXAiEHXJE,^DZ*jih7)> + $=0=-Ajh>=fUQ4t[D/3^;o8bKl5'qA`@lp7#S!o>]S6Ck'o^'Z%b0I!/iKRQ;)j1kT1umf) + b[])E3-I:[nA^-@lf6U#^EC3!nJg&L?aDS8l*?[fSELdj3u(FR1V`#0!+S6 + nKbE[=mejilK*prj\l9F!?*#o0P)G?]6Xqk9QfeI!jXes.)YD^-=IF8#t8, + $p%-O:dJs7/^:D>9faX_6$;"5k@W)tRsQGOa/@`PjLG68frk5@HkcG)r36!e]'dfMb>:5C"(rPekO/L + !DN901^G,"`L(OTS7hWK/ZPC+_%$_$h5K>2fo^`1Lf&tOEQpir]_9?o'^eN$(k7JrXR_B77Q5P + 9=?r4,gQ.m,aQl?3l>ZNXuC`if6qaksd]qL)u)"/aiKfhM10b_`Jf:Xr<[UR2WZoW74GH45 + !8lkYVGQUT(_G1Q#S"aB'u$HGPBloGJD::h1]uha_jM.jIDF(km0\'ck2'>P$Dm!DK/# + uc9J07rkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN + "+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN" + +N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N]JrkKWN"+N^5/q98`FS + TGEet;1(BMRX7WcP69rd5:TJc-(*q"(_]np!bZJ*--da7j4pr-GM1M9]EVJ+KRmk>*u50m0 + esds_6:3Wak5BL5nmb_=Y5#I>s7V4HJ)Jh)rcu?S"f=M+"[5,9k"kaILPZO + !c?%d"J/NG&bal(U%]eE,em;JERd9u2%R28!-#n.hR((F:.S4YQFF*-647=2>Nt\(3VJ`"u7ujjGA!me[4D99*J + ,p.m*!c,je5)D,DX8lHZM[>YT8tup`p\a9:HZ2LaX`&*#f3p/L6*9!tLck\4&K>":79Sa:Kk'4dW18]/<`/,;Pm0f*ng8Ghg65+IEO3^U + Tis0Z2SqA#p;NkG&O[V#h,&*Db\n$,TJamsiJZa#Q@las,L1V-,,L]2\[WTU]Q2q`D\SZeU + FkbLfuhK9XcD2dA^0gU,$c`d#Vl#!LXNZti=Gj;5O_1!5F"s.ApkF!J)Ck8JNn2N6T+-Ji=Gj;5O_1!5A#< + g&cTQfp]H$,or#C3g;JI]r..*%#QDg1O6JkF#(PPAr..)h8qDNb1I3Gq;D0bd@kYEEfrB04`:1'Rjl6#d#j(S2 + 7j#k>$)Xf]cM(MNqF5We_R)o&\VN]k,PnNiWLEM=u]^!klRZMTngpUiP"pDhLVDTd20Jm + %_pg(.Be6Zm9AmrSGs!VNJ#+3K8%u7B_Go2T^#a4Cg&:GO/,g.Y8KiBf2D];!V]TdU&K + S_UE^NT6S`FlLj(M&!$9^re&5G:"::NNQU!<',IqlOnPW"h^kCq4mSc;:"-_*AYqM\a)L:I + _&hC"jh;"R**8#En>,&=1D5,sVF37/K)j@k*J$Co(LHGK0^O1lX')gX"2'W5H/a&:)YJTlDC%Ti + a6$(uqP*Tq`m'%1RNb9@[J+RT(ebW3OQr;Z"c]*f$P5XXZrskTL(54F$K_#`6A3&hFC"oPJ + 59W&BqsRYXq5=,`XIMni-!=5Na"rdKa?2bZ]5oUm:7QtMM\Fp1h9#R:#QC+>bI_)Pi&TaNL + W9TY%,`thEM-KR3Js&]*]`lh29('g(_>kjF;t&(p6SgN>IFCqE__+Erq!jnql6*bb-g?$kT + ,Q+THc;]ZhL"Th7%%Y7"SuLAfOQ1HmJXr7IQqqjI_Q2Hss\:-)W2@;l4K*c=ob`N3OF6qek + cD]o/CJJ%CI*7l%Bik`I[k)3fub;an_rlM>/]/2PX!Q(hGTieA + I>-'qY1QGA2Z;+!'DgOfJJod[XMgd>5#M=*lpYFm@]`>kj,V"-8&O+En\IP+q2u1WQ?d\t0 + e)H2&]=urufi6)cVkgT9P0ZAKr_R57cG1N4bJ>9Ore0Hg_]NF4_&n7-8:(^KIunDs56CeGp + (e)9+OpUE`;1.0(BK#Ibm&[9qK"^p2#KWt)uL<6c`rF=n-@W_n40QE<7L:`pk*B=p`nRdd% + !r-K5<@=,M\oTR4$r(ZH_O+?.!;GHZ$7"5\X*)b:YOIQmWK5<.7A"l0 + q,8McoccI_:^BFaiOD9A3-Mm>Hn+2G5A,G\<19V]5EU5Rn-@WGnAfX# + [Noa!qNG'IGpMFk_u)7Z#Jo=/;GEJ>cgL,2/_6P#93sGU+CQBNc, + @!a[im/Dq?c[3c\Lteq7u@-3O?XDk-KNb=9($lImF9Q`QUDY!,e"$@T'RNn9jk0l]t&>ibd + -bFj+$:a6Vbu(4A3G/o\YB"Q6K2RK4iQn6%^-^Fo>6R"!%V1jo3b68)AR`n=,qS47J]V7>I + UlU:cpW:-$ibFffelqa8bX+1ethkSKO_R^2&'(8jf#&'O^)YQ%W&Sg0tr6n]FiFmKXIrIE? + bT8>p?L;4lV0RE4NmeAcJ!=f3$\W6O*_-aj(i,qdZh>>[ona#GA$KmdBAQNLpjH!B"(XjJ( + 6mmpk*B.p`mVIcXT.?c6'(LO5St-;GHXNJj8]FHWO'oHN"0krZK_oIjFeFHfo36rTX-U + :uMp_:%1Z)5@Zjr.dE(=C/7'J$@e.PJj0nGl0$F^o:YIur=@O#2?Xo6Dsp.atK_(RA0d\2Jg'\dRhMbpCKNrNc;&gNI_oK(&r=4[tM,)UIY + ^n#$E&%#-u;D#E&Vp=n)8R*2_E6$)5UT#58Ci2fpuX7"KpafSk/Xf:8%qh(H<&0X"HZq;Lp8HZK(Qi&(Q7+Q:H%cVWeu"NW+*?ff5\/'k?)$@f"tV3dJ=B1pYgpk*B+p` + n%UR"?1M"+LkT>ToKi=GiPbi"O=J+h + ^PVjou3QQ4rpZA%4t1k0[Th[+ej%q5`mV"s&#eR(=d*%j7e+(Pbq+)1_9"7QQp+D1+5RQp3 + hmdLJ\+D1+5RQmAmT(!!a+D1+5RQl7&rSS4a6-S8J1k,S1#:er`7JMLO,5h5Rb5$\)rs.4Jn + 4/p3M'\#J#Q>iXn4/'pI3&0]C!m^f-P?>#RgB!an7RR#&@:j\f,sqho>jCQ58*niJbK\Nq6 + T5#)H6QR:?qBK47EKS-2:u55QCTkJ*[:)V;;/no;0],M,(bHHe$aJRfL1l8+ + PtEUX2>XKNW<5OH4bs!Y?RD]F/bon0GhRMRf!IJirY"rZiY>2)rUW'6t4!n7Pq?1e%ArQF[P)+Bo-N8FYeDLOZ/!5CQ]4i"*,Ii/ + \"j(.KiSe=Rerr!\(:RY!a:r,GMU=3dG0^O-<:OICbc')[m]iOe@Ro_df')rg<#tgIL.%e=W>Iqu_G1RY!cdqQp+ + dE^frs^$5uTOGsBmbk3@QHD%#3o_dZ0r'>')rg<"I@WA,_rq-'G(]6R6$N?FScU@5YddT!= + T3ab[Jj2e#_&p#]q3McpU8U;iIeX(rOICbcB)1J3d8%3T + $$BF`,-1H%h]iZ1#3pt[UrNN.HaLQ\%VRN5Ig_';Fg5s<.?h"H#r7?W3Kp!s(/C(?>4Hb0 + S=QZjn(7H0\HRH8R&df:W&m_C29dN%abmp7,c=:+o:&Wu\&f!S-7_4Ri2U$qn1T7=aW_?X:M$VNIFL(cWR30QC-_iHWE;JOg)+PcN6sdgbK!W.V:m=4`f(f6gg + +a!7+L0&PcW@AYI<"BW:.q=Im('CA1Ar*X5+:=q.I,6IJhum$fi7I]7"=&TrZ2<:?MumUES + M7Ui"&^anAdqHr3#lFlHe_]e*mUq>4BR#Ir=,TWMi&?H/\5tfimmc7":(4MA5_2qK=^n6+. + R,YloQ:AK3K<+8CK<'`>3=InjRGJj7<\K0P[[:KVKOr'<4Xr36BS9`N!Ppk.'1r"8ACM9HX + 1iradmRY!c@r<^RPJNq46K0R6OM9Lm25KGa85@XROQ?hgj^.CQ_"b2X1Jj3`C1$b$Ipk)N] + r"87U=eE@E+/H4#O'$nUqW&[r+I*+["T!0pl_M)d^`TALi/^-Q6?>KP&$k!(8pU"3Iup+N5GJ(+GJ_Wb%nW + N5,^okjOP6PHf7N]%:;Vm*=cr1W[soC(2bOV[a+Sek-,R)P2G3A$4s3]C`T%0!cS+'VDkIq + Ao1,_A"<5AqWhS":>13Ph4\A=]AP-EY9g-9aK(cBA.:;/nrY54Ae[8FXYlrQ2%aJNrYEg4M + W@kg,OB.i`rp&$h;TO#?cTleX5g"+O8]r38_@nuD<>&,]9jnAjhlTaGNBi",`_61Dq[r2FV + 6LHk8u*Pii`njfJ(d!lu3JNrE*r`GLO3eIqA^`V)0J#p^5HLo\7f`?T\O(s826%sm4YT!>I?M0 + p$2.s>7nKa/&eQn^5u[V3SgjK?.ma#JMfSdR=5+dV2sK*LY_p5o6r(OdG!I"aj=oRDCCMsL + cp7^4K$-W`(^Q-hDk#E>DM+qoZkj.k^c-J%!N`;N1Lr8I+7GB/GN%`n/1@KO<4KYeUQkBr\ + $l]ZL?il4(cilE:]pNS2M^1%/_HV6O*ASO`#Z9)*/0p%7O + q#c^_UgNmktAM]:Y7ciN:\LO[S52b/>ggpZD(O0/46C"jmgA;]7Yak?LDO[#Xsj!@3NM[kp + )OK]nd>!TX,S,hM90C/8UL$5aIIl'lgpr-@r6BFWZ:/cpO\&,^uC$Mi0DLKF43 + i=Gj;5Odj`qa3@8HkH,UJ)Ck8;8SroQC;,5!e9,=r..()q"(`9gu/eAJNrWo;1EoebT6\u+ + 8>qfPk.D?dr]\T^`W=RJ)JYJpSZV-G(r6N#QDL\-2a`Vmer3;i=Gj;5O_0dIsV+&1]2egn- + Aq@k>.;HafLE9+8>qfi/]Gg<&[mJqeq$Mn-As.+'JLrjU4qfi"*l#An/1.MngG0"+T6iKQZ4Mg9(f'-aCbMGDYm_9h?=&/3)I + rD@ee7Z6R43;+J-b@/cpQ6]U7aO@[Ob\R[#P01.q0-GH7_+Ksk:pkE-`aKnA#BK(qhJJWn< + 7-BiUl0$5@,DCI,i2*o\>egg'_]*,]:/4mm``mN>#S@Y9qTBDU>lW=gdR,^Mg*Jm65l=&S$ + U$6/Opt1/:Q`VMrZVW4XN>8o]a#'=U#?ocHs-iPXRaREZ#-6*H,Dr23*SDm-0N4Nai8IgE;3J%V@uHL'%M->]5,.rZ7A1, + il!1HN=5+g/qiP&j3E_^1O@#,RX3IEK:?2od_@6FZ+8>qfi/^3W5O\pW^`QF+5O\ + pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\p + W^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW + ^`QF+5O\pW^`QF+5O\pW^`QF+5O\pW^`QF[3.LM[nE6;Mr_V&GVSD'd!n/7&!["$eIlo:-+ + !s2Oj3M&75HjL#Q1'cTOu*#]`08.^6bC0Tr&L6r[bIGK:VAEln,$VXCF?[]r1VRIe";cj,N + ZLZQONl'b2^fmcg`dnB9GI^#W#W]nOiHuIlR5=T1;+DM#Kn!lb)-.A8%uWY$kA_;O=OX:G, + 5Q>]Q628nlGNlaqOBI=/6n9$Zm_T6H1edcdN#U6]cp/Gc\K,!R5MIt-bXbhbS_r^S+RrA") + .S3@A\n;EYe2T0Olh!_HDQ@Je[p4_X`#3Q+FbGr^r;g4">hlb]2]CgAPgKO:;H=lf0i3+oL + \7;C0QN,LTG%7k`\_4cU*^B;^P?jGJ04_/aF&-A<3gb*[E;F#-h)`4Kk5NnNX1s\lRa^QnX + -^jZs&7RB(5=L'6s!J1\Thi<;J&QGQ`Rs+hCHRgoU`GQP_-70=hV: + cm#?RL$a_=c1WkY)&bC\(E+,>9gCf0sOdY$64LrF/UYO)OIPA?=s85;]B;8S%($d@g'8#+P + ge(s%P"OXiQG2@X?]*/lHN3o_'+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qf + i/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi + /ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ahQ+8>qfi/ + ahQ+8>qfi/ah9eXq7KpG)UQ\e.@0XGC/u,Y/]#kR%^8(TQ&Y-MV)GZS[.e.PiWl+0*MV3#V + Yio$!F._A3\*be!cK1u_G/jNj:dCHRbCi",`_bt+PRqjksp,32jAHY[C92gR;9+4!o?Xs1> + 52lA!X=a!M_RO4$O/^:C+9a:F;.:&./=-H_8:fLP(aGF4PC0G?joo4q8DT6j0HO&.3\jH-a + +ofLqZe:I-1>G4aIKuF@F9WaAX[0"%f%b&P8,qX<=")Ubngi1TQ#"R2Pr4j>c?673[4Sf1> + 2!/=*Cb@s@"r;WAg-L(m,/tZ.FP!WV3tD;^7ee5cB$bRo*.F*T2O*6_N0_#e]lXgWg]rVN( + o$:"94\-h+(iO6pGoNWuq7j5O\mk2>@9'i"%/Ln-As.+&(2B&,^uCR&IhCp]H"";1h+&#QA + ,*#(PPAr4tc1rkKWNK8CNEJNrW/'/fOeJ)ChaC@DK-^`Q8"i",a:5FACc+8>qf0N!Hen-Ar + #U'?,*&,a73%K=-bpk+DAr..*%#88ui"+T5>->N#TrkKULeDLl8JNoO#_&oNP.BY=Y58a+0 + WRDq0r..'LB(fb\?Dr"@Ird:P__;M:0Wb$I(CafkR/~> +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 new file mode 100644 index 0000000..82c6045 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-dpi_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-dpi_expected.png b/testfiles/cli_tests/testcases/export-dpi_expected.png new file mode 100644 index 0000000..cf1781e Binary files /dev/null and b/testfiles/cli_tests/testcases/export-dpi_expected.png differ 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..a92caa7 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-dpi_expected.ps @@ -0,0 +1,319 @@ +%!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 h +90 45 m 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 h +82.5 45 m f +Q q +81 0 92 90 re W n +q +81 0 92 90 re W n +% Fallback Image: x=81 y=0 w=92 h=90 res=300ppi size=432000 +[ 92.16 0 0 -90 81 90 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 384 + /Height 375 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 384 0 0 -375 0 375 ] +>> +cairo_image + Gb"0WGB=Pn\c6Z%%44*ud^u(.KMYC`,R3VR5&gnFp9BgFm_na4)sko\Vu^)(,`76nLgk[36 + P9Z$5sk2j#t_(uHIo;7Valj8d58Y[Ur..*%#:"!A&,^uC(f:Bbi",b%L`6$jJ)Ci,eA*1$"+N#!#6)C[pk'/9 + n-As.+,m.L5O\pW?pkJ%JNrW/,AQ-Ir..'L;$2=+&,a8")YaDai"&<,^`W=RIk[T$rkKWNK + +U!1#QDL\N2V:ln-Ar#6k0'F5O\n&C>]X#JNjuK"+T5>r5"1-p]H$(%n>'U4DH$&RNFCCUJ + %AZ^8AogM?k[i'UuSi@73U.K$8?#o!iE*$?QHqo!S9>L6B]jb)4m[rHF^qM'-E9hue + JqHlgBaNQmIF;jpcTF$ir5(&.P[(I))PMnUD&CZP%VDpgH?1"I;M.^SQ0ga@]@*DJT+pW + d(H6ur1nmLQrN89Fe,r4i8[:3q#8AWb/"$2S15cn&56Zf["d>o:/7g&-s-KIZ5[8l0N]'#3 + OMl=n],;U-T1?-L#Rj]:QQ)Bu^Y>p9$md*r&FCi6>sTBrTEUs^Mkr7Q;GCl%/d^A%;l4*t# + "?V,ce=rF_gH/ruIA9RHYB!d@t'XihNK$X\e0!01jFEb@V`lU*Soh='WVE_1s[$otmQ9VM; + +8B?("+T5>r..),#6)C[p]H"6%K(cAn-ArK)YaDai",_t2=LkM^`W=rC>]X#JNrWoeA*1$" + +T6iW.@2&#QDL\;$2=+&,^uCU'CV4+8>qf6k0'F5O\pWL`6$jJ)Ck8&N0%_rkKWN,AQ-Ir. + .*%8(>r"1flpd> + )Ic%%Vf3LTX!WA8891c*#qB*OhhfX8cI:pDpYVr!QCbh#e54l!#M5S[q")B4l-](# + Kc(o,Y-G.@[TZn5j]#`i8M*TK;/kPrd4JCQ[g4(j)h%gs!i1#r^ur9>/R:Q$pmfg=aCS#i0 + )>:d`ugr9Flq^[Jj,SA4EkZKX4]eF=%'1CFEs'kS22P5=N;Z.7j9`6__]/tAQ38TW\q?;\X + Wp[;klp=bq#8%6sl1e1%MDMRN&X,>$Zc@PG-BC^[utWH<4*S=O*;/(4$2H*d_65K>4%5?:qb + +n2PuX,.roqF:G>P.SPE_*ej4aGe1Tk?%TGpn.P/l>P*4Bl:$@fO8+(L3jGtT%@pBK)(!uo + jQEUe[t^EmehC@p?:bpPFJRbJ+rpqGePla@kafH*ePg7:7/J:g=4qW3PE#ieb,9[X5[,`/o + Qm-k0'5W'0T:;;[F"1F9Gc>_4UF[>jJ"sP77HG/%la^(39--=\e-8c`K=Eo$8]_9M6L?j*\ + n0+X=WiE2"TL;tlJea[(%<,r..),#6)C[p]H"6%K(cA + n-ArK)YaDai",_t2=LkM^`W=rC>]X#JNrWoeA*1$"+T6iW.@2&#QDL\;$2=+&,^uCU'CV4+ + 8>qf6k0'F5O\pWL`6$jJ)Ck8&N0%_rkKWN,AQ-Ir..*%8(>>=%07fbK7Nsj7GR3GKS]c^[]4T=T4973Kf + Dq4Fa:1mK7"iB9N:jf)fe10)h(<159 + sO^L,+DOsBZE@1>e-X&efO'M[>@t1-t&@4)T@tsCg3m;@V-TZj)"!'=YBKl%dk:fP\ba0XQT,eZ==;3N`]B8LF;$M"^0N)!q^(tm.l0a-r + ]Z';]8s;'dE"OCbG1BW``d!H.VWuCHKr&&I=Y=e-B?B&h];XN#=gu9o\n1.l)LX#FC0/tAm + Lt>53qk-Z]BPAjIU-C7gNaZ7@#qVU + oue/.8tjDi>mk#U&6df!I;709*>mn^4&\?VlmGn>9!Bs+?M.O$\.I+ER@5/X[rnMi",a:5=5;4cmKIb&,^uCn4-f7b)Bm7 + $iGQ?n-AsjnGZ6Aoel4DrkKWN,K(\(4Wao\5O\pW^`Q5Ee"/4(^`W=RJ)HA6r1QXcp]H$(& + ,[%!:RRoXm=-eeJNrW/r`I76Vg^96rkKWN"+Mlb:Plf]NVDGk&,^uCnAfSK'Y!m">2^"iJN + rYEUAhOi?G)6ommLbW7V,)0MUfX+`&PDXi9cqfB6&=unG>Rs%#$q>k0G](r*kmLf:N@u'Bg + ]`NcjLN,IZRZ#2^B6o'F+iBE"_C[dHq6?1jEZ0f0`+NCH[?-:2FS`tNo]U\6(Q3m+;bO#R%4Q%2r5"AG5h96q9M-[p=46b4M7:-HkdGf + oPl"kVr^2:NS42)]OM$=s!3Brq6IrmWgTOg.:cVgMd!E*Db4TNUkRk&X^HG0.,,Bg&osi,= + lUkL)/H1>JOV?W3p%d5m-jiq/c4F*-T>8$GSaP:$-#PT29LhE1YlRFF#?+.VD62#6@cJua! + U1@`b]oYUP]07fSW+6-.n%/ph2jNiG)"e8cpTr/qY55j"0Sp,JZ)*&`LKO7ZVrQ3uYdrRb- + oHRPQO?]8Tq2Th%aSS8;61F(7<>[7E&,]:>nAi]MU$,VlrkKUE#(N`3TC4Fai",`_;Xha'r + V?F*#l_U],mAd7_Op;R#_PA27nLN=S+)2JBPN&^n4-p'+'\95]!`OV^`S76Ir*)rU7.gRjs + Kj*J!:ZFYn_be)H.+CJNla6rn*;s`APX,#R5e:O(*]*2WPB[CbW^JpnO57O)=\kAgi9rn4, + 4L+5?@aW2<*eVh75'7iB,bS+EOG?NP`8O"u;O2WmkRFmd/)L[YQJ-m8:pF8k6"jWp*:_&rH + IJDcJ?qK'@.3rFOn$4-X`U-FK[M7^_cW'=ATY&\t!4o@Us + &H&e1J#JU;'UCst+gZf50+;(+Bkd@jl$K;Ni/\iTZ,^DHa)BtuJB;&G%\*DWQ$S>:Z/fDPf + mi2Tr`&&+BG.K/?+F*[1SZ]m=rOMt?L!$3ro`(p\XXFi/t[>/OY5,pf:qR5h,"+TYg=o + @OHdVZYcGZk/Cn=(Q20g9)Z*hGq2Qt%Sc3$#S[kXti>]#Hd7^i6;.eMK*?aQnmVVod?KE2" + R&QR*_F3c[(A.!706h"f1c&rOqnb9ZA/6=Qg[^JBbD:V"Ap?, + +[hEFU3!%fa))m^20,553)2lg5kfhO!mke?)>leKU=6Xt)fB%(J-PT_c=h-aE;bfsV-RLcabN1=N]LUAdPnX']_P>S@M%A-8eW]p)"jCW&&r'>KCr36HU3qP$er'?2Hr`Fe;a-)M"+(U/C + +)CA$MTCU(5KM]55OJ(j[63!6rj;\q5k#"--MZ%bJ+haTCJfRV5<'+%OM(gIg?HquK)T=YI + uYluLHil:Jj8Ypk9jJ`@SqX/s!])cK+o!sBr=2A3'J"H)f8H%_U??[&$i7o:](*1N-/\-P? + aE$39fprr+Y=1_.%HC%oPr=q@g^nqelESqGVDt>^HnR)ZG$#k=a,RjYT24I_a3Y&q*?C2NO%Jp>;R + qWh6k0C3ci?d`^)Qo+O('D-"WV*h-AcS)6rTV\XM=E,!8=6(W^`lkmV(V&_5^;"Yr4Z#;'( + 'qIJ54$VWIV&QiGMDS)-'rb2UF2"p + 4nqdo^qdO]WZ\Zh!f$i?+4u/5.c'4kJ3^-s!aihgP9lpm1+W-^fp\F7fN%$lhA\UGMYOQ2Q + ,1$^:kb:"$NYQg5CYcf2iIO=p$,TQKBsu\dij31G`T)-59>Y&n-@WBn>AYQFEZqs^$rVpr,GAKK0RG + +Jj1:HLY?rrTB6!EG$a&4Iup3(Ilcl@g.Q35lAsOS0DL1d,l#hcJ,X]jNu%D$qpk*'#MD]< + Vka6Mo,hUBIlnB-i=E5Xi(llAl/pDGV(BT+r]Kj*0_g87'E%*n5?)0*UuhMO-`Gu7ZBO4-" + Fmjeh/56&<:MI5KBslY,Jg"KiCbcccVr_QLHe5>B8>9rj;V9+S^R''E"!N%i(ZJDE3 + 4#rWj)56&H!J8FpKGm9Q%LVsTNF_&oJ?i/]^E2F_VlS3Llj((U+l'GLD,k0MhE\X)ibm>iC + ,+/G:^O#2@cE;U64o>``F(&f>&#l[BdkKWsD>0`bK56=RY/.#YbIuj_`5LTIln.EV-p>=OC + \,!"K?1T7l*h.HTST&lJhgn!_CbkkYc@L2rqYDd=ea=R+=P`]5M9\h + l)e_RELRc$-@:R+GD*$qT"'_Tb?o//Efklr'>Kfsu$iEa<#ptdejE]'``aA%q5`mV"q@g`_O_QitUYZIulerJ#)m-%_s1]K:'IsC&Y%EeaNhC+ + D1+5RQmC#T(!!a+D1+5RQpTC&,\`ki/]^Er,;C8d%=G8KBsfW,L)joGPC+qGPHfX_&mCj*5 + $dJErP"gccAk55LTHirnod6JNnr.r/p+P^Ae[m&3oq7c(FLLE6J'0huA>q,krV/TD6'Dp]H + !W1\`32T?b`Qn!2b9TKi5MccA;%58*nYWTr.[HogO'p:ik9P$J"=ec$@P[L\MY&,-#ikWb5 + MrM/HP^]*s\L'Yl?f_6-Nm3a0,,cs6/**QLi-ShXsJ8[/.-( + X:4D:pk+5)J#)lr-Y/8!r)(G6i"*,Ki/]^EejlpQS3LltDX[na6h!U75CPQi/E`'T5n/=*4 + Tp81q%K2$3#T@%'uHgDXhRlp^mEI,mAcZl;(LEY">H]QLi-Ad0'@j3skn.e=Y, + PUF"jIIXg)Nn.5F_8dbQ>e=Ve^GPIZr*V-,q&-'EeUnlpE8,ZR*[E>6CG[9om5KHTO599DE + n4oWFrFt:NO22p6Yi&<4r1TH-YoqG7rj;Wn2rG3E=R`4UrX@U;<#RsfoV_(p^;D%gYi&<4r + ;"fu5?ZL.X]N!K+(RUPT+:\'-%:b@rRlXB48_D<'E%*V5NafJ1&]c>[n6-L:KoXD^E\Lu6a + dNimb/]\+G%YucT;Bg@JXKaqsQL8r3\chj%oK[l^t]3Wd*'(F%^KD]BT(>!cJ;rNEA6_EtA + Ah$0rZY]N0Nn\THk"rq':dT5eNK/V,mpZ2Y8g(l)@5DL,kTVppT'9<3TUgjuS&Pqdlc6YenPkV-H^>h4JoURtgI:-^.cMS,"4#qg6,UGMMHE2AdEU,uA + 9!3qbNtL4nQChC\=i=sC(5=ErI=$1;Tep,CcRDYVVm"^qma"t^?SVLN/k\BuFSJDTOiJ6%) + FVnq:G!nP`q?Y'B^a=^Hm`m%j>Ue7q]PZd"@f:2iPVapWoqHo,JQA8jg)s=Sm5`3l-E^4rmdbB*)AcT*dllV;H!"^Sc8EAoXCb`V]VF`5KM]55OJ(jW?fT[re.)&^`R* + *_4PoIPH2s9W'B5O_r2-3\)<<)piA:VBKPa85=eA^+)CB/e:U]h#MEPT`u=kirssV;%oQ

@2a:;W.re.,'_&m3[_&or]*)/I4RF/1@I + DI#$]\niQIld5I48_AO$iYtTVaKpc_]P\Yi/^ui3qU]Zr':YtrWr/Z7.Q1piWF[lP(Gn"r< + Z4,L-NbNK0KG9OmqiDIuohF5GJ(mD$Qiq-s'VgIn#-%?9pKq.^VnumNM + FbS%sC5R&3EtU;9=7WNL.(k[>R3=/A`(&GP"c*iC#%Y=6Ha43 + +*h.qhitVjRK,t-S[9:8hNi`WlgJ?ko-!33[]0tU9fb;OnR8u9^h6"PBloekLT*IQfjul5B`>Drqp + HYO!a]tS/a5.P5cfLNUn1b_3#6pdR2+_jAO+NuJ#MA$Ypj5EURoX$?%pI\/5"=or\)SoXa4_6pk/3[R%t"L;WhmM+Q@ + N">hP8;1I"DdbkZ6Z1[%9/c'N?ru)+apk,Xnpg]6]gb62KJ)H@hJj6^-:O7:Ir..'># + l`JH5K,M!R?a30#Q?+opg\CEBPY$F#Q?+rpg[P-PT!0YY6KL7O"u;O[cJ%uLVY)-UR9u#%J + `qu.r'@Z!e9-h@Y-g&jH$H=pZU!Lp]H!['E#*YIi=dpi=Gi`;Xh_-r2H]uC2%C55O_07_&l + nOVnTDWrkKV0"b1@*T*f'sbI7S'i/a%Q5;qI2rH7$/r)$eia85``1R,ip_=XXDli&u+nAi8+_&m=]r]:ek-BKAar?b-SXRFg9O1ZR)((>\a[.nA.L]/FtP$OX'W + M$+2ls\QEd.p>[0&a/gEnTc*?LP#]h-]!1dfB+CF;Bu[SXhet'7NZLp=Iik/)>DO\TIf?VB + 26T,Z?;>VQVsLGMEaq,3':RVG + rN/_BG^l<\+8Jji=Nde[WEu@MSBF$=+o;>=3),o1[):W'hO]";-7=-3*kGip&(_l9<5"[8T + -(ijHLTnj6iCK701L5J)X0C_El8bWHo]2-]#;-=a#Qe1A+W7*Rsmd`7JXNB:7>olV6Q3IBO + QreJ$^QiP7Adt5L&l3g>'c.aJc0g:9h@7oKVcGYM]3TU#0p;n*k[G.tg.\k0MEA6V$NSq*R + dto#DonJIHOUFctP"R#Sg=Hja]sBaM_7DX3Rq[d?kITqo5q)?.Dnp]H"pG^oAYqDJfbJ)Ck + 8JNjq@Vp&9:kaT$[^$l:+^`W>]+b/bqle4N.r..*%#Q@iB+8RX?l9X>=r..*%`tJA.[QOL% + 8+6c_^`W=r]0G#\-beaRJ)Ck8JNoIlVpnO8YeV@U"+T7T&+@hCJ*[Sni",a:5F1f:4[4+E5 + O\pW^`V8.0n7pQd1\b3%"I1Gr..(uo>fKkm*J&V&,^uCn4+7D.V^IpH4]iRJ)Ck8Oi8CK^L + @KJ^`W=RJ,'#MrB4*S"+T5>r3;>J&tZbo&,^uCn;$I.M8#dbV$[.:+8>qfIX$?5!6GIs5O\ + pW^`Nm3MGJA#2uVh>!!!*\l5ilkl?LOrM)UoOS!DF:rK*]QmH2-HQj,!Oi.*qs + P(^U.F!c.$:(W3*#"X5p'6Bl=dD4IL4F-oHfZBNjU9O^J%VfH:-6i\/O>S>j()gWgb62[ + Q6$h30S35&B%6+EeUKaXf8i^W/A5!EkgH+]3Sdd`2fe*&iSMKLHh?dihN&Nd6ruOdSuSC[T + 8ZVLg^!aflVCjZI$)kc*\U1sR/Hg;f3d;0RcL@7R8,c\3k/O:-U8rT8l0B>[QV;J4gQUoUG + >2W%kAaal11:3Rtr2!D/>f?N02;UlFL^SLm,P=J$7oSX^7Cl37F)LWq39)p%"/Bs569PRJl + Yfq.&7n=Gd%(&kF'n4C=K:5O#R=s3D6O)ko9iYGfPSagib.DS*>/XWf?lb%umpdOWd(=q1C + DcbLXt"+T6iW.@2&#QDL\;$2=+&,^uCU'CV4+8>qf6k0'F5O\pWL`6$jJ)Ck8&N0%_rkKWN + ,AQ-Ir..*%8(>r + "1gU#QDL\p`jP3&,^uCn42!D+8>qfi/agf5O\pW^`QDUJ)Ck8JNok5rkKWN"+N^u/H4-Xe] + [&M86X*foWt(5AXltMIc[2_s7u+2s3?H,)Ws%sR+F"n7!`1Wkm4D;0XIeXG6kJQlM`Gc]7C + -`_&e4VqG/A"VX9ekBklSU%5AgW'&6aP>pZs+I`pKIrs54GI;,M2c^bMI_=?a!6T9d2h + H1EnhbaL\VDi]>NJP;AhMRM@YpEkpb`5,2KYH!,/tI)jSG#'g[skV8/4*FXK=JDP1Wq=San + e(:]T1HGfhn^=k4Qjq_,jHmK-q<%Z8hq7s`jF4H(2j@7BP@pVfq\==sdIPEF\ek(tZ+2$3> + 1f<$dR!.:la1ent + k;b)ZdO4g&]3OHl_*4OTIeqK;dN7628UQLt,i>LUuke_8o1S%IY/tWpNF?a + >+FGRXZm;(cc7l<.@l4(`;,H'7Mg0AK48m+c$Gq--6.49qEKD,jrg372eRYtr^?!+Ka8p[N + kXT%eGQZGOVc4/nN13Z%JJgFhuQn8YN[/SL"cRYUT$1=>=in]48K&\\-0tB$/U3!&cN`&5Y + M7uB(L6=<%=]7slo:opoP7uM!5OcbR&)DR(-9VsZa]NK*Y0'Kl9/c75bNi9YZ2Jn@'1%dCE + ::U!4*q9qPu0%l&RVo$RN45S(*:]^LWj*F[[>abd"Ph4r6"&WLH7`G8JSEiPBqr`\Wh/l)6 + I5dOCEVm-PDB(/kgXr"VZ;Qg=O+^p]H$(O/RUon-As.+&N,ii",a:5GAA]^`W=RImabDJNr + W/reMKf"+T5>r"1gU#QDL\p`jP3&,^uCn42!D+8>qfi/agf5O\pW^`QDUJ)Ck8JNok5rkKW + N"+N]Jr..*%#QBMtp]H$(&,["sn-As.+8@'qi",a:5O_1m^`W=RJ)HBdJNrW/rkKUQ"+T5> + r..),#6)C[p]H"6NOASG<15(b5KUt>h:]:;c@3kI6$mM<+[&joX]TRLH:6-NaQ9a[Ae@>1J + nNC;RC=Sd&[MWa$eATgkC1C_JH[FQbH>L+\GfaW^.=[j0sLR)W[WNa2EGmS_o.>1D5b^Yc6 + 5=lPWdrh>+U$qjlD!)#<84A*4g?M'O#]ph3n^e33Bm(Q3a4]bC\(EbSHgVr)rf-ba+i+\hS + Nk[]A.FYBY).:N2Y3ruERbRqLT-a&!tjf(BOq+8B?X_fq&oDIKj;,$.cG?LF.sn8^&fuH + 5BI[KhLh3C=^=s5;e':51[0c+`C9VI:3;.UI3Ca_jQZ6FC%LPgB9oaG0@?+celFPG-Jj^k7 + _2aP2ficj6C0p2:L9")&)G<;=[hZBoqVgK]"\n!r!I0GEj`IUb_U!)psIOt/a\pj)9N51d_ + jRF@R`9spk,i+JNrW/ra8,'r..*%#:"!A&,^uC(f:Bbi",b%L`6$jJ)Ci,eA*1$"+N#!#6) + C[pk'/9n-As.+,m.L5O\pW?pkJ%JNrW/,AQ-Ir..'L;$2=+&,a8")YaDai"&<,^`W=RIk[T + $rkKWNK+U!1#QDL\N2V:ln-Ar#6k0'F5O\n&C>]X#JNjuK"+T5>r5"1-Abr12,(DH")B&M4 + iracbehbn;:JJNJruL\P3X0IiO@H/,Q`&$MfB"e5JkGY]k0;:u&OFE+,M#(;2ua=Q<)sJ~> +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 new file mode 100644 index 0000000..e6ab7ed Binary files /dev/null and b/testfiles/cli_tests/testcases/export-height_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-id_expected.emf b/testfiles/cli_tests/testcases/export-id_expected.emf new file mode 100644 index 0000000..3c8ff73 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_expected.emf differ diff --git a/testfiles/cli_tests/testcases/export-id_expected.eps b/testfiles/cli_tests/testcases/export-id_expected.eps new file mode 100644 index 0000000..0dd5840 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Tue Mar 31 01:06:36 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 75 75 +%%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 75 75 +%%EndPageSetup +q 0 0 75 75 rectclip +1 0 0 -1 0 75 cm q +1 0 0 rg +0 0 75 75 rectfill +1 g +18.75 18.75 37.5 37.5 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-id_expected.pdf b/testfiles/cli_tests/testcases/export-id_expected.pdf new file mode 100644 index 0000000..ba9a322 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-id_expected.png b/testfiles/cli_tests/testcases/export-id_expected.png new file mode 100644 index 0000000..5ebc531 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-id_expected.ps b/testfiles/cli_tests/testcases/export-id_expected.ps new file mode 100644 index 0000000..c7cb7a2 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Tue Mar 31 01:07:13 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 26x26mm 75 75 0 () () +%%BoundingBox: 0 0 75 75 +%%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: 26x26mm +%%PageBoundingBox: 0 0 75 75 +75 75 cairo_set_page_size +%%EndPageSetup +q 0 0 75 75 rectclip +1 0 0 -1 0 75 cm q +1 0 0 rg +0 0 75 75 rectfill +1 g +18.75 18.75 37.5 37.5 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-id_expected.svg b/testfiles/cli_tests/testcases/export-id_expected.svg new file mode 100644 index 0000000..6dfe9e7 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_expected.svg @@ -0,0 +1,110 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-id_expected.wmf b/testfiles/cli_tests/testcases/export-id_expected.wmf new file mode 100644 index 0000000..fba7d63 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_expected.emf b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.emf new file mode 100644 index 0000000..d34b0d4 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.emf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_expected.eps b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.eps new file mode 100644 index 0000000..1f84f07 --- /dev/null +++ b/testfiles/cli_tests/testcases/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: Wed Apr 1 00:39:29 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 75 75 +%%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 75 75 +%%EndPageSetup +q 0 0 75 75 rectclip +1 0 0 -1 0 75 cm q +0 0 1 rg +0 0 75 75 rectfill +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_expected.pdf b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.pdf new file mode 100644 index 0000000..2febd2a Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_expected.png b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.png new file mode 100644 index 0000000..3e0ef96 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_expected.ps b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.ps new file mode 100644 index 0000000..0947232 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.ps @@ -0,0 +1,117 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Wed Apr 1 00:39:28 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 26x26mm 75 75 0 () () +%%BoundingBox: 0 0 75 75 +%%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: 26x26mm +%%PageBoundingBox: 0 0 75 75 +75 75 cairo_set_page_size +%%EndPageSetup +q 0 0 75 75 rectclip +1 0 0 -1 0 75 cm q +0 0 1 rg +0 0 75 75 rectfill +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_expected.svg b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.svg new file mode 100644 index 0000000..138e29c --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.svg @@ -0,0 +1,47 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_expected.wmf b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.wmf new file mode 100644 index 0000000..25ff1b5 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.emf b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.emf new file mode 100644 index 0000000..e571242 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.emf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.eps b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.eps new file mode 100644 index 0000000..ba306eb --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.eps @@ -0,0 +1,80 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Apr 4 19:16:30 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 0 0 75 75 rectclip +1 0 0 -1 0 225 cm q +1 1 0 rg +0 150 75 75 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.pdf b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.pdf new file mode 100644 index 0000000..36dd312 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.png b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.png new file mode 100644 index 0000000..d27c855 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.ps b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.ps new file mode 100644 index 0000000..fc92a46 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.ps @@ -0,0 +1,117 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat Apr 4 19:16:22 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 79x79mm 225 225 0 () () +%%BoundingBox: 0 0 75 75 +%%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: 0 0 75 75 +225 225 cairo_set_page_size +%%EndPageSetup +q 0 0 75 75 rectclip +1 0 0 -1 0 225 cm q +1 1 0 rg +0 150 75 75 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.svg b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.svg new file mode 100644 index 0000000..d0cd190 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.svg @@ -0,0 +1,47 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.wmf b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.wmf new file mode 100644 index 0000000..9d55069 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-drawing_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.emf b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.emf new file mode 100644 index 0000000..c27c0c6 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.emf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.eps b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.eps new file mode 100644 index 0000000..8a8bf40 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.eps @@ -0,0 +1,80 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Sat Apr 4 18:19:47 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 300 300 +%%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 300 300 +%%EndPageSetup +q 37 37 76 76 rectclip +1 0 0 -1 0 300 cm q +1 1 0 rg +37.5 187.5 75 75 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.pdf b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.pdf new file mode 100644 index 0000000..b3220d8 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.png b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.png new file mode 100644 index 0000000..906dc81 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.ps b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.ps new file mode 100644 index 0000000..b2ab92e --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.ps @@ -0,0 +1,117 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Sat Apr 4 18:19:46 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 106x106mm 300 300 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: 106x106mm +%%PageBoundingBox: 37 37 113 113 +300 300 cairo_set_page_size +%%EndPageSetup +q 37 37 76 76 rectclip +1 0 0 -1 0 300 cm q +1 1 0 rg +37.5 187.5 75 75 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.svg b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.svg new file mode 100644 index 0000000..ed5eb1c --- /dev/null +++ b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.svg @@ -0,0 +1,47 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.wmf b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.wmf new file mode 100644 index 0000000..7b55707 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-id_export-id-only_export-area-page_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-ignore-filters_expected.emf b/testfiles/cli_tests/testcases/export-ignore-filters_expected.emf new file mode 100644 index 0000000..44df006 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-ignore-filters_expected.emf differ diff --git a/testfiles/cli_tests/testcases/export-ignore-filters_expected.eps b/testfiles/cli_tests/testcases/export-ignore-filters_expected.eps new file mode 100644 index 0000000..c73abd7 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-ignore-filters_expected.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Apr 10 23:27:45 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 0 150 75 +%%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 75 +%%EndPageSetup +q 0 0 75 75 rectclip +1 0 0 -1 0 75 cm q +1 0 0 rg +0 0 75 75 re f +0 0 1 rg +0 0 75 75 re f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-ignore-filters_expected.pdf b/testfiles/cli_tests/testcases/export-ignore-filters_expected.pdf new file mode 100644 index 0000000..5638e26 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-ignore-filters_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-ignore-filters_expected.png b/testfiles/cli_tests/testcases/export-ignore-filters_expected.png new file mode 100644 index 0000000..944611f Binary files /dev/null and b/testfiles/cli_tests/testcases/export-ignore-filters_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-ignore-filters_expected.ps b/testfiles/cli_tests/testcases/export-ignore-filters_expected.ps new file mode 100644 index 0000000..22eb9dc --- /dev/null +++ b/testfiles/cli_tests/testcases/export-ignore-filters_expected.ps @@ -0,0 +1,119 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Apr 10 23:27:45 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%DocumentMedia: 53x26mm 150 75 0 () () +%%BoundingBox: 0 0 75 75 +%%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: 53x26mm +%%PageBoundingBox: 0 0 75 75 +150 75 cairo_set_page_size +%%EndPageSetup +q 0 0 75 75 rectclip +1 0 0 -1 0 75 cm q +1 0 0 rg +0 0 75 75 re f +0 0 1 rg +0 0 75 75 re f +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-ignore-filters_expected.svg b/testfiles/cli_tests/testcases/export-ignore-filters_expected.svg new file mode 100644 index 0000000..a409973 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-ignore-filters_expected.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-ignore-filters_expected.wmf b/testfiles/cli_tests/testcases/export-ignore-filters_expected.wmf new file mode 100644 index 0000000..3d64bdf Binary files /dev/null and b/testfiles/cli_tests/testcases/export-ignore-filters_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.emf b/testfiles/cli_tests/testcases/export-margin_drawing_expected.emf new file mode 100644 index 0000000..9e23657 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_drawing_expected.emf differ 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 new file mode 100644 index 0000000..0535214 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_drawing_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.png b/testfiles/cli_tests/testcases/export-margin_drawing_expected.png new file mode 100644 index 0000000..de4aeba Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_drawing_expected.png differ 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 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-margin_drawing_expected.wmf b/testfiles/cli_tests/testcases/export-margin_drawing_expected.wmf new file mode 100644 index 0000000..d37195f Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_drawing_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-margin_export-area_expected.png b/testfiles/cli_tests/testcases/export-margin_export-area_expected.png new file mode 100644 index 0000000..2e53613 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-area_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.emf b/testfiles/cli_tests/testcases/export-margin_export-id_expected.emf new file mode 100644 index 0000000..3802d6d Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-id_expected.emf differ 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 new file mode 100644 index 0000000..3f2adf7 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-id_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.png b/testfiles/cli_tests/testcases/export-margin_export-id_expected.png new file mode 100644 index 0000000..d044884 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-id_expected.png differ 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 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-margin_export-id_expected.wmf b/testfiles/cli_tests/testcases/export-margin_export-id_expected.wmf new file mode 100644 index 0000000..407efb7 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-id_expected.wmf differ 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 new file mode 100644 index 0000000..5dbda47 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.emf differ 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 new file mode 100644 index 0000000..736e623 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.pdf differ 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 new file mode 100644 index 0000000..a63f9c4 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.png differ 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 @@ + + + + + + image/svg+xml + + + + + + + + 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 new file mode 100644 index 0000000..169b86d Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_export-id_export-id-only_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.emf b/testfiles/cli_tests/testcases/export-margin_mm_expected.emf new file mode 100644 index 0000000..78c3182 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_expected.emf differ 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 new file mode 100644 index 0000000..f4c472c Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.png b/testfiles/cli_tests/testcases/export-margin_mm_expected.png new file mode 100644 index 0000000..9c22341 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_expected.png differ 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 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-margin_mm_expected.wmf b/testfiles/cli_tests/testcases/export-margin_mm_expected.wmf new file mode 100644 index 0000000..0131399 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_expected.wmf differ 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 new file mode 100644 index 0000000..e0130bf Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.emf differ 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 new file mode 100644 index 0000000..a463c55 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.pdf differ 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 new file mode 100644 index 0000000..84fd7bc Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.png differ 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 @@ + + + + + + image/svg+xml + + + + + + + + + + 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 new file mode 100644 index 0000000..f8c842d Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_drawing_expected.wmf differ 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 new file mode 100644 index 0000000..6315da5 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.emf differ 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 new file mode 100644 index 0000000..f9914b4 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.pdf differ 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 new file mode 100644 index 0000000..51a98e1 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.png differ 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..6e39aa8 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.svg @@ -0,0 +1,50 @@ + + + + + + + + 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 new file mode 100644 index 0000000..18179f4 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_id_expected.wmf differ 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 new file mode 100644 index 0000000..78c3182 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.emf differ 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 new file mode 100644 index 0000000..f4c472c Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.pdf differ 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 new file mode 100644 index 0000000..9c22341 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.png differ 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 @@ + + + + + + image/svg+xml + + + + + + + + + + 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 new file mode 100644 index 0000000..0131399 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_mm_viewbox_page_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.emf b/testfiles/cli_tests/testcases/export-margin_px_expected.emf new file mode 100644 index 0000000..0d52e4d Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_px_expected.emf differ 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 new file mode 100644 index 0000000..a467503 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_px_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.png b/testfiles/cli_tests/testcases/export-margin_px_expected.png new file mode 100644 index 0000000..a9ce6f9 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_px_expected.png differ 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 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-margin_px_expected.wmf b/testfiles/cli_tests/testcases/export-margin_px_expected.wmf new file mode 100644 index 0000000..57bd577 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-margin_px_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/export-png-color-mode-gray-8_expected.png b/testfiles/cli_tests/testcases/export-png-color-mode-gray-8_expected.png new file mode 100644 index 0000000..3ee1468 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-png-color-mode-gray-8_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-png-color-mode-rgb-8_expected.png b/testfiles/cli_tests/testcases/export-png-color-mode-rgb-8_expected.png new file mode 100644 index 0000000..0677fba Binary files /dev/null and b/testfiles/cli_tests/testcases/export-png-color-mode-rgb-8_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-png-color-mode-rgba-8_expected.png b/testfiles/cli_tests/testcases/export-png-color-mode-rgba-8_expected.png new file mode 100644 index 0000000..4798382 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-png-color-mode-rgba-8_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-ps-level-2_expected.ps b/testfiles/cli_tests/testcases/export-ps-level-2_expected.ps new file mode 100644 index 0000000..2d73ecc --- /dev/null +++ b/testfiles/cli_tests/testcases/export-ps-level-2_expected.ps @@ -0,0 +1,2366 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Tue Apr 7 23:58:52 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 +Q q +37 37 76 76 re W n +q +37 37 76 76 re W n +% Fallback Image: x=37 y=37 w=76 h=76 res=300ppi size=301467 +[ 76.08 0 0 -76.08 37 113.08 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 1 + /Width 317 + /Height 317 + /Interpolate false + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /LZWDecode filter + /ImageMatrix [ 317 0 0 -317 0 317 ] +>> +cairo_image + J3Vsg3$]7K#D>EP:q1$o*=mro@So+\<\5,H7Uo<*jE<[.O@Wn[3@'nb-^757;Rp>H>q_R=A + lC^cenm@9:1mM9jRso`J%pXIp[&Fc7\i9+F>q_Zo0[n)-uXDNg4o:$d,(%f)pX3/TtG&W$Q + T]66[)]^DV?&8gI$,1h,H=-%FK?m\aM@62%@_rEaU;53ZEs2iM!b934Jd6L>JW5BPkta%C\ + ]A:tn"3j8H5MCXCeb2Qi3te=j85D(T$&UTU;t-uA`!3eko6d+OXA?LiinTsAo"2FS(96Xrs + F]W)naRmUW2fMja>;MMu\YNTce)Y^l$J$189\f0nX6X8!i'K*Q5D=70`f!I<2%;/%2IOJtM + )T%51^Zl\B!@VMoL/o^6>)$$CC)KpCPn8P%;lF7a.\W*,)+^HcC)KGN-tNfRTp,m%58,GUn + qKoD-tI(I7S7D5(F + pnE;MITiCd)Spth^(ar&j+NKjR"25k"_L,@EF(su>3@lf?#-t=` + ]10/-,`hA>k_M0brC)Fa[Ms;.lTo5of\RR$sh3+Ii8f4mI-t:&J/#Zp_L+9-2V6b$2igPTN + -t81QTo'0oStV"`(n5YRL\R71M/!llTnt_&L*S0V3eekdGNo)NW+$s*+fJi_L*5F>(kA<8p + gSt"@Hn\UTneLBG+j[`(itZb@E(@%L?]UmOXOYCD)>jI_Rc4(F++"4%I;=V`\9r + (I^=05+g>VA#*h)'NXr^fE\9R=pL:DHnLN`Qt*P14_XrViIeZKoT7_!PULH`4hCPOPfXrNn + ha0$CciPVf<*9ObLl\>,CDX3&?9E#CMS[-\8#f6T6%.R>2c6Z)B.S, + iG40k\7Y&]B"2FA+L*!j5CPEA;Xr&)9J$'UAiHt65L$#mNl + \3p">jI*al`M$"iGG_5]&@?&Rc(MfK#t/'(:Yn<4'WNfE*"p5>1Wpf>SV3LXpV&9.U(c/CP + &,e[D>Pg"Y3glNGqb&_*n[!i1XqSF5Y:,TjGf*'Q-'/8[R$&5r9g>J94JlX + &&_'mn-XpEUg,9ja)&T)JU28KpW"@QX5JfV!"B"0!fi.Plt%Q1Z + 1"P3ba>S%?`5K?7'+.D,9COu#Y#I_,`U\e:,/Tj*QS!/0[D9H,! + pa)!NGpJn7^s5&i)siH@BKcZRb%VI>RITP.Q,#=f)h2hCOnpW"U;IMg>G_r/T<&E^mN^T>? + hJ5WNHAi\.T_<7r*YnXoqnmf)d1%#]4N(28Fi/Rc$GHJGlVQk-tq*i&m\bE#l@%FOpQ:>R( + s7XoijW%@Z34COjg8"$/Kp!L$am/T;Oa^gB[%i%Aeq[B9SN\-hJI>Qmi@'Xb_Qf)[s<"Ou\ + =!`lf;)W2iUJ;U&.^d?WR"'brqE"=hA4&_U+*,C(AXoYE0#&:bT!tB2W[D4?F!39?+Q&2XE + 2RimYi"9aT6FF5:*nLC5>QLsG"uX14?(0[YCOd_6!/@ualhaoec#<`l^^/Nl*JeK]$*F7Gl + 4I4A6#2,GY;RShf\7ohD.EOP&,+^AgN`a9,Q506p?QF^]6S=3r-u37rnpO!!iE$+7KPc^d7u$L\qFr0Id8lkTL*7r"C1A=F\/R"*,,ru-[jCsFcH3(GC`5NA^BNs#AE&,>oaj7*)1)@Ac$8I + Zl.9T,%=5"Ndms!7pJQW$ds:Cm7^5NMnFPXGFJ&,AqtV*q>KP.Fd,q-lSMT`:=qr`g!0FfV + A"^6fQ@@h8Bm5NY62R7$sc&,Dd"VM*BdP?Mf6q6E6Ii;]:arbrDD`NuHfk+*0iJ'P>!4,%3P4)J'el.7/+A0U@`&WdII6,L]&A< + oSo6dJcA<^r@/o]Y^b*[s%GD#18^;iS5[9(:<3;s+8#V`e0_(j8,Yq"od#%:Z2[`mrD2N47 + ]FpAZ9RWis/TZ/Y)iFn5O/UTXF0<=ep>eL8,[6Got5e+&cZ+VrH04ThkeqnpKq_Bs0)V)_2 + nI#5O:B0Yruj@f\7KY>2*=)m=*7P>AJ + 4r*+8ed_u7Y\l[*Sg*Q>P_-KM`=rof.7Uq-4\l!6r`lgE$M]9dj5?7Wt_8,L%CmfrDjHe3U + _IIY$qc015_VE`q>q7da:s'Q6=JM8>1+7G_L^75pi?Z?$o"9&$+pZ[?ML(qMNpC-#>3JXjD + ,/d;/J&'J3"3:CJ&@e?rSd8GL + ]dW"AF,c-/>e8?XNIWMbA=c5m)$sp[NF_E+6^G_m**^JfZhXuc:m;YiVni\rf1gacKt8NXT + $Qu#1.&g+6a+Skml)p<0;b2Ohq$[!WJ6V*mr4XP9KphD(O,;1=L)$e*T>a+o[a8rfs2VQ0h + 8pX]!\d>1N"HQ_FDFiVo2frg7P=eu`uED0jh$I[VGZRUQ2aV7P<]NnH"Mfr^k!l,m;VVV8/ + NgC:OENP(k-^>(10T8EX)+o\-#rh+iATY^W$%GopcjPGm_h[T(L_>^21rhDdYUQ,91c33'_ + 9&T+GiD(6Kc62*RAnXpf+6mn+mO[Bn39//;j6f75$C%NIT]KV]W^6WaJc;[p@--fgk,rUb/ + p?DmbTH,s+6qA>/qE/GN9Lh:l&M.762n'=riaVCl7T+%m]u.r[]tD_Z,Q^J!ZGiI-F0esCa + &fEmaCK<3jZ!ED?f0>b>9;KkjHac[EDhDB*`Is'Xo7bn1P"8X+%PH&9A(5F3Be&X-iH.S@T + 4\Fba56$afM>G?M5oA^JANiVnROp$6S_YpQ'^BJLj84n#6*/Ykq*n`D='t-p#@VrqoR5r6Na19Q^5H>)"S_+7J.e + :[%f!G5hu:s,Y\,XDC=82b0X,_bBhm.Yrs00i#`t"pm8"$;DO53J+7Pg.&>]_nDV + "<[R;&8F!WNOh]aP4MfZf<_M8#KsTHE[OSDjI<0\J?,Enr+7V7dU&LqZ4Q=X@'MRGdJ16!r:.&onk5Z!LK,J?Y + 4FJa+\TQnO$:4[7_J:=Gk*>u&h`j8m.LhW,KI8=$j.bNEkq-i_(np)YDC$`O\0Y%_XEsdnn + >r3D#.s?qWpuSFMT?k?RRSE`imP)n'audPfN?^rToF@Cl\McVZ/=Cs/_hC#a$W6#>]BObEB + Uk0GM`m*6cjVN3^mVo%*s0lN:tl/kGRdN<(ZY8C5^[d1Z6YOBi&%AC:o10Q:pXXY2Bq3AE4 + :e51nLOH3Bt,h8)-$*@bG/SPR"AM^H61[qj*:qkSG9ilC4fooDF%AbrLW7o^4gN.-?F)MPj + b7=,gh/N5HYle/cL>K7p&FK3(D>Oq<[5lM?&s^-k:)c6V1u`S^iitdSo=X+i^o5XWjKV]"P + Kr9p@cd46X-;?%'B'a&I2C1[53h)k/sAM>Np6)"l8/XJPR0V&VX)X4lk-\mCFqk'1@7^n*/ + <8hb=N]g2"%DFml!m]n2$ + >jQ7M3BaE6!!KdfPn`0E5nBR;`/]K%98*?22IgpB\Tk0T,!VM;"$?FfamK+3(b2NPDrbn'& + Sfihp\$i;kI:CU8;q/3jm!AQ-273cTA.V47Q$-2;:6U='dUfjj@^ho@i?Uh``pj(QNt^(\' + ^"O$?S=?u_@p&Y";-#3us2@<&=5nZoH"*F^NQm1^ofB%^Yc04Qgo[5L$4Q9@UY@mgh**c^R + XdIM=B;.W^,AW)mddKO4s@(LGjo*_sATA9`g4qEp"g&XH2_ + pQJ2cK;UF3QRa&:Dtd7o]4U?e'q5_XQT,Q\H1e._/bOF4Z$NgcHL;#b/eNGJ(ONDBi`ErX;*O"VaQ%K + h'XuHMEDkllf&`7Q??b:5Y%_54EBY'!Ie2p.ec1,B"+RJEJ+a8#2@f$'',jWXJG'q50#Fo[ + +WIp1*&]=!.m[YTiuJ``A$Og.'L-+b6Y'tTA@,!?oM2nq;Xnc)n]r@IcRD=AB1@,PG'7dnp + 2btO+\.flMbOhGKf7UYQJIMjTh[A@DOB0.f\]I5V,(4UM>$a@f)8DRa)Em@E-2N4FUnPZf.G + Sj/h$0cpE*9l,1*eH;R\.'=WK0k+YYi3dWm9_WBYIs7s$aK0ssk6$"nAq=`mk;1DOCUBodE + pCNau+1j*r,$+G+YIoZ\Qh),Ra\O2'=asLb?\2q?(&N7fu788aZVNFX&\P9V$8#LTmVlUbm<242MVeW:`CANh*HB. + hWD'q6V-]bg;n%U8+M/qL/P4_`-!E1cT;jer9cuH<"0sOQ%0f'\hP91)M,meWA1A>!/:p%'#ZSV2A + G10*k%?\"obr&F(%=)o`]2K1UM[l4^=a>S,1OWF?Jt\Tl&@79T(TBE7+h-th\1SH)EA9MQ!q=VE]q*=Wk5uo"WH3 + kPa-QGn9Jkk97==kPX4/*QNU0'JuQp7>?6F[k%nPiSCqEH*M)hj_NL!MWPmlM\U+(p`_V7: + TCpidr"H`!0Z^NbA(eXJT)%/O96ulC[_o)s\#L:W.!3]^f%$eQaf?9 + '.Fd6)2Wp'alRMgrXE`h,S=NIF'?W<-!]^&YPnT67hbguROP9;g'(:rdrK3VjOnCX;R4$65 + Fj61CZ+T%;gEVq%-^7O]=4]\8!]?A=?B;:>n^?0j]O_cGnBLk> + A'=gV:)cP[p:e9gO5LeJJ,X^>[*3;S!)ep:L.s9\bFXc;-R@*eJ=XX(A7:2F6R&BiOg&i]M + nX=RI@f6WP&n=5dV,S'H)I+iIRPbJ_TF@$U*1m0^`5AU!E>Gp-eBI"b[BsgU:/QS\`-g6en + 1RB"T>ZP]E*0i%#c&TB_Nq1)K3no^3e)^66!o?q[YW^1=+U!2/O_k\/ + *c7&l,NgpMYrOEZ&+`Turb6sMTB:qQSd8q[).81iN"F#40gQ4%6Nh-0?\0)eL"IPh#[4:mJT,1W?>80 + JHK6@oban3R6hIfpiZ#I$MUWX(\<%\SHA+QDPe)o2a*6*(W3"<$*iK.%k^#V^i+K>\rJdNWPGT`J7";8NRO?jit7APM@@"JY,IL%!H#BfN$j:F6Q%7((XL`g.4(P2g + `JQO$nLBIq"!`2.@&0]8L"5n^n+>sK6Jcbf<5ZA:."9_!jrWjVb#R,e\+Fl[M&-W1:eVLF/ + Qd=pg&3o(!8*gi`"F\&++nU@.-mA)3*q22rHQ\*D#^RVKRL"1*80QuE*XEqGJfW4l#^2kr@ + L.+LLJeD"`5j+KJfNttb^ph>H3eO6LDgG<+GU:0E(+gSG3._oZ+_60?-m<"sTS7[ + t=!333#Z`(%?!r7!80Ll_'aPsY>bHd+#Z@=L+p_&=Kb]Dq'IY+iJeR>k4_C@?l3L--K\?]+ + +GA"DJeJD5/qO_W+Y.N)KVA`DTS/I68DQf[+G(3h+WQ(GW$*%)TS-JS73I7U#Xi%@+V')8a + <:nB&;VJ7KV3u2#XG&9!XM$M80Ih^&#^WGJe)N;oo>\tap:*PK=V=MAB5nYJe!SZk(4(6+Q + Ji^K7X@fTS%7j2WmURfRaQG+pNXlkTU^jTniIaJ"d2E-)RDmZ7q:\kh5rr+6`h*OWWg2rf_ + ->6<'6t#PqbVVFUJrJ#:9_E.=ciH?c&1$6fDBTB\01U`\l!rhaVVEhKB]MS]:mTBai'Xrls + !rigCc'$.C2$Xs%BTBgLr\0(%!rjm0oZLGO\MuipmTBm0h_B8,!rkrs';]*P18,FK[ZA8<. + J$TCW1k2j&q`N4^9elXqTC"rDeK=0ermr7ZLS3no + [18]0ARn*u(V+:BH+6m*\ + WKI1Wa82?iC4/pY2,6Bd0`P,trDepO>!LP^s&Ln;=fYP?Y/gCM+6rKJX7?1n8,C+FlP<[*F + cs&]GlLparFh8bVE`Y1s'"I]Cs6J![oW@c+7"`4Y#52/a85$Bl`P!*e_[r?ReIoifRL)erk + ?GLr?(A)Ej-;`_,rc,+7(D*YgNHfa86GjlqVl3<\DBogE.O(G^m"2rlE.W,p2KFK!L\Cb?9 + 0J+7.'uZVg_Ha87k=m-]b;epbtL,=YBupY!'gk1&bhe#K6Ct3<(u`r8kYJcMHF6msZq7q44eiG=VJdIkTd[5N + i+JTFpQ5kInbT(_Hf,;>NM5!XTD0"@(6Us$4q;$UL^O#GD8EKLf3pTn32tTgU8^E4-S#(hX + 9);#`t:r>.hgE=X5b5_r8M+sZ(GO9bVKM,>TH`;$)AiiH-P6iAJFoW8nge6\(GMD@Xha?S- + -s%NUo2+G++)l&(,Nfh^O&+oKYe):7%dI'.fklDp&,_T$IrC7Ck+@"A?Migmu84b6Z,o$F[ + <($U^8Z=KnAGi-cEgBV(62n!AqRDf2W`Mh"AM#48[TN_2AInI%0.#DgQno4]b^#5X#Q!:!l + [i`mae:PgUt2!X\::[_rk+$_oUE1-E)%k(3N"Y7+7'PgY[ROJ-Z&.@'?YVsC$`foq\UFABR + d;/q`cJ4!hbbrK/0/"b6Rns+7-k!d)mM"W219(bkQ[p!X2'76Ukc!.AeraSOk7f-u,kbQ') + bL8_X7FVDQSe[V!cZ$)oj2D8^qQl@Dd$]6C3M,c8'Ps&,k.:9"dE_ppNR=BpCVWtfBP,td)T@L,-kH4iHqe9o!/\&8;f_esp*H.U1_ + 74\)$pff5K91[!KOb#E>mmJ9@859?8Tn*Fm2o.l$n9=A'Q:O8Oounk?``\M7hNA[O8ur_gn,>%^O + qZFUi_f,sg80P2lX2l?:]?]5&-O8R\#Z\ELke%7ZG"t;^Urd)nYq`msArLhgg.%oW#6ti\? + USr;FdOa@K;/uW4[)53R)K(TmRR'KP$W3_e:K%l(:tIR)0Pj_9Z>1(cXP7X#Vle7;[p=5Up + %H2#/deJc8u)B/6]B\u?-+SLat!;i2OViKWj80.[%/DL^ft^t@rNrdfdjVe2`Ssh8`$p[^` + FE2*\2LF96qY#HRrmr/;`[Okh`fEn$i_L+"GSY4+n*%Kcbr%/NN\[=o:7Ho!k`YXdTd<%PRq>i+T%HWC(d\,'=jMB3N//,X0/!a-(Dq1,$_E??+d.N4M"uab:'5d.]-_&(GjH%,;,k:0 + W*S[`LGF+)qQlLFL-:9Z^b>b\p;!44K$@dVqXJV/)_lqi\W]LZs&0jHtPWXM8"=/W67l5j6 + IUEO.'76^=na=P*Eu`;ju07[9N2NOg1mmF>]2g[A-qjC7guiTuW'tS)[kjWhl4(Vjo8IMVD + [M>Q61paf=UJ[ZIu,UME+UZ^i#BSL\T:)fN1o#V2n-X3?G[6/B"KG!O3d*[8KmlZo(3HFLO + !/:$N^SKV*=>\83'88c,W+S2d5B\?m;/WWPQ`"M"@Q3=I)SRc,Bh + j%;t/T^.lRCaUi]'/#fS3MIr#C,4L/BX_p(V3.Ag<"c!/PlS'f3%0;d2QVW63ne(23[>Vg + ,;1Q$?=Z%kK[h*qc8Vpdl.j5?==iP$jS1eNHYC5+o\Rm(oW7[m&Le8#sQla6;$RY5Rmlu0W + 6X?R&Y2,dPr4'2fIoZ(2/a(`(SHhYR=pm]b.W^4G@]DKXlr5[L08*[,pN.=.rJNsp$*7TTk + +je;("NXgOaD'0qHFY&TM*R;_5bZuKZG/>&G=^b=NB@_C";"-:l,b1`8Mh)%g_;_:!fcVQ461gf\PTZW6#G@#"augok9I-:d-*CI<3IId9OUjdKWk + tjW']@2PU+.YPL%JS2nco3m5)nbKC*b[(\ + og^I.Y/,Q,A3g-\Ob6HhPZbXtCL>83m?a$b$j7"S3&P8_(Q_b@tdQ/kY5jA&D>>YP>t9b^G + O"B%"%be3#e4Sa"dACj7jCe]jjc(%q]Wc64p2((fJ7F^0_jPM>Di%r5t:)m]f/7QmcJBgeT + -q*2eAEQF(kU;DS1noq(XD5JNlpenZ7apa"j&*P[NkY^:588,W%!+WiF?`'u^J^W1X'A/I? + &C0.8#,oVX'rc\@g^G/5NI;io4L;rBT$\Y^at,b4)D]2D@?r/5]hfYK5s5EahY!9^q>Vt'T + Ko`Nkjo@5l/I/Z[BkFILY'Ga\3Dj=n5.#(P0hWcI,'5UoPGYpE[Q9g + .6Zfh*Kf6Nt3]cdi9>iqceN5iL5.aBP9FO21*C%/p6T^u79N4GSAOJW@8!QJ5ba_8KW`.-S + 9?bURV0l"C'?<4od(H&c73'ap/CUIieAY,3`EHroCG&U[e&@O$(W>&s[+nZFfgXZLQt5*nr + 8?,[hSpeu)$K"i7-.Goj@3qHRAB&dN9So/l*SuS[-R(d"`$U!;V'(]f%ff'>k6JLo:%l7WR + LQ:CL"W.F\e9G:SV=4ZXQGTGu*7B:[;UWqe*tjI8D5=:bun&6Z#A*JP^38:j[1IMfPlKKe) + Ku=EA]%jUPC`%p5lZfY%mLam@[6bJ@2>\1AFnD3@bEP;mED;5KO"h3KXNM`AqQdI!@E-(:t + >,<7O>g!\tKD4`hA.+3O;dZ(!3`M:khUnQV@Y9YdTH_WqK0Nt;->-k,1`A?5r0&#=b3kMLe + UTUgqZ7odn4"S+X6OVXY%6J@89Ja5a/\3Z(]K=oh]Cij:D8&tr_GlN1e='FfX!#@J9Y?Tdg + g*]\D,<@F;-]Aa-@JfJgX3\kff_ta>jF5[F4ealg,#SRZb,#+jPi?"6!\7m^*D[`CZRC,g9 + d@4^6IqaJr\EHm8g6L^>i*?*;*A`>?,/M&@7S4EWg.k0X(= + 2*J@:'6=5'pfX)(=*D6%f1X,CpU*/V-^K[?iTd(=Htc%o3LjA>-\5n+C7e.UEa'3O?13#*0 + 2%2L$c(G-mMd?BAP]p7!YQI3m760jNXm2nq8+?:1+8jefqbp6HJ,rofh=p68s<@BK4.oN.5 + _UYJ\c)+CnU!i>,deY:h$M_M-1:iE&>2;&>m5@#L3BH65>9,`Y/NUKh4hEhkgKd!ID*L+06 + 9CFM>Fe+8X[B_M7_@t'gY3W7V8'Z*9N7k*<40V+IDf+@`?k2s13?H"K?hG9;V\BQgq2"RK@ + EVlc;f;=NF(Xg/_5.Vll8Jq^[6AZNURq->!OrpA]=9^7U-qX\-<0/%L$91&I<9rtPT*D;BqiV&,'DBQjAZf3TsU[BBq' + t<17OeckB`*L"7SsAbf?cH[)"+3B + RII.5Pi!k`,*#:LldpP@V;2^2qX,-.TE+"?kVV,@cg0i0q+O1HhC?Aq&-LLL=kJ\m\ + bUbd:ib.s#>'$E*$`!,j)/)/g3d`eGQKW""*P063ds`CV[d2[+N)RHM;q?s_cL5HN5\Us!k + p$l1-BqJ)Pt[4(9VWP@I7\@#RH"0=4G6MCT))qLSm6We`C%sietHSpdURu2j-3_d%F=C5Y/m7]P#$X4@3NZmQ)nm:,AZA8;QEE2KqlG-e.0[+:hVW>;qfp#,?-\8_B:CSjj5neHf(Sm\V^,LFHS?aaM + 9B$OMf-t[o-nt+6+:Fk?UCi\+V=[+QOp'5XKf4Q*Ek:Ug`XW[40,%/osF)@LiIbi]VhTDGI + d[&h_[4:ddY&5hgmQWnhLHis7jjP:5oHc;81q.@^Y@rVKBU(R@UBU)+8D?QqgK*`UmNfDf- + .EDO`(':O[nkbt7H1?cod*.IAshTH<:>OYoklMKf2ut!;"^]Y@qT$7k+^C,UXa7XZUY%>"j + kf%dI9&nA)lBToj6\^@rQ;:p3#$=4k]=jZ"-esA7]EC^.<4hDK+D"h@c,u(#sKaE9-;SpI8 + !R<;9dWUN^nuGE$k6(%#RRA`\UGAX!5^9n)WgJ'_2Gluhu4j)F,Q$"a4mnhl/B7a'G5bfKM + &d/M>]I1^LYPO/g>m2mi]#:rH$e'Wp"o'I=cr1*.kQ['=5B//Lh5Ei5KgK5`tO]F9rlf7Va,;\.U7oM1Hj + /YTu=;%0Al3OH:_0!X++++CI_G&c\$r5W6@&B9808.`Xh$kRF^0;(Z&">6?6i + WLjN-kNb:$RcRjJI:o["=kT]WWXdo6CJ$+7ApclJI2YoSq.3qZ32MI6=L'DTL)V,JI*_9OF + []$&<)/GZ;LfL+@6tL+Ws)[VL]!Y&:T08a:NZK#EnW\*M>^H"<=(#`6NoA!j@$r?u_>]prl-]L%+6i=pTPc4lLncC+@K**ql>cg%+6o!fWc0G + nYcTFrqRV0X#PuAgXG?YrJ#s]Re@$sPOoDk_l_4NX,D>+6_p/U;RO7f_Af$OG$KDf^^Ktt3b,3bN=STV*_rk$5InK7)BCT + gb+^/sOu?\A<,O7iW>fGOWrU]#hjL(_AUCCqZT5_$$nrl%D)(E`!SJ$HQTa&r3^A>B*d&,& + a_fgu-SA,V^Sp0U.SM_etHjF=Lerm&R]4Wj%gJWP&25KHCq+_1G)[$Hg&)KS_i9h:8)niB" + Vq#;TkAZRc/]\"/:@O:(4R#gfM5KTs?D%3bZ2[8?uMAZ@AU\pmJnrhj6_gHCJ!Pp`>Y!:(M + s!qt1_mm/oj4oQVEb2>%QI5\9grl(+Nd8u4-V3J0q#<#mr5#tB;X7V8Z$($8g6j\pAOlQ_G + Ac[&49pQ0*[.@%k+$piOoB+P>KV6;60UO&W,>-$]-$2-J"-2@p7Cm6Hr#mq*7=b,a8++)k= + tW`Vqh1lPOsp?u-@*0MVtk<"_FB=T:[kD@J + nq5mX/0-A9H^J"cE3LgagEL%*)"_cUgdd>7flA,R=`fQe#P'L[c))'P(5MEfNKs%+q'-:J3 + :'dC"c9&ok$O7]kFdd17tOb,;W8Bi$9=T;*jrATf0iu;K=E/mfD4%Ei\5L]u=:iZ%ha8#f[ + j=H(Jl:c],;?!EQClFMi8kMZh0d[Vps&CdHV,9blHr(So_+le$]jJcmk73rL+8jD+&&k'Va)cTX6V47qhiEBh^ + (?&Q1C6a8IH`FLIODVR9*S8M+agrgVB*G>DFAC8_:-TXQZU;//6cWGUn5<8sWP>T!L@F]PQ + QQP3DX).bBP:k.%'`E=20R]PW+]U.5B5O30)XtHj,f0^<`9T->$p$07mkBQGH$(j%m'S"bN + &RqhOb^#L:fpd2c5O>54ZPI9C4j,m+cn+Yjs)p$FgkDu@n"Q%IMrDJO]XOL)_ruMq&a + DZW_72]8iAfX4Yd/OMZ.sif]K:o/m!Z + fE/Ol]W&3o\S.`IQ37q2-TW)YC:+8FG,j-`+Zn`$lUWod:lr.U7g1pE8`-"F$ARkDb\:Wb[ + m@*BUl[atB!+8Kh-KNu9Z(K0VDF&t-AN7"*#AD`mP]n%k,&NY^HFjBgFGY\bC`L+O_T4@me + BMAq$BF]l19X0s]_>g;&Ng$2:91q)'JO[$$7\gJ<:_>iZW@:27V2\fKIN;PBolW0/[-=pGn + ("PpI^uD:etb6NRJcalJ(U#X_UW90ZHEa&EXeV@k:E]I0\XD/gBU("9%\7Ni,pWg0eLCg:! + 0XeE3H0]h1IcEc/>h(Nj0spZ*6FL#GU*K-@4u1HRh#Y%L.;5$FD2+[&;?[0Oj"]io1>PId: + Tq.rPYf14Uu8\#9eH-kbT.roAk\jNEd?$_2iE>!d+5KPk81kYf$+^sLs(8B0tS(l^'hNGL$S%a'fLcGN3D_oVQ=`=hSF + #jtA]O\Afcg?1ZS/[kaQgiWtc+jIrK%ER>O-Eh'&YOX=%Vh3a + o2R)A+Z"KND(UWNlXu`bj>u<_hds''*@Rc"R[o*&Bn%7Cg/VhoT + F+en'N2raZ.=>-Le!*nF%#(%#1%KO#)h>QEMS)O[@1sI*.XFo4a0TYu8c%Rh^dQo[."<&Rq + 5'd[Q3M2U>d$O(@sHG0\4`cVo;eC$PGrIi+.LT?Rm,%ud1-OSMbBdL%&DPG7n'0)BRfBX+` + :nZr$=RephpC6?7-n\Y2Y`bVj%VP_HU&()CneK'D!*Qj+SOlH?pk5KAcDmA`1-OCkjocK7i + EKC$uXe+6E#hl$9!7DG[&eoH9)$,m@!QSII$LZ]Od3?id1N5&n:c*FF3s2cQ"7ed(nj]oTX + X)7f,nNp"8&$@.5^_!e"nH.-11kt*C:2+L-P18F:j".@s!Q!7JC9&U15?-K*=/^-jN^[QDH + K4ZRjmj!.O\.DE2P1iWeM(f]M<_7o"+$QEsqQV$n.5hONB'#bq03r/PGqu'&*l$h[T/9N&' + P3B[JHZm4T%@01b+VN&$G,rt"]'&1IVkCeF+jlS1$];fNU.Yo>F^2)6m213"Y*;(BWT&Fjg + "n\p7sZTf,p6C3m+'QZn]WJM>UZC,c8'm!P`d9N,sXIBf52N_]3d;5=ME6_6kp="E`-7'KB + Kc!aET9G6OdubLT#oQGSq(J-s&"[E2V)ja;do3EuYHT3([2Y1;47,f@%9+UXaS_1F4Uks#/ + SZXfgAS;64tV*[9n4[tm/GE&5>@7>@_VlIrr;NjEj>oMEXMlF3rnQqgJ,:'XhZX[+!NB`,% + kgo%/O!aGH8Fn.2'[ono'h\*O7l@\S():%3DcmjPr>,!G( + Gg6*F*e_0Ii%A4(bG[\c\"4GLh+ns3H:BGWZ*tgT/n^$U9UTE.Q#V:Yg`9C4-cj.bt@lX;& + iTF4LMd`m9okZB,u-84k7_>%>3?d6&f'H: + FM=^[-S!`flg0J,Wb)acM)hCpqGP!NQA6XnP7hiLIfnl'%_fOUH%Zm1D2dDUfD=%fLs?T='X-mRLGG^^1MG2N:9cOU?VDYl\NEk$hdaj;*>`+ + 3d/U8C3I]9a-WXXd:nb1X9jZiG&5V8ZpFn7kr2aHZW!AkSHcl6A7+^hZ&gsdc]<%N7#0X,E + NhGQJmWuYZM,2Z,l,jkZ=Q9)A?$K2V*iG2G(X'4Km-RUMt[h`/VDDpP'K]G%(8="$^c;."I + F\,+c8W0PT'VOTmWG%NsB[j3J['OIg[YOLd^!;T$1o4lJDl7T%fcE=tV]YR@QlgjK19 + Ijr'0^S5X0FliSPlYaP"R^C=DKQAMoao+t*Dqk"&m"m-2ZHZn'2l:G;X%[i/=.%c3qDf4ER + dKu'hIrd<:j0f=Diul)\#iSU,[U[qC)nt_kS'/N + VYREQIDW(T;5SaD@YnBmdA'J3/ + u?Ps%'o4dV\;3qIYrja*-VHHMk`pU*50\KA;o+:>f01^UEGbEp]mgQ33*q]D2lh-fWr!fba + 9\*9<_iL0="RP7%6Q7ma[97SirJ87JNO + M^n$M3RgmdfkUB$H1Sp:qOc*qH$O3rt5hG]fKY^(BX,(1@`!6N7rDQO"1o?0tt5MNUK#j2, + B6ZpPul_Nu'^E)##s_kE"/5_"e/7'n#cgMYMQSG^o>46b4:tJiM5'^90Rf-OIAR6&IQAW/koEDJna-W5cEs@lnu]D;O18HjBjCTeqi+8DBhUL'9UKe6H^iD@[7ust\i>>:Y + .LG#l(]s(],&fBp=2sm6H":4:j^*;\l7*?bATO:V>.aS)qRuY=cAehebeBH?"^(fgXb-JW- + (h5\rD`8=kD22O#(_,=$P?-$$9D]3#iN3]G9+BJ_@An_:N,4*Mmq-WB+95=k@f6'r@*62m' + d.>8+t[>2sl'6Ikm%4]tDUHLY7q='ZL(?!@,Oq-M^a@m?AnEEm?e]Q(1+nZ`]9YuDCAS:4[nlk"^N+2J3/60o/.."VreK;]pT#WS3f#4Opc&8MCe5mDDO+NasEJd`cRqC + E1`";\fWO?m/5#V(E5@"O1WSd6[E_$$u.,S3HK&Qk]X(a+D9++a`jJ_OuP3+gSF["9',+_60?-m<"RTS7[t=!3 + 33#Z`(%>hjoG80Ll_'aPsY4.q9_#Z@=L+p_&=KbX`B'IY+iJeR>k4[l#sl3L--K\?]++G@u + jJeJD5/qO_W+Y-?]KVA`DTS/I68C[th+G(3h+WQ(GW$*$]TS-JS73I7U#XhaM+V')8a<:nB + &;VJ7A"\Jf#XG&9!XM$E#U'%s&#^WGJe)N;okg@Sap:*PK=V=M>_jNfJe!SZk(4(6+QI[=K + 7X@fTS%7j2W"c_fRaQG+OkuP3!opJ+G2]\1E_<"#VohE+NB!A80Gd$$lGuM0;*pf#VMd%iW + q-s#U$L+$Rd.%JdV"qCAJ90$!LN!VJ#a9J#9.?DL\Q3qK@@d]8D'1W+n?lUEAb + mrhZ7PC&Y%"$At^\Wp8::XWQimri_s[$3%4#$S'H/X_W4][iapmrjeZeWW'O%$d/1WYO!/+ + _&r"mrkkAp8cH^&$u6p*Z>@)Nb9-)mrlq)%l2K$(%1>YR[3tiJJ$iqd>GnmrT:X[nXh"GdT + C(>2hYRcZK&O6&qi$$8-i93Z\Yo=rJ%@j;VWtb\g&C@\mcj`>TC3*cnXo8'o^faL=mmHq\: + :+_rd;c^ocNAPJ"N)DIa@9Y5\'`n&+g2ncoD%k,Q.e,oG\#HH4`JW>^rGUre)^"9cJ"c + XIX8a/ouV'5i + '8,?:/l"#:?\@.`%qI*'mrA"oUc9KcKs%R#%2NRLf)\\*M:9!<(Vh+i=a813+l26%0&cSH` + l@i(",t>q + <%#Y7^cH#Q"$6ldUEfEW3[alMFqhrIL%'"@(Nes'XmcKTGgB5M0f?@I-F>Z#Tc^L\hr2lth + 0VdJh2,q]VTuNKUSj<^586s(.u(Q]LiL5M;G(B!ajnZ^,d\a88%C6kFt]nds2P,=lNC0rHl + 5TLK1^)B\$[X#3q`f%TFsCb:=+&+Wsiab+5Bc)J-0k2>$aO[(#M#_/(.nD2jRI;eNW^m-)B + <#+6?qL3-Q.u>^MTR-('1JJc8i.q.t*^?-Tq353Q8YH6;89o:CN>H:HiK)s=Rmc2dl(6i>q,pUp9n,N + aCbWV%8trcO"lfR=@Eq7g#!ra4FW4TkWT&+eHS?j$U_clrWYa;BC3q>MK"!XV.0.g=kT)hY + A;#S6PQ5L?2NKM\*O6E"#p&J4t1KDcGooMH%UPW":.l5i=2Cd6=_s$oHT*^huA&Y_ZcM30M + =&+l5RdW#4Y&PacDBX&>IjBP?qr@ecS`>G?YAW6/V29+;&S;6r_+6hK>a!gYD&A0;\6h+7!$YXb$J[VC]ZR'.RTfl(#_b6Ki7sU,5$GC=f@DX9hHj5=).B7OqM5'fSBD]VR50d2MuTO$.1qSA,`-#.Yuqcbss4 + :6,=*.R8^,>;K4<9Wg3_-jG3\;X-J"83L;O(bFs0&6iOGnWnCUI9<#'@+N?Jds';\EHEW@j + gt2-WBH@`bYa-3G4GT&.c#o(mp-n7L4"Br?]pZ3FJach&Que:OlQ>h`doqOdr,#Tp4@bh=& + ,TjQmApA>]03nO>"IP$1Lfoh;B]q#A@$gDj_&9e!@4\l[=mJ)i/;Og7B + `QJ!j&/Lc-5nqL&bR9F)oCpLR;1s[9>HSB%_aYfs(B3rdHDiahLS$Re0S@Qmt0W#jQ#QB"p + H1lS\D#hTno-0hPs$LIZ'g_%INFiU@Ro(@/V"CgVUD.341cdemFSe_\3f]B23`=LN8Ku]%H + WJTBa\A6_ZmOM[\*Jp#h.dmQfB"MjloLHk.XQoMJ*1CQm@.-]U9:#lYeUof*:mts3RTE\dj + oeL[gCYF)S2K6]Uc@B^nZ&no62`'i[d+M2lP:d]6k'\gFSKQ/>I\9ilrP9JW: + 0mpUG223.^ueP1UlIg)pKVO->Qr99-.>#HeC>\KM&81(?61jWO]g+VU3(e!R\7lQLTA+c>_ + TZ^mf5T!'=[Y<,'s,1MZ#n0W1qJ7YQ?J^+u$UU1cjVR3qEQNK*\69ZBO=T + UYE/[dQk&-6+_\=4-E&pUD'Ge'r7VK!fS=L'DZZ:n$+P$P_q- + `.8#VAh&)1X;k%ca)hLZO1EQ/6BMOD7rk*V[GG])q^N6fr&?6ZbguDid*cHNBQi]^&p^#)a + pVTj-auLW,q(-P);*%Ma!;`5,1l/@#$T?VR7*)WB$t->]7#IXu0]j59cO8.\'!r>+9;3[EJ + 9D$+hZqeBu6m,_mWCF2IgAanu\F^YFN4>Mj%qbbQFn;d]7*2[fF<)'66?i]:Gt + 8S\'$'drr3J%'1o;XA"Y`Z0&k*&>#\+U[F*F-n+DR6m)'+bK,*PFW;,SiQEpY;.4R; + B\(M+Z_]\_]nq$K)?gVW"QG93i"[<&hl!r\@UBN3pWueZNm7`$-Uf(,KmGU<'RVH5qrMY]8 + B$=S%?O*'Vq36b[\@4gV6./)Pn)eV'Ekm_o+Z:9X5R>1-/T$M.Sl>b/G#BV@tGV,L.)-cTM + D2ZMJ8k)JVDqH9FpO`M5>h'0+7SfdB_P4g\P%dWr1ki4\E(^&-a-1IJ)c7F"im-tD@&A7r9 + DMR:=d^7('#,>UeHlpfIk)O,-Rlu0W6XZm/[2/?;a4'@E8oZ(2/a(`+THhYR=pm^=>W_pUQ + ]DKXlr5[L18*[/qS:Ej-JNsp$*9;`&1""'9"NXgOaD'3rHFb,eM*R;_5bs;YjGYW%iQ0d`a + QsD.>S"p`Xhb[!_'=E#glt)mPsJ:;_.(d$4,$7iL5t=58[KF._>_R+*D,<5+=nTdgQ&fIU, + a(m68YK)7&;%(VF"gk6?3aVK'K%OW^J1ac7a-6MV$+n + .PfcCib9]j+1'1QOgeH#Z:<`Q>bmPmG"O]^admZ+C-;;rFib2&&^Rl)PrgI8L) + 7Da.8dlT^ngeIt-R)EE.,[sM(JPJUD:/kdQ<+[t>jh>j$5)Gq%V!C4Gll&Q6W>e\l/8mC2O + ?Wkf588,W*-4>$F?`(!^J^Z2_d1<8?OB0r8#,oVZXZ5;A;]Gs5NI;iqe3bQC(#]H^at,b6Z + ,.fDi>rs5]hfYMfZ\'FUZ3H^q>WQds44:eNibg;%4+/)h(@9'=\/ZN^OW(C_k-fSmb%m=T`$`]d.+4$C6E?W=A?6T_3/Up\*F[aS`e_gsU2Pe'5X]-D^96c?Z*dQ>A,$p.+j9G=n"F@&YX + 6VKg;bZ%#)A4@ig7kp8u]G*rM.9fKY9?bXR4D[bTJRqOY:e_[#]Ym^\fl'SY<6\]J4WINd0 + mQKX=\Y_p]l[JG,[AUL?-VYZc2:qo$t-!W@C.!34riXt0pY:6k/M6#W1<(kN9S?MTiQh^)E + dAc'Q).];a0kk:DIbC,?IYuE6ghWcVg?!AG7tApfC_rf51;l,PsA]I92s<=02E[HiLO=J_/ + ]ZfBi[Ke-%\rL0,H$==je;/-r^QMV)2BfPM&+KFKl/`E8SKfWC&t*0RCuJ&t?7=R?l+r>.F + ^(g/.&+-d`rC`Cd>Ma?0c;=0`Jqi=VaRaN)];C^_D9dI8[-JA>F=q)l?Ua`jeX4f]eg.a-/ + r%:#EYZcH/>)b6t<&2%$[+`2Mg`2X"5M_4&r^frO4%0\1o6rg + S;DL>t!Gl7GHS47#Sn*Xh[o,_,RJS`7)b#ou'hk`DlHP72sIq4igVTa]1FL`FI=jL!3P>bu + KDI7B>%HQ-_=g?Eogk@ZW\6'rc[i9B + ZRrk_(L+E^V2iNbUV28%IMGXb08L+r$ecDl>O"CJN=VHM*Po87<)VIc?fj,V$C'!"6h*M:5 + \I9Z[-(IjjSN0E9;I,n,gBBUKrAr[b4/8o?Ye32!laF_H\'u/&e0DQS27lgS9@QlW]CWh^S&-oA^p3dT]O];MHR + 2oi-G6+sbq%$o`Q5@>cb1%E4Y&l@l4%9u'(?!T/0H + Ojj!<8em:U!J*$q-*EHUaI=pZFq&S$t5fJN@Fo>p3r`H=<=N1?W4+QJ="(pAN\4d`!@b"k. + S#q,Ffj`_!9V=!"G#At4@-j\l:(URnki]m`=rr-$;B"`r/QuJ3iK>DK1bm^UKjiCZk\N.\h + MC/,MIIm:3s7XW)[^9>^G*rogM7A[Pf'aa.b$NrBjA_`k*P*(;sBN?>UGqM3a:jm:u#ZSj* + G5#"BA^(U1:cMl9&5)k,%,;Vdp7a]t@]8dm*-)ij:&6h/c%rI-3>H8QK=pep^9+[S5!'9sl + 562*OfB/l5U?=2-7gCT^TBFS<,kpGMBPhPOA_*a$b.=hiP(=1.MD"n9kZnZ+"Th`V,"9a4s + .\SQ]gd$=CQXnf%&b29lAhoq-gg;cbpc;?0PXL?I-iUH!ZQRrtjd>l^h%L:CnMF#FDm@1(g%Ogu3n5M&;@_S+M*qNk&7q2-^ir^BAB3&7h9\_i,@nrRWY+ + AW'T1(s@gn.kWX]=/jraX6L4^OsbSu*ko@bhi1n1E)X4Q16R?uTIcnQ^?Tj`bp&GYcS0C^ofDZY*jg!9M] + 2lpZDDm=8#=JS]2sAg;>.2$rD5$LFUEEa=JtmV".a-p\)pk-lhf7aO_6/D17[m4FIf4IU+] + )f8q:;9q!hmap-Pf^hh+F'PJWXX!5J3)Wg<8q,UM(ReMR.U"ag@:k$Mn:35Y&,%7XLBCsMf + J'6C!X?DjYFo[`S.0`G?,5&g29ZML*eCHOCM4X;#.0T0eo3L2%:]KB9H\*F)S--TJZBo.\_ + IWo"'!(d&2cT`#,ZsN?tr4NNWu5U^sk%q":[Qt:KATPfG\c7Rt7H0Bq$(O0`t(ada0hQZ3H + PEUu5r8)Fj#p83kSl1is0G"%HZ@BXes1#)Ro*0ebFH%1ND+^sJ0"*`<2oJY6Ca#TKpB*Qn+D7&ZiWaUXS[L4.X:4=q3P`p:1QM#1E.OM:B':,AMZYk&c#>I<%+ELQRNQ3e + )4Cb@JXJSR1E6hB"#.O7*[hnT#$ukI?tICsDqb@G5g(i:`!ijCJX)m>=;b!@.A1.7!eH4W( + ncG:kSTio+C]'i-6Qc$"slTL(m9H,#T/SQLr^Ek%j5=*"sKXK&dBJskSSi$LZfS&JVU0@Go + 7`5g'/Q?@EJco7q``WJVM5_C4V+q(hY'9@?Lg3TOEEV(WkkX>_.U-(g)?CEl&"q+CRkH'Hg + gF"qs[D(eT@4L_rU4KMu=a&>3G5"qRA7ncfTLkSQ:1K4l)YJV,c\"q2V^\crNb@&aD<;.pd + nJV$E0,(Y=[U':jq?ucGUTO;45"k2ZP'S1f`(_D7Kog/ib+CHZ'![(kk@Y'&#(]t9SVu:aD + f9P8ZJ"Oe"qLP8p)>@V`B@7!3TP)+GHeIU#m"(b,)QKukop%i+6c8+PpM9-A:LI(qIkAUa80b)VapT/[jT< + "KVKXS.K6+bl;@PX+6mkFW,LsaW2hF=qQbUOL\eZ5X9\U?J#o/lbd8rpEW3D=l[f&G+7#X" + ]6!;ToY*!&&cTS6i?oooDCi"!<5;\8HL#F&;(5a$QnRlJ"ZoBKSTC6]=@#YEf1EYi5J"qSoNedHnLa`'A,UA2/#Ppq4kpV% + W_>]XRqG<%u8Lc#sZp3![s%A"C0+[]j5LU2D9Tb/f-A9m9j)`bXK+Pf* + ^U]l]?V!EW3O>qWf6h["#7SWk;E%oj8sBHk5oD5M,-!?fV*8O7if=Qn&DM/2Vj\_>_?mq[j + q:9RjB*eO7lLESp1Q\D\Gp1drLK#CHUX@u"!FB + :K9,R9d97bcBh^=[1u^,PaN4B+A,M@p!L,UA8H+R['mEsgY7!<+626`UF&$`$3X7oV8,7KRjn+%hp + J0tD;lk,e_:TUPraX"EOWW^[gUh*?miD#8GQrhNRPFeU8,9'-mht4La.2cCJ[HT^gjbfUrb + gT)epC24mlgulE_#rK+6PNQ5$-2/heV\00?!:>o=dH8$ho+rl2Ep2!o`s;J_T@UJ`9[79Xs9V"COLdakMMWIZ?A/UW&s>&R/?.qPW3gmjSZi'6K + A7&\A`]2XrZ;bDt!+8%greMduslEO\I-'cR_qRK\.".4-EN4G:!69jd)C9c@$,0$)CB(SUlP-UBWbWU`dB$M:7HmAX;=th`[kuV + d/W(+oc=pIBe84in>H;epH6*i7&[Ua@-HQ1&l@`Xk10=WY + JgX8r@&Es1C:No%nV6%^/bj8$NJPhYZ>\n#T-<=5bL&(oBOdmJjsVAh;k.^6hhMA0:Rs#%6 + ZF)R,*?:9!A:O8LYcE85f$G^2ZTPoCm%rZoG7U..\tt_GI9l^3$1H&p9ZZe:1joE4F + 5l]+icT9A9h4>II'Oqg;J*62"TVq_fd&`Y#:kAY@Zt>?H'L%<:2K[9D_#Mjm$BI#<3^`Q=T + qoq&Pr1U.p[q0`eTB3CdtYoEM6=4&RbFFD.Z3%>kt0LopL)M6#?73Ga=FkOa)&o,Ef.SOc) + **FWnQa`FDBBKWo!ho^3-QpY,>m8-Yfih.,@C>h2;J^CCYTi(B^f)H*-M?-`42IWj=BQi!6 + jO90R`=7XV?O3c5^]c5O*GkdC`_ie,P9a8Y*,Ee(3:JF5TcDF/pb7_$Mj\O\F96ltHM>e3H + u]#[XY:o*6p?KV^3L9&CMld6)XJqrcK]uZ)F8<1F2aQ\MPl-&jZX8n.GW_9LtN"3/0.*TN+ + d-Lnplq$.&N%C"U1lj9?:p/N6:>Wp'&B*fIm_psM#q#+7@$<-TPA^M&Y6OKtGa/\fnR[$fM + -e9IORai^i_b-LN@5XtJ`gHFIPr\+5(1#TVo#8I3M$K'SgR/lmVm>7&KOKZgTR%VeCLDW`^V] + LZkOaDg>GDWjiP$k)!LbNOcmQ:Yt_l1!-9aK30Tf]pPjlOL<49GWTR+"j_5NUFgQYkGs?nA + CFem>1i1cJ]=n8s(Z'0^e@l0(SIN)TG?*`mZ("8OW'1.`]Y0'+%e2Yr;.B3gS!UQOKKC0.r + V&1@oK\b6a?TP>q0GU@aL@((A?T9[bn<>+AApp+^U58_229GkVO,pJ6&O9`CZD#<8oATT>! + K9bsF>*hfd+B+LU10rAV63,!%m3pf'L0=5I+\GNPDqshI;0uTr$_&TZ'*:M6k&(INECtCDu + f7K%^;TVgrt4i%7hku\ZIt50+>'B@n-L5A%!5AZ!AYAjEYrq>*3P'.+tt;eE%*!/G + 9Z>UGZ$C$E]F6-4F(s4Z3R3OE(M=Z9dJo2,qD**;HX1/>m9EA"tN[3Xs#.;-9SMR-W#"7L^ + >HUIjbk[JWPVrN^i*XOQ@`,$$)F?W(AH-Tdham.VN$9X1j=OYmW=p$Z`b4ZFmlLM(C@"/9& + ]^W1,@(p55$`%o.X6C1mSGYQB=Cgk_>2t;GY.J5Z?M)_c!TM^fu$55F>R5qOC3U.nO/M*YQW7+PD+gJ8IN + Bl!5]%"l0*NF3<&%c6dJY*Db9-L>s<#h]<E/?!A.k'nL.57!=YaE!YQKBlqk(H)OOK0k + \W998LkN$D/Ye;RZ]'/Y'ksU^dd*F9Xbj&$W95r]=nDPuJb:[bu0!O]%YjfMiaR&Kom6q6k + '*AeE#*AEa&CV.%#p0aQ>jkGb1%,*BE@!A[.8gZfnP_/?YrP_r4S!JY>#@dHO\7OQO#7MJ2 + ,RDBnQO-i9(`j.ok!e3ZY^KLE1Je-(NXje"I[9V- + /d63mBZg#*Sj5908,(qoqk]26`rP8s]I_m+AN5?1[es1]# + e2s'F1VF#4*&XfU84'&/<&?n1t).G*;hX0t]NV]t^1:++di3HP + F(-b7]6Ui[K7WqKqVt3CDD$Q;Kj,eh('S0jqK]JASB(V%7FHF'D>36Hjk%hG>9>'EtG:P:n + ]f)+gNeZcG`9Af@C.n3`cD)t/WG<4"CK0$R<8VK`if/'B_Jo0Cma2Qrdnc:]:X7oq(?&(]) + c2Jt&X@E4&,fgoT`A$q?Si'rD6X*N[ion + q6'_[?c,Tl;bp&Gc6FIUqmG.k=j!1uU6e3PO%J'^>q'=NG7.rK,/dV]A%^aeP[4l6(N["c# + D.PPDASs;8[!QBJ'kStO#e"L/n<6E:F\+K9jm\l(;Pe%`UM+bHk>8DGZF=O)[:s`mkchqg' + $4lFa(f_=l4DJ1C^4`,%1Y;-l`f\M=b&L-qY<YT29c$$' + &V&kM`HF;J,\RQ_][?d$WXB3:^ebOU'I!%Bq!VQhJR>c>KhZFW3IX.H/2sg`+.=YL%HT1g* + <]P[j]muNeA8WInXsCH#)(03>JbE?Y);Q^!Mk2b_\[XRI[X3Z&p4[`[$J(,gg'3=W;[`;gK + t8%VG[V$sX+m&jLAEE9NjfL9]YYM80.\W0pid)T` + n!D&TgRB_p=BGqD+g0g$=1VE3h&e'4*hd?IMZW#85kqY?C8V`q5;rp>]L=0n2mk1S)]g,fn + 5(W>&%a[$`f!Lk0=H&"^(MaD]LYT#0^F>K>l3LT1RZ^I^Z=fXs$Y-XTdRrh`$ZGMIn@EC5>& + V+.F1rQX_k\drPnY + MHlR:6=a*.,HU1e`Y$3'jFpgW;&$hUcILY%\<&K,d4gT;Zau1bfo?d,m&bjpCpG%\7rfk0$q.9gjb=n,(Ooh"uS]=WX?2N:?&OgphfKhdJYP + eVq!bIMeqd.XS93,HCD),8kbUH!\M40`V8.u9W_di5trrAg\kS(%8VDV[g?H=PIZeVb.eMc + dHd'ee+f25dcLelN[=S*t@Oo/1mhEH + 7LOS+Zs/LeQ-X`jL`G<@V7>1pf;IlmCWXr00CNELMTcZo`>`7;cE)Y74&pDuBm5+;MjoC'[ + RorrT#Ye4gZ]Q#'@'0s8*?aLJRq]2%?dbIpU69!X#].7<;Q!q$Y@J_pN([g/so0dfs"T(Pr + I'I1g>C^KdbHtig=il5B`O49"bh+/2][O!p#SS/sjT=@AR3(llr:CEYL+ + :n"X!X/]G_$87PX:T(K)8i,"-m6M80S0\ln3M.->6G^-"`akkWX(&*$6XqF+IZ@7'#=^45o + ^G)1kH!@Jd":;mG:dBsN+^BU$i.1#62@' + _C!poDA<"K]G"@3%^#Tt#k"bHatJ31sd"U"hA#c(Q$%gds,L`c*L,PDE@Jj/_o8(8.B"FNK + Vq1p9L#k`d4+HJK,b=;\[_&a.XHkG29JidA#a7dL_te:KU:NMn(6#hX_dqs[(^&ZZ%L5oP3.,>&6hJi"U/s,7P\"D5IfO@EIeQ + 2H4O-m=\()!E-&!hb8t#\"p2)@0aoL(#2V(^M:6JeuKOHOQR$iWrh_L!g63TS:B#WeW2U'NcPK9?L"fLR.CJdpodgk$!D=pR#/K3AO<+G3CeJdhu.c@QJG+Nf9EQ + MLkATS!j_0VF%%d"2Yh+M<:6W$&U%$[8$F/KfYf#V7*M^%d0da<7L7$A]h%JdPU@#Ul?tJd + <`sJp&8g$)eu6JdH*5Q&MAf8dH[bJiX/^0Gu&5+s;IU#U(=B%Tn;g#U"SJ#KS$6Jd7^T#T] + RhdKghcL`-VMT]c.aJ"^NO)LnIW=sAftW6,$t+6_DWNh>P2rfHG;)G63i.;AdI+6e(MR%NW + 2rgN4G\oO@>WX8Zt+6jaCU7^^2rhT!T>+2@h.]NEI+6pE9XIne2riYc`qSKM=X%E;t+7!)/ + [\)l2rj_PmRd.MgBDV7MYG_6rJ$:I_;Sk-s;?"QWluE$GG"e)Jb;2Zc14QWcq`KA8#Q$o=[ + %841e29s?rmm_/Jc==Em@jO6+77+Ih)C>bKR^KZqhTa3a8:sJ\OZObo"!%uV!B,jWW)6+ma + ;%%+7A[un:&[saR_PbqpKtc_>\e:q=#Khao\2&m!]JmrZC=qJ"QiAJ;Llmie9HWLMJ#)'&PR%%_+6cUOV.d#t'%1#Y"8sm6oY`uC+TG-QrA5&WeJ]*1DGCMb + J#>%#SVR&d+6i!=Vo\:uPQHG5MBIDIEW2\fqMZN]3.In6%]#>`Q;\-0J#T^PVhb,A+6nZ3W + _"hBPsVKNMSO_Anc#VFqQq@0fRKrY:9KlA^/taSJ#kC(Z%r1s+6t>)XN>@dQ@dOg_u4>2or + p[3d/R=&rGN5>_(lf>jBTm,J$+q5]*J3#+7$^lY9EnY-Hc$h$gE-Op%go*!<6ForIPRR$pW + B4l=!@@LG9tO`(0\=+7**ZZ%;noVop&ib^km3:l7OV3<*P7rKWH;>='3S0kP7PS<*A_5M=] + hB;>EtZmLCP)Daou9eiLW+oXn8q%d^>7B3b=ZI[a_,Tl*7J!,B^8t-K&Cos88[^Oa^#PgD& + jR@Y_k2b<%X*8J6mCeb#r_nUJ:`ndj_)N5j8A,%o;;C,>OR"oc2,2!mWceJjWEZVrkHMT!2(SAJB-/hT5j + jZ8,<%5YVHJM-n,=mZ3_W:/:X>?re'.q*/"l\&jg8*LI_1_+6\B-U,Z?b+bVV*OP1Wu&cRa + 0qDF%imN9@aLCmuX7nBER,EMJ\'4PKKMG[8%7>S168,?F3l#n^KfY\Qd/8'qsV)FD,hETJJ + DiN/e3_*lR*Y\>K:a>p)O7`l&j7IqbOr?_ZKdK%6W;fcUrCk<.*@.GVQBMqi;igTL5Lim9< + O.'L8h!=\V*q7`A,T_pomT-V%'PrEb$%GPE@r#Os&pZGC!5af0P2GAagjIH>Dn]8+8(f'_1gH24GitJ/0oL^Q,/&dYNI]ql4Mt) + 8sVGtj0j&#ckpa66c#iUE"b'f3Ej/I=[a.jeg9WL$GTs._DoOO@)tM!7rfc + p!X\dnLoZC$In2ko3LLKQC(,MH8?.HXN_#QWQ/*APQHP4`1u>pM75-YA-.JWGVd8s*]jc2F + UVceRcfOli8r#bVkopSFX"W")SG;DDq*)N(UUNK"8?6gFLD$2b;6'=l?c(_&bYT*_UegMgH + M/Hn9R0/=Glapu8din[KL_+%jm%>D3R1L**1G/P5mmC&U)jp:._nXf;N+ap"p6+ZTl9\JjG + "b2]/Kjhb5f+WHb#MA34n's>b13P$*=b3u%HnY+^1&_j!',GHi#,qjis3a!iAC+?f@r1_pE + U?ein)lt8?XY;Lg0N'hk#s5a9G5-,"12+-*,*B;I-SK?G*gb]ZO_HgFK.2/Z*U:(MhGG]@/P[DR2ZJ]kN#1H? + ;<.32^gYVh:%p1jXp6S7k*&.=U\,U9HA%5(6_3EZ^"C + R;nil(M#@TjsQ(9:S#l/?]C$0.a:f$6_GLU;IW<,$Oe84/O3kV`KJgYM(T^r4"f!1-3U\_k + R>ZCBdGTYp6"JN[HU7dI?XqD.8<$]Us--C6>b(Ah#7&e%fWktR4To?(Unf1 + 9_/^!]j?99f^Vf]Z`!!o + P*5\rV78-*:bZ%!S@S+db(8TI$`.Z7NPffgBbH]c$9[lb[jA!kh=j7$oV::1\$1OIcfUu/krM8f\W`Y*_q1h+`uA'Ru(7T2`(>j'+Kk + f/;?W2/^c`9YFLlUJeY:>8UZi/KqmE'FKq[9N2ZE0j'^oLDmS27*"aaIu+^prAp$[L;sj+K + J#]rC>rK2IlcqGdU'^!QZhp[_)_Nj98(c#>f]saG^DOUN8]!c+puO5g5601ljogO?iX)5mk + W@_gTWoIh!G4a^c..EV)hU(WhmYT7e)a4,5eSSN*;8_;(YKm2n=K+Lq4HattgQeL\8t/eQ;\9+3LI)C3KW1.s_c,)e?3];N6)\%8Om_h>SM"g_nnFOdg4FOZpX_uPYAq^*5b_p\\pkI'^WiXAB320^I4!qQ&NmSXNXYE`5L-E(+deMo + [)+Zb!d1``@TM-4Okc`ejWiq7;?PUHSIZ>eBP>N(]7L^e6L8XG0TYcc3.LPXC/Br?bQAI4q + qO&>=?1ej\CHj[%utVSEiA8Bhlof[/95J&sHAEPdNSQ7jD'6V/[rr=Z*:([DJV=;PLSb?q7 + P3WeG^JRq+E^J$sC$=44=]RqkP^CtJmq=;?D.K5jGQKLiFk=Bu?fD%3ss%bR$WSn/J7A.d3 + >IR-,W;,rZS@tIR#OjSaS;3KBoXW'6a*8,0LfmOpOe/u3eU04TB=hQ%?/0m5DVV1>`g&3;/ + KIFC$X'.)*>!4DsgatPWo3,o$_[WQU6o*4CX&D0_3ea\7AZd6]Y:pqVgCpbX]fTF]4BkIb6 + gM,''t7-G\5X-O`&"tu?+X'1]Mr+L7!l\mV8#up^f7)H`5BPfmDDoZ`)Q'E7178DNQ3fM<* + YX5`FW%S]iJC]e(ib]h!/laq_psodClVg4-`H]_bH-bef5O2q + &%=HMKIF'cb^b]dWlT + A!j0>'2M[/MUG"1*V-&0=3T8;lRZWY1%g&du1?WS[)1o37GJF4!V)U"19i=\$5J5]9L7GWt + a=#(-C!Zb`fgs]t^i$_Rr:]]NZT84!Zq@aiu'R>]!?nI8[`>;r"3KVN"T^$s;&,eO?Ud`6nH;p[;nUWnuWl;c+c?9Cs:3+LcLZc9%@-.V;36H2 + bg<]fB^CZ]C>M.D!K6:WAM!Q:4SWJ[U2/UdcaHp$c<.* + 4^u_Ztjh1\+b-5\G?I2/KaAu]iDT:%WK2A.Ld&pp#`b!6F^ufbMCt<<-`=b,Z'"@;U?hS?i + "+n@1KP`Vdi&r!gKH%FmemNB<36l\F#'WBTg"F@R;FV*n?4JT2h-gI8i>!hN,49=Q'N3Ks9 + )]T!'(t431%&'[k]J_nN&E_ok\-h7>77T$X0:s"+_^2Ikl!\Z$pa7J\Dh?l@XUW'M\Y\-.b + &>de:oNZcLkZ694IinisR+#L,.9X1X.g7btBQsAQ3U!3,1l`4[`Gd?N=ha4P^\(`T,]l2F$ + K=hJ1;ClJ(:eA_=^cg"'0W`fCI4c:M'.8i667:@:doV[lhj:THLC0)&ikS@jlQeHVVB#?oo<>OT8In''DPh,a"5?WDkh9ud + 7i%fuAUdWRb2n3(,h'jtPu@H944CA.ta:C,N`Yr&oslS_>[f*tcnmpsS*E;sq/o^c,h&`jb + h24`l*Fltu<]iSh^f6$plL;2i8lo%T*:^-8P%`;B2*S9rf?Quq!"9r[bKCUUId(T0(pE`Yu + b[uS+Edl;9a!op.D">$^;/\$urW;ZYe6,R$i*LMH-J*NKR8OK_D3bOlMiq_D,j26UD9\_pV + 4geXU2BT:kPLeU!mCZE=[:Ol22!.XYCWaIC=jH1#-3TrePJ+s%8d4+`uo,1)O:T'JZ.LA.6 + J&,"&M83n20dS#+^=C+DJ>(C'L)s^s`iO]F?Fp9$nbq8/b5-P(BECYV_"B*s5"udBGH=@Kq + aAU7c1e)C!'$6bq'q1b9(B"$tZaBIFc'#(V8sm]\M>%/U,j5gOC*ecH&$JY!usGT#6L"$46 + CO>EC8jT@L(+D1rt^'8J+RrbeiA.7&l2*fDIBGmNKB7ZJDAloq7@fnI$bYU)(%)KN+Qf)H= + )0Q3hJX6)81=Q`=""Z^[r9,#%#$$5>+D!MM9="^K^rd3DHjlS*JWjJPa;HT79(g!A0JZ$)N + rpUlaM2C+&dC^SOJ$%jrdfk2(k.$ka;B5SLQGC<*M?ih"rs:E`$U%ikSS,eL8Yr&JVJ.7"r + SOlM?Xn?@=1h$Kub*7JVAms%&k + T#_f7JY%Z8k(0+(Op60(B7^>3TP&CjJXr_WfR]T,):X5.2DPJY+D3_>F!,*ISq3Df)9.5t8 + /]9qS/0NWDkL_5#&^)Gji2k@BGn1.Rj]/YJXZ=R#&>>nWWm2\AtA@@RReh+D'O:?(bcW#$d + g4`b'dfkS\2fQDb[8Sfh\Z#_O9jq@\:OL\`!?U'LN?J"iBP/;tfEnc"Q@klLdG+6asJP99$ + Y^6L"$Eb'Zs-i.M+VT8OPJ#>g5H+56E!ed)Hrhq;=U9(I=lH0%.+6rCq + YTN0I*jR??6I`IdlY6@.+7#'g\f^7I5.iOAir$V7lj<[.+7(`]`#n>I?H+_DK-\V^m&C!.+ + 7.DSc6)EIIaBoG,>`lskPJ5.[>4WaJ$oUZA`u%3ZZ+bCmFhKr+791/i?.J2ro8AY6^6^o#Q + (*B\juXrJ%E\tY^a8lPIU'D%jCrBTC4N6oH37pJ"F^_H]NaK5)8'GT5jjZL\^iikP0P"#U4 + e\+pL==0Rob#re$"&&0L+,J"]D"Koj.i6\p8BU%/,:UfBKsn + Ks$m1i*=qdf&1sLdJg')R\<\qPuNh;:dB:["XnBQA8,D9gl^WI-OoDr4qX#Bj^2'nek.Oj;s'Gm,I?4 + 't5M,]1?o+4%YZ;7N=D7_CKDgRdp*)`RR/^X%fo*,$2TJr+s'u61OcT3.5M8$rAMb9iZIW@ + +=fD@4KDh:#p2WCNf`,Tk=eCd2$9uTn6tgEXUpRS!e(T'`+66s^Og_:?)T,`oNHq`d!`hP- + B`BCGRBj8ef%XDUEGd'"J!:QE:trU*Db]c:3!TF_8,6(*j]$_pG7NT%;iG_A6-'g=r`R;;B + clH=bIM7Bk8a)dF9U`TQa-Ns8,7XVm[;Tda'@sOJW1c64F`b2raais[WbL:h`M-oBLhln+6 + JjK4BI^:hJ:G`01=NTo56e;bL_'dC$n.I_"aN6aWK[sJ"5-;q;5EDIIG/N^GEGccM7E%0BN + *ra8Gu\'EUGXr:l?Ek!.1n$%WXC#=/VA"HXK#5bn8[O7X(i@)O%;d"2ir,VD=.aT"V;r=6] + 3;%"Oh0SWEG'p%uj5LFjYdD@n68F7F]f`+aBrBJ?DpE/H)K93AR7Z[3a!`Y,:O]"&2.E+S!8 + ,Ar%lB$LqBf.5Jm%9LtN`+#"Cd6Ics&W+$]/NQHL\+XMOnBV<#7To*/XI=cY;gnG + c_qrGbNaR5?7Te=+iqCbHt2]a+E-S'uP"c8j'.k;reglkk5VJcYUc?df^m`#M/)B\ + C=KV + QP#>318,Y6@[,&'sH?;m'aZXN/rh*4?Lu')i7k&"4^lS>[;lYOLE=O1mQ1DrU8,ZVlQ$TYp + LG;oSRtHc16Z`s)QMn,XX,\$a*@>#b/meJQ4h,='&7utN0TSQm(LO,=_o\3O?`<==3EB\ + B4]'3],-.R+8LgMAnf"=o1K!i;kSX&m,=J@V!jlMh2*k#n3?O,IaAu?J'\'#adH-7+8RKWB + ^Hs1k^J_.9_s\Yr@lTspXR`p.o5FK9%9h5<7Kua<41O`9Ud%\Cq@]VlUK^4WV^e9D;/B]SU + [kY>D&pC(9.>)P2g^k=`S8gEiR"W9rN-8XK:SSX_18.n.sdA>21UmG&$SkWqujWe9A%IY\/ + ]pkDJ,+^m534ROc\$Z(?oFF`\ + *#S'+NmR4R@._,g;\WE!9BKkOYUkGeMK^6#Q:2GXPE4cHk]SLIgjD*m,JEUe&Ls+e7%[9O; + R#3Md^IYNBaKk*,]'ALtlRWO*$l4gt^eQN#Nc)qTM"8Fhp?cDumB5b6aR.-.)9uWqkST[SP8%6N9_:@E1W,4cY<$tl1iVFMYLolpoP1&9cB^b,8ngtU5ttql88?s2Bc + NJe&Id)&%8:rVPS:HeHWJ49j%=NBP`QG*=ZUtNG@&5g8H@`W3P@6`qnm\]QKZgTR%VeCLDW`^V]LZkOd^J?FI-==^$k(pJlfTgZQAP$ul1!-9Lp4Z-g? + QbplOL<49G3=9)_TFQN\8?1u5d0@N\'+i8&mdUqY0c#qr?BYe11(OGN%gM + O..`[BDa:g?!M.6#$+VW(_QV+CX\(C]/ + kD!%:lDIO,spMkf2WV4[fqY3NNplCCP9bsF>*hfd+B+LU10rAV63,!.h)\91m:UFjk])/bH + qrY3^.U^eD>o`6@-?%?RDq?#,k8j$K*\ZMkDs"#h"Wm.$+#!4-B,;YiY]a% + '7K<+YXQQE#0[q=!?kmG#BUf;CM[1/9c+gYXaBlE&T#G3dFOcZ-D^o;G,iAHN`n<"Ys,+P$ + 8*q?NoWG"tNO/Xs#.[-9SMR-ZF6ZP'mS`JHumAJ[1*ABIPA!O!ucH.;1dlX.k91TaDF/$jWtKF+Hf;F&X+4Idif>14VCG-n;e)9%hr*m2)C@T1WaVn&OA6N + 7$nQWb"jkcZW-Q#bnZFJ("6Q[;e6_CBblQE(mgd(Lt9M_%]D/e"[g;Vch8#3q9@e&[J3L5h'edeCCfdr1YLF6_CRm+AT9?8MC`F8X^prn7ti?Si-tF:R%:&DM4C?o/m3FD\!1u9_t@OiB#2CdU'917>g72@l@G!/:&5^c[$[.%^=c6EPcDe4$3AZdfoXuRmgAOn^n + 88_!)c;,liF\,VZ8WI-amU[kkKh?NF9!3:E%XPe]PeBo.C!MbJFN&!:a_IuNC@otj.(O,0# + nAl-l`f\MG0*Lfbj;dc:KGu+f%@mch!Qs-:j2"VG3[&O)XkmaDbP'^QMg7b0iGIc;YLOh(C + sH2&sq2catZV1ml_Cc9lcLrEmII$'jG`N_/kRdp$ZHNDedSL8C&r2pTo\N%1.0:%f!5i3Nn + as=(p$cT_``2qQmGNF1$4o6[/.:GUBUu.UN$q]%-8q4Z12AFi`/,brulhD`-%D/V)JnnCYm + _?:qBRD4Me$U9%AeXKASY1)/K#iF#:?gb$VlD9f?9'X01Ah=mL + ]`mFU(a,'2[!IDUTZqp@D/4pJMM0;HElsM-Em%M%d9Rno7$:,37h56='JdfNu;l$3VR/hGAC?bV&GaF)TIb?:U6d + ]X*=tSPB"U>3B]LiF*VcXVq7JElA_'+lWq&,HNt4M0Df(dCO?@CQOjU5\TrT.;jZtq@(D&A + #BQ9Z0k%VXIi4`*<[ciZ7c0+WR^,o!RB^8f8V%Ld[5\slX(.Z_H"G[VJuBKVE/A2[hh.jdS + ktnhg$OHk=._1KB\E9:\cINYRcpumkmQaL'%"BS(MaE]LU,pTfRZdK*MW,s_Kn(V/2rEL#A + s70DH]bPN)oD9BUOem6kX'.M2>'%4':UnociHTW.>E)haX^SBc76eK$]0I1I5^1)HRh^=X'7BEiI4F?a(Y_8Xha4g3YT#0CZoq>6oL,?`W=DOTebj#bhl?f4upjHr'[gm;h]%Dk7'^k>7q!C/RUY)%&pn + (AbUV'^,]U5g>#s!o".*",2]VFO;"OSWNV\Q5:JV`ZNt5 + Z[i3El59_trIW]LS2&Q,MD + H>eF'_),nMcrHbg=HLpfV.]oqFD-k]q?Q0T)=`W6lG7--(=1F_3Ji/?]@ + oVK3_-!5V,7+X;-:"W4\K^a:VCrO]sBT0oeF0D>uQ/[1jeP.]C4=[+kH6f^NEJi]m3VKI5\ + _?F5!0cR\;4k^LD;+`(OuIKY4h6a3]f[*aV;9+8h8rn + >6Do7ZPeGU22km8lh8UJq?5j&p=_-3RBg=[q!.,AdS9nVm(LS1&I9D*U=bT1fM#t:>@@WZm + e2s(V)9NX^Ze,/ES?'"t43KXlJGcsc'PGW,)k;;r[GF\joR1=5AV0a1jE]QPg#36AF(`/KB + Cqm24+2eXo]J719,[Y_>lAB-!P%+hrt5;Ri]&'<%g3H[";!ir&3U.+`1V\&+DqH'Jd,_(5f + =3e":IKsYX#"Q#SVdmTRdq&6=0j#_#_nJC_.He"jWckW$!Dm#_E*@E'Q5k$NpMs!-H:)$4$ + Za&P0,%[9g+?&3o(!8*gi`"F\pqO/O;c#l'!7m;PS&&aKRG5osu8Q.cN6Jik09p`mBM"EqU + %O@NOfeHC!RTT4gQSd=J13HB(/,SA'"EBtQu7g=8Fhh!e[NS#Is:BYON)c0#J&[;ISm%B>O + ,?>*"Ji*4@7[+L["DC(=r(&%n#gIrW+H3fT/"ZrT_&3eR4;!S*Jh^Yl80\TM_LaIhE(0sBI + fs+E(V[s7nd)jZ/te,i,3/+p>JV*%7B-Vs5R8NFJegm#@Y,@,8dJLkKlRH"TS6h\D#Wn]3[1n3&W$(;U%VR!GJdsW;#WNrZH3cGPK5E`& + %>Z.XJdk6ndo2ol63oB?K/*]fTS"P$Jdc<8`.ACG+Mh?VK),a++G/ka/g,c%N.MF.+L6S,# + U$<`TRsHT.\MBf#UuEuQ*c,M-m517$0WM&EM.nu#UU[G=pQE[L`hk4#m_Z6JdBMimXL%K+G + PIR80EP7TRm4N+/"2U#TfXijqNCPBHVDK#:L^7M4fF2#TFn;WX'LcJY"uU#"TkGJd)K'?^% + .6EX3GRJRSm"jp3)/Jd!PF:kAi6+AJE"JLUqVTVtH]KHKD\re@'/H2`Vlkan<%U?K`\J"qe + q5(B@UqF5t1Vts2mV(#SOR%NVorgBDCWW&BZl,ipqmKr0-TW"dbLjuAdqN??-BDS+4WToA< + WiJ6;XKAP$qS%H\-i1m(XK+D1[\)korjSNcM>k&Xl`'lqoF&h8^9B!^!.V4cq[.hWkPGmAZ + $hNKa0I7qrlQ>L\c0gFm+MB`TBuT2d'RX?;Lc(Zqc83SVu'eM[O:rbl*d_+Eo*GUiVq`,mK + rmOTC+ANj1-dHRcpC3Jc=o+m]$3OTC1%dmCTOu_Xa>f+o_)*mn!IAA,Q&9,MmfDRIrchr;7 + )sp-6mes$,QB!5TobJP\B8+6Y,&T[Eaka8-AikY-K"=@S"kar<_.r=9G269ij7s$WX\'9Dc + a%1ubq7HhsFUETVr8,>.dki@5gZ2Ten.R-HQ%3pr+N'G`]s%-`!-BIek'bZC&8uZ)JO7]eD + dcg^(j8CZmoZ%g_.VDI)XZ)=5gcs8Ds%[)&3fiq%*>?SB:T=:YO7`W?e0t>nj8DB,obSbcC + 6)7B9hUQ?/3hY*s&3G+:65'4,o$c^<2uaDWe(/La82n[lF_VI&cSln.^`=Bj^+#@GX'aRs& + ^NE@?:)=5Lqs*=Xu(9XV(Q>#PumklVrA9EW3C:qV.D'F`4Dtb!4K#s'4U_FH?+G5M'`&?0f + ITY>t'(80[mPlgTD-iVpV?.fs+;)2'][rkc_Q%Nk%&J$C0r`@%]%@gm(31'.Bpa87&&m#Z_ + &@K+Ct.k5+h\X=!%@R&P=s(91IS.G=85M>-6B?^F.&8$aFg,hl?D)J5ungm#H_#GWRg&UXY'n[.'(eE3i;YIUS^TWt=R2N1Z?A\sJ!g?:A=^WIGAd*2]GH=lbn + 0n3KDa1\Q]Ue[F3o5/;]5aWJmi/A>$BFoZd@K(j$bSYtoH4WCk8I5sDs$K0 + P%RR*m$XnE;L2b]^U;?heL\`][E9\N5#_`j71e("jVO<,hk8"8te%o + dM+2>`Y%':.iW.6pK3Es&@Ea9hFS8.&A2dPfhX.X+C8QV.?Wlo#=hU=`5nC;#a[NrF\dVGq + ^QZ`0f!tA1cd>\-MliRF='-brMg^k.:%(lc=RZ62nQtEql.?q4"# + ^PSs.lT0ld348,F5Ilumj(aoOc+,mL$dXFIP'rlaM:$_d2^M:#K[7G7JT$tHUcouajIB6*EUadP#?J`74:s'TX^b'@#)f + ,Fg*oget>Z.;5.]t5V1N\f`jNBgaAk$pX7 + \+iJVk7`a@]V\K?#+8E;]iu'j)0qtgO$IVk6r,n&ToW=Ch"^rrNOY-n<8'*bD?VBaU[?e\b + R3V_]ASeV-k'gN?9=epMr5"c,->&b#SU@WKqS6`'s39673G1q>40uO2@^Fj>kKNmt1_fq]g + (fdVRLVRSBu\)?1'o7/C&o.8Se/GpK0 + q_hk#gMQN@E6b9(W]Jug0`MK?LZ8,]@;I2JZC-8e2]Yc1q>: + ZRdc^.#G]c/W%dkR`[eNHP^]kc6+C36e>FgJ/U]t/L&b<;cH5H!7%`\ZR%)r`\HKX>KJ^0- + o=C5P3%9.82].-t`ViMAC&:d3Ts)Ocp]"&kZC<4,s$.@IIj]QCQD[Paga5AHi1WhN"I?CU7 + f^T+.N,Q*GGXt#jZWiQ0"aiZ+"J[UE\2OeHs6F.[^[7FeF*G]RP":2&rgFKpo[lN>)96J%u + ^`GPR8Fq*JH[7WX&Zf^5/<#e%l0pY0's,OKXQfAe39iIrKu'M4T=WRFbD?`sME%saXf;K*a + oo6VrXi/?dJR\sY34X/j.%![C>@,?q>bPH[+_4g:)3Yd-F(8OGRD[_sC%,YJaq>IkNt]0! + r#Z#WOCPfUK5:qR1P`3UJ\;]j64`?g_f4EOB)6=$m-dCcJf]XuD,6RnsC/Bq\O-DSsWK.s1 + W18a>T]jbupFBl.uFYfJ04gBdU_qdcq5,ZjpVrQ^')r\L^A[GWp1jnK#@Ym9ikXM=@7^MB9 + ;sVHPm)J"_`q/W="7M]%n>Ub72/I@lJ=/VqG!B5U)k;.;I!Ir5]t^#3S.p?8]R<#oIPsTD2 + GqRe$in?g!M%X@WtT5+]S3f@_*Dgl^jLs/UkumWMSQ4J5e=Zg;g-7JGR[U_aUAa&)='jF'$ + 36LT(E_uZ1?"Q(X)"=d$N.n[Ytb1&"8j=VVR0/#,S\g4RB3@$sKZpR/1b?QpJCc9I_0M@<(UHH+ + TUq9"$]H`*C0R>h(lorVj5KjI"9H+J;4MsQD`'d#4,_X/l>"d(e8'Ho_V#3fh]>6T\be-5K + 7,6)+m*DNPd)?F@`>W.'.k&'Jc-9J=(Go1;Hrm2hfgV.Z7ASZc$sU&IFA:Orc0Sc]qKU9n4 + X\2-7O7"`1up%njYT;W:2FOfHtTC2BXFPt^6;71]B^A&lmWTD[1mPe.$$RqEPE3.RhTqY1j + $Ju[6IQ\260tPMd;2rq+%L^:V1&M`-jl)AA@d;2J`C%F94ui"%Y`*aA`=6A-O&Z#:k.>[hO + ]Y.*Fl_N'P=@*\<=:jGuRrk.q,;\#XmJ1OY8T'M27=;,`%^F+XseR6d(+;4E>,]82M)S\a* + QdGp2&"-*oAU-^-#;Cdns8HqLdVS[/ITer^bN2a[_(IG.g\[.gKgR]"Q0$=)Fb6fLf*&5Vf + 189FXYFRI1Ho=$J/k^jW99hHIe2k2*3(qIXbM>9B/3c3^6;/(Z9I2s9KL9MA\[b\]d1g + di/Z8PGpP9X7Vk`(WkS9dPHf1*afOK[DoMBgj;r75WL@<7OE:ejX%^7<:+^>LQ$1eA\NDZW + l$EN8?^m4&,od:).*Klsd[0ONpO1csokdJFDGM + c_cTQ6n8[M8sS\J_0[EJ>H>l%N[s/N?72A/?=91'ULd/crhR?\5S.(]8/%]Q7\#P\AY%" + g>5u,hmiiOb"Iq$eKnA[-95Wb=q)l'ALT7M/(1bp6J\Kdh58WdTi1ig;[OmN)YlEuVb:NuY + O/Ks"04K,]"6o*gFELj$aNFsZ`q]_YiE/RI)ER['AKQ&41i1"K>-*r8)*E%]H'T!'hYf12'ZT0"hqHc(!3=7F+]Q>!8*V4fO1l.m1MghG,TYZmF;145r + Fdk<;o!em7"\CZnfHleUB2cJ<6C"`)EfCmr%SWH7U\qc?!EoiEF4=#4&^7/5A2][pVg2>^f + Pbl&GJr]fInf`W<=;o?$o_H$=H*e3>n8JS&Q'3h + _)75"4c[o_JAG`I8VN;SKp'iIL-_kqaj$*uc'Hc3Mo#"E8emcB'q3PqO[;-mY!nna>UN\OQ + bo"9g*J3%1Rm)e/6Ypmg1'Wj"fOI51/epfdj;'+Cc+8,[p%lO>4jg8`&YEa]A"VmgGM()*' + QG@^ftA7>BN1mF@*Tu`7q+UgU0G]bXXbT);F0j7'46e1ecE,_UQQB]QM0BmDYq#`j17rgl' + HH>uTOd<8>C>7>oX>X4>aZgdT4D>nl1+`Ecb,?9R(P^%C@@ARXD;@_O[25"eFPUIiIrgch3 + %:Oc4*a*ptB0$6)S + 0HY#$g2sJB8rNDCa_;qlJWGXY1=6>9(?QlYV/1k;Zc^PN3q= + Ke"i]gm/6/.,?Bd-&VCdqXK.-Y=nBm%2',YPd3+CaEX1+k68;^Ubie$>:3eLN4]>hE<,2sO + (@C1UP]KO$a4W$d$V`XUF-m]7f85Xnc+A1"Nk5-\D*kf0a\7`F4Rg6(4iChn1PjLoIhA+I$ + V\n(3j:NKaTF'WS3l")YYAOQIXa^u:_=EAXN + gNW#'qds+F\%E>4f$@rfs0r75d:NEqL=4a5DGd9L;8.!$L=Tu`*p5C'B0tKmQ?H.aG=l1d8 + oj(WSL-5VI?;X@C.t2IBVjo3,"jCkc4pU[Z&\\NR + R$MYhne^%7+\K6Kp!7mhV/;?Bra#QHZBLBn]/tAt!2r9g!f"4I5eQ*hM/>bsb:Nn&D']A's + =Zs>:=p8caSXL'njlKr*Hr9.o)l*RV!c7ouu:deB[g]D,,5$dVk\sn#o + o"QWm1%r7+iCJ0nn--K^F3]BrplZ-Gg2=ID38Z^Cu@+'i'eRB<#k:2QZF17;>lo"L + 32@KOPmMki5,rpFe82ZgtDtgb,4%DVVh!Y/+^ufmMLI=dm+07AdJZkVBC_?,$G8;LVXUb7% + =i8"A$NTM$P:h#`aK]@#2oE&JkR=5nPe=7'[)RJg$eC=<\@`K:B[g:db^(!S-K04@'JH6a]etFb1VVLH$I"#][&a%M2!T&D[IIg)u-k+g))cJf8M\6UVL3">`= + PYX9`-#\/H'TS=:,K*qf8_$eUVlk$]1/`\%.W$,aY=Fq:Z0LE,XWrsn<$?/=tOpFp:'Hi)( + +Zim2-G^"M6g&FWcD?#[a6Ynd + &RYBH_VP(MFt6JeogYEIT*b\d2L_KrPD^@-AbGJegm#@Y,@4Jd>GNKlRH"TS6h\X%a8l;a6kDT03<)93r<H4=Cd6=c5Y"B8+!^uF5LLDK8AkBO&+l)NdUZ0Ga[%@% + @K)N^qH+j(C%%n:_&(Pb@SDFQ1Cs-)5LWSF9o6D?-UIa%a80s$l/7&hU&LYhqL4JT!C8,&& + 3nZ(s%u/^7M#/35Lb5`;Gnr9.:k32#Pso3l?IfY!WK$QqP54uRSBf9<3$aas&J+X=V(1=5L + m"<T=iVpIpqXP`odVZ1!n@k7L!$CP)J$:*q_$BiA+7(1oYbi8TR#q>W,Q3K1p+/G\_#In + 3rJj[n4NJBR-6MT=J$OY)b(ojF+7-LeZO.VpRA2ZQ6iEO9p38gTnGd/)$)073&jjZR&S\$< + M3%3W5KLH7C+WGd[?e8Q>3RCVjJ79g[`6sh1MCW"Z*uXNG!F+4s!R3]\[QbQhV7@GDrj*2P + nF!pgae%t%OoCWk9/gn)#l.^r3NqH.ct!jSTF4H\rZFM5Kh.J05d3+\sHI`?$ib0,Q,NAo, + 9j;Ha\+#jk[Q#IdbMEs"i^5d#[cfnX_8QH#GS']^oSsc'\MhY>sjNLU?dsoAG!$'RuWmrc2 + @%jaAeap:g:\r(b?54(J3V^N]&DTB#p$&./FZdJeL5q=0"I*X0@3*s>u.ru^G-J"SOqJRHD + 4K5buE_AGUma8-MmkZiV2Qr+1K>V1[!`YbFirea5B.j*u`*(+sp%q5B%La_V>UXB(%a8/)Y + &KW7:fUijeMGG>Y7";$mY8*e]>R7T\0I@(DR8Z.^NC3Y&O7_9ndu84)dE4L?B^m.=dX`M*% + "G3Y!?^ABKokjP7EDkd5Ld4C;_gg58P(K\,h/?JMPPa%Z2Ue8'VUbsSlEkC>:W_;s&\7Z@* + :QA/Z$CsQ]glOO7f53esQJ@ZOUD;Bot0JAB\:grGmtlc9KoSe!a3=Ce^n>2]'"(?R,MtO7i + B0k7m'L'<64N`YLekB`DN4b';68mlkC>rL^0=J$K[caQOWGT[Y0>:s'eGR@+"dU]$\08gd' + kbo:=a+G;R`OOBS-9Vf%ePdNEI9*k>:,cu<@djf'+Rj2IA,g;^@QJOjjrB[B!e[j7>N`&Jb + J04G>VcfYTNP`]%;9!mG5I'1 + ?NH3&,QH:ln+!;miKFdZX38/rK"6B:$XrX/8n8Y_gE^.c<9Huq;4?13[[Ve^ENVlD-a8n&) + u4_;pK^I)#q%qinZke'5p[grIRE9iET$8EZiRD\S*i+_BJr$/sXqtd&%N5PX:48OT2rEK(3 + /jbTb=QE2 + (.uiRPs-E6D?d(<(C1]oo]k6L.brMsck5!+Z1QquN1UMYpI.NrmS + Fb(N?&Z&Ar'0g#L=$\JJnVSnb?9f8+8SK!kuoT+FMg=V1j;^C#*VTc'2PG67oPQ+;V&6]0l + .QSZ"kOnXW(TTVp35T2a)IaFo-R=2(cXDpBe,4cH:.=19cub/u!A2 + $.NP_hgA?NsdY>?M#7sNjJ!-h-BG`*.9DHttonXqEb_(4FI + H[0Pp'L[=#Q`o>&m&9@=l + nXX'3fi^a;/Y.&(XQBeW7YGB#:G8bgpCSeu`igC4L1 + oM&ku2DbYc7:["dU#-'EIfd@QgD4:L)ZuV&;+>'O5NNE2\b]IULFKN20/\p.<*3P'/Y6Sgu + ,:_MdgB-[DG\[_4XlqVom,&@>Z3R84P"=Kn[brbC"Y2W]MaJen'RbuYiQu,C8*[M1CuVAhi + pJT-CMn[GG:2fDJ^-[iCPIGANe6[u6#Kfdd$VBm9"Lrrk+k3'mW/`9^4r].L@0R]DM758]Y + 18$^*o$+A<,oWT+(&ZMQ?b/DQJc#h$rSfN2Y$]0^-?og;6bWm"jrncI!0(2NQ'H0J;4DcJn + 83%)iMo`KM#)8M9Ilr=SC2PRMUgD[Ma?%e28-a@Tj^dl?n)Eq3'maiT(U8VH\([e#PC'eHk + `%)A<-8mUm\oeC"%8\iTm`:aB>p.oB=D"+#)q)@bcT+?8BnVGPl!mrfcprX6F&!\$7,be!b + 3\R5&:T#,.MYbR_UeO>uND(R8]c7R!*(I[_O3&Bfb\ZapVi>NE1#1B4LAheGr__lu1$nnen + G`_+s%9BGNLq=&Ub-Nh+HQkN1(OBU'*0j(F]'-\-Y">3+X0`/,)::bb5QW@1BTBk"*-GJ;E + h@`UEiZ),`kQD0MJf*"Q6Rfi<,PQdU<=mA:AQ5#*Ng-a7ffHB&a@[-dFh:RE=Xo?>L2sI)o!8]Z[YL$W]h!o0&A]no`@Qh5/BdO?EmkIQf*uE + &%C4j%0];89jQibr0$ru=&Fb^!oYU%Am8F#PV%XD=#nW:/Og>W3',;*N.hR_Ln#laI:BjiS + .5K:&1C7DE;)L.l30s(sa_?/[;+3=(8MnPM2%6dYdoR9*>8=JNRe("4l+K!;Bf=@U2[Reh9 + ^81tHPa#<([:<(/HY[mK/i=UAFYjDEL/\c+Z](b3\dA(&Z4#l3n)K\e0^_*Dmp[h\n]R*V< + q=6dE:#a?Ms?Ar@ul@&_d2ghYlU+r[O)`/VtP9N[jMh+)glqV^3GRru`usF&3(BF9pVt&DN + rZ+cmQbe/I,H,2E>K,-WRAoISi11u;_<,LAS!'L(Dn7Q3"o,k+SU-cIBN=!b(SI8F7Wc5P[ + TC>ra@#4cg?13S22HO$j+#O!$2.tL5$9aK$B5r+]3;OL*/@gVR:6aETsEiVf-Gmb+27P_L^ + P.aM+NsmY*8@$DIZHl4)V%#hr%?fOAFP/9!\Ls-+lk&S[Yk'MepFiK@0C\uq0`mH!#/lP_m + ^!Pp"Zm<;)\KCtPLC`h1FEfL9bOOTnIHElD]Dla4#?Ck;f=6%D_bNQ:DED!<0'B]O%r1MHD1u9%m9Slc?7MuTQ0R'7!C.Cm5ZRU + 6&.I<6'jrj5@!!7@E$!f_-XehZ@<=!TcnO<33FXg*@WX`i0LFZT.q:(a"Vs/Wcrie\77FXU + iRU^m<`"9(<45VGA^3:@e9PYJI:fWR#`_\0(3N1!GtAKQ$*Ihh2MF`rM+TCC$I3uKmP*lkN=;K!EdG7@Ie&Q;IS'JD*r[iJF,+]NAE'i.7Uf.C!(0ia97(2m + D8pH;Q$5ut1)(QWO][nP-\LNQCH)"iT*ondiFQ$.;6G,d-;m54[+G15obGOr>@F2"Ks_`Vd + Br3a:&'uN1/D`sB14iZkQ$BY7.kh**-?5)p:;tenNqd/mnEte\W9s!))&DN)s?qTA4/]f1g + cEDC*YKb_Unhf2r'4OTOhX0t]D>RfW8Rk^ni,hh+oMg5Q=L>;B7LgXI[SoZ(=%;U67lFdGB + GF%36Hhk%h58CUWC9G:O/N][iC^/r&T<_W`T8C2<8%cD)sdWG=?>CN + S.n;WSC3_hbBACof3!QI>/?!Dg/[:\N`7G3)Pdk`U,U`Xs50:BM50*H1ToE%_lDFXqF1CN/ + X)nkUbmD_T>C*m5'ToFk@!Cr^S_bk2KJ2QpB22a5NJB(j]$pGY`HG>D;DIolAI==O\\D&X@ + XNqorRG1E")'qD<m*o?UlVn4\N+n[4ZlGBr,#i>(RH.7H[4)oW4?%PC6b(Wgo=G`+,[7K + Zi$m"G9Ft"\oQ7=hc:6:RkH\[ + J1gk95/uWFLR[o.!BI!=?(q9lNq`_T/]Aq=nrDjNM%+jLKXoj[[j)dBSfn-%+_PSfQj2NI; + >9#C\WYpY/@"oOe[*Hm4eJ*N'W=7$H0HPDJWOR1E=D<=](-#Mt8RApr.32O/EXWEE[XIM2S + ;%;0#iqNesg8d:76$Q&gdFWNgSf>,.1JWK>_0p^rDYD&'+8R*kcFG)\/3uf_YPSLg5R7V[h`n(aRf6[+9=^+(,LAn<7YSh)#Fm.N)r7X4AHoZH*q0bN]JH8so + @$fP4fA/bPi30aAIZuL7e2;^`(UI3=6l5eI\,dl`21TdI[$VAo'OKbfB&[#pSCeurXu-HE4 + 15tXSaK">1khN?Ogat1KJ\sIFIRra[C=de8pFE0fNPs-M2!jtL311bX6mH"F%j)f/XUk"P2 + Ei-heW]=\sC?r3]/RL0r),M]=L@e2$33.%ds57MY^=k0)lOp"hcs*N"mW.;)7[Rhi-90np5 + LY\pG.'m;b2H<4M*k)!]>Wqikk8a?a>[$U8(!FQniNI=aYIn4+]ON$F"($N3 + #CMaDI+/aV$K&,DLLAUT@2gMA3L&@1R6qj_".M)US>0QC7@MCQb1'4o=::VR\$X^ZbPB82g + r6[cEQm&aS\3F[=>NK-2b9;s\XRTaTs + W(Jq8cY$"2=>YD6Kf>T\BQ$c`5pi62?QCHRE6lQ!r/u@N.%O3MPCKVaNPFHMjgRI'9n84g]68['X,Gr4PQ^_']%\A + XcoJ[U78LJ[RCbjgK(uG&t+E4eBr)T+mWa:ntM.MpF;B9"'qn=C%S[L`c]e"8j/A#/J':0O + -(3$A!e:@#,X@-NaH9^p#L<$jRc'J=p9e)&.u.P=ajKJHPlL"+J&CO>kt;#5Wnb?uLi?hKK + 'K5i/_(U^cJhGu:5Q(`U5&r#2Oj>0(:dS%CH:S^tTDY^'Y(qJ[Jm&8/k>@")1$S0K+RnT9Oo5TPW7"1'YpQZEs$Y + 9F[*dA&-aNL`7*6`.>/NCa^5-B*2O,fC1Zi%=>a=Y97Vj)X7O;JZ_!%27sB8"'WLkSHp.Z# + -rf]?u$7r%:93=5h3(rA.;W$JZ>AXQl;\'VtRpUco!?`8HVi*e6e"ML'F<%PNWlI!2*lf## + 6:Og'17oABYmAP6`$YJWe(l.ghq[U'=2^A5bMWh#!^2M)#SrGW#5;\O(]C'.%k(m#!=#<\ct5h8/UWCNeeP + 7JW<8(rCi_'Nt\o + TORHr/tc\5"te9E(pnjP-lB1>MY-`L.j/<$"tCa)RKb3@8/S(PM?k&jJVhpG"t$!P@Kn-O@ + T@Z(M's4&JV`M,N02cUpkXKWBGcDRLc0P`+3oWo"V5O/rJ#4UiB,_UU5J7dI@0,,Q/dHoSPl]4A&0o + /LI:cVE`Ljs%9'b/!'>.5LS=j9s"$o*`jlm4j]oEcF!\nWQU1UVSGSn":6F!dLK*Pt0`Nj0r5 + C`&?L6LK[s'IcbRa;%5Kr'c1X?*Z]Jk`p`B=mI'9+5^6>K[cER=1&&%^%-g:N$_tnjQTRWQ,rd,ais+#&("2L9?!mfg)5K!F"5o:a + K+LDu<:i[$h!WIb-q@nTZL(_@J;[VJe+s6$1J"gBNMBS3=L9TMS_mjlLL\`tPkidMkaFt17 + /4YOO/g[&k_Ld!qs,iuB;>G + )m7#5"ER#5L_su;,R`daB9#tA6b+VWb?m]_>^@.SpK;jO7h6ak*4Gd'5D + DZ`V)OJkl5#]MK$jDcT5]Dm@C=@J$BUb`93Z]T$u\I:W`Q"R2Gs7U]$D'8d@ZG9adZ%5)6I + arm"%24/0)[N&3"Dd2Fkb+s^0dO8;L@kt>#k['5[U>$ag8Md`K)e[&2#F&(J*D5Y>YU(i@O + 5O'OaW=A[<<3iT+$KHsbogYq2=!$De_.kQU_9EMe]iZcuTQCp5^DI%YlGrj=XgPjp],Ka@N + 3g);p"m@5])(o&%=g:TWT=Zf$XrBrMg@$G`uCe$p4rU1ZF4)`^)+\"%WTpF6iPHd4%fDmKr + @*=M"dH8:jh/3lo*j-;R?;g!RCYWS:2A+\NcF4d% + `2=amN;8Z4D1YX4YuCCA#tE7O8T.julCCmI.?e8=R_?)WVUqpW#.AE@FYT!s2>E4pOK]o$qqRl[I"4K"D!(sC + b`gYXh#J@%(_^+#A^3efgk8#VVCW2&P^)N:WKNg_auLjMn(qs:::W@:eb2)23j6gtC<HoKOf/>;L5_=+l>ju=<3_.q@>C + =>bDL**IO3.r5&H2fIdSiF:`36R;tqVE?@i(>M^+M3ds1aF\G&2%ds3GK6gHmgVI(Ttmt\[ + `M:bFQMmnY,gNU'mY-';@NE0e\D3YGs"^Be)5kW5Dg=UAFtd$`k"?XZGN(0PWPNN4h:k41d + #L_s7aW!tS'E[j4>N4-W)e3_6M\`]M=:]A('g-saXVi*^`$f.`(hS&hr1a7K- + 7--TfKg%lc7VbPnRnCtqkf0Al#]+<@]PSR?DEcio53].4r,Kb%nMOhI20#un;tNRioc&PW. + LTK=gj1jIWB[2+5I>hY<.7']Im;o65OtqbF(iWNC(&Mn85o^_@Fdtk#"XCP*M`rkWSPY&$: + r)C8C?Efik_3kO21+D_#0=dUlqg9mE%a08Q6Bq@Id!1c_"I0_0hZeM>=uVe[Ts_8_],`KH8 + 24*m+foarDPH/0U[f,-EGZ\O<=*=U[W5W5dO?`E_$6CtPVtf + s<_X9se(u`*4TG>Vhl&]sQ]\ac".Ai^OXB-j8U#2!%1nKLSm0^.[T`PNSA3Bf*bCW;Q"]'2 + LIoDRCUJ^@ZBj*:b$OF$D5J[>X[6oC^.Np;`$&a.)kEX8/7nqPnUF[PWHA8@(PIJA;#5SD8 + _3*.u$UdD.fM2Tou/HZ+jb#KWD@d$o*lX*"jcNPNbud,TC:o6QD'P!KeG;(I+34+If?QGHg + md;st,JF5^fRmEj?+68tY`1B9C!^Yi$37Eo1,ENH^,"b6J8l?0lA0jii-6Y2n/sRfpS12"R + (.ue$b2"U/oI`02+A3D&9-l:'9JX1f.SF#'bAB*tUc1?F1eXW)9=6dkr&^+l4Nm(SbPFFs$ + pVrU5bp5&YoC3bUrBsV;++[0`,*Mk"NeT@b/B`J7&qBYUW#XM`l-rb1/l:WXO=c!.a:Xcc! + =72$s#M7Gg2IT9r1q)A6P??>Ktr.c0BMtr*IYW?`1PEZif2L%-5,GQ,ZM[`a%]*N9J9/l,J + RQ^6;7)UhcDmCoJEB2&#CY]^XLsD+?*Wa$jpe>?TPlpK&X829bkt9_o_+q^QCYcdQC=h0I? + FHI*%4clIO2.F?F&ZbT9=[d44N,m[U1#raCA[mZ2-AIR46%C_!#2k6"4V%Hh;&i\SY\+Gs< + jV?G@(:Z1;3(hZQ,1Su]PW50QdFFQ1jd3L5R*lG3TUhOS,U;!cPep]Pg%?]G".6r`RS(8fd + ]K:m]:M@gGN\9hc$leEb:H)pFW8a"kQX]`cqM)_p + -S1He+Uc+DS4j]Yp^>od2uX^3g]@FbP>7Qo>R/_AQ8j]5+021En@J%!mX + cu"?)Q%H'3EORc_[n=EfC;DiMGf^&6/8^9GK7(/hPdgM6f]pdB,D4+%KioE6fe",PKcA]F* + 2"#eXh5`Qqi=&YRSkH$;DXM77@hk)&lN3&\U0`:X.$3QUFuG73UEq1!qf`;p:;cM908uR`N + (ZHW&gHY3jSolo)uYZY=m'CgEesd2*F#a5$M;W,UG]1'LL:o]#7=Se4mR)>JAU(^/TDWgq_E;;?Rt]_kbm'\HZm4]GRtCH(&73CVKF]t@]Ph:#Bke33c + \?1UlVdo#2ViT0'>jRdMmUKCi';I46>=#4,HK3kQX + lGq&FhSj`>^04&?Y%>9J.jaaW>.!0MJLcahaJFQ%4ntTaAO+e%Ap+$CQ>")TN+T3mT,)6/A + WUNd"Qo[effP#+]8A2;F34R>k>dp&%LgKPj'^soY',.aQ([7%Mp<9JjU!GkX + HL8VM2ofXQY*T,:877SZq=d,A>@J>=5bbo`Lf/)J\<.=PV1aC0j'gD9tGI?9Q1iA/sU9%RXN+7-`Rj1j6'';bLY + eZ,X5XW=DSe9^_4ODrf\nCOG^(m.=itojo+djXbX+(0")$^1CmA:Wm4^b@GE(mU`MI[Y+Z> + T#>3ro$C5:?dd!]jo819!)ZJl/FLnn2&G1=RUB*aX + _%db`n"OXFA_Xi63E;9Q?Q`eS2i\W\Q7Ko#(*n8I+"%'_QMeM7MX@s(=M=]Y@cg'SM=QT1? + #hCDIspXQWgEcDF=r3bj(Jn33i4-""@h@_NogjArE + hMrhs"kA[#t5+`3$5"eZ.%:02+h@c.Dqs\BTDfI(B:M&Z;rtNe>]k(4/EH])uIi2SD=n/Z3 + :_t,5c11>d`E3?f?VY$M*lq]2$=AJphibeA[jG4:&(mJu?f#KUenS&GCI(_Bf`*O+%2e6ue + FNPWD,po)2_o5mQub`?@)k.lV'GS\%qi(+D:Ta8:DVZ#d43k\9MeW)bi-Xkg1@dk\kE&?Nm7:1"8Al]F + T:1"63LBr'og%MN4E2RMQL9jpE:Y)?1^>CeY'!?Q[X-+NTS`fKXsi9ab'0b$U`O[shr9p1M2Gc.Kc[fZb+4h + U#XOCq)*7d=uP2O"XWp0PsOKm9H7MD'&(o1XZLbau7r+^=r1$STBI^mEI#(NM078U2BT<#Q + c7Os$T-1YOjpd%0Jr4d#^((63`$mTO;F=)?)Do5=!Q!1ZSu="$K3uB:'Rr#'YWhV6DbW%-[ + jS^s5b4N8b%\JXbS0kS^g]"#`EhE&1H%dn51[+D,j9RKd>SR4>Es*"9dg0YkmIkS\gR?@eG + NA]Pa,dfV0eb:k]i%'O]&Q(V\j),^Z;JX!@B15lX8""1n+fOu-\##'T2i+/p:%$Lc=5fiFM + 1^o;2JWV'c3#N&-6.*Kh&2F(kI01P+a-u3/mKP_'NaQ@V]F8]\)aMEI0r,4j_L[Z=@i-'"" + u#)R`R$>U$sJcTEY8S)+D8h$Hm!(7Q@YXK)TdW.#%A]e)?sUmAdsKGQj=RYJX=FqHY+C3iW`\]A^UcfTOl*FJX5L;Ck7nN)/ + 4%4AXWg++D$E7=C!kPAG5VC24P + J#9.?DL\QGEd"%Pl5BSp+6kE+6puIXe4nCribjm$HBBQlWO4p+ + 7!Y?\"DuCrjhX$Wp[O'C\dtE+7'=5_4U'CrknE19,>OQ-i5$9Z=j%aJ$S8714QWYo/b4)/L + g\I+72)fe=Z,2rmm_/J"G<$D6%],[g2eRJ%)?QIXejTqhOZ#Xuhg/TC-.ekF_1!rop'CYMS + TW0&*u,TC2g[nXo8!rpucFV>m-ng3_/&ocNADJ"L`[IRj52+6W>&TC`28cmf>DkTGAJZ2TA + Gq@=\37Lu1L.YZ6l*?XKaJ"cE3Le%:d+6]",U3':jdjUfc?j8rf>+r + 5p,>$,G\;!P#>un8V?shO7]/2d[:&,U\u^^KX-ollEAGu.[A`$=6g$!O7e;nei<\4,Q227op[S"HI5o3jJJ@Y+bj,8,DZrlbn:V1&ejug@nr)m=12ir'/g>s'T@8JrfU + 85M/Zr@;IfVYqc6rL\hf.ls,%FOoEA@q]2<1I?:`m:-[Dcs(*GRQ&kWB5M:GnAh;2qZZ^LV + g!Kb3U]$gGp4>TO4%3iM-)J!"RRIJW(*DUGWO4(Sef*"BCX%*g&+W[aa^\jtD4S&B[bBKjG + s!20pj\M4lJ3DsH>ef=^D,Z+>0D240'1g6+6uIIX[2roVA-k6ZQmhEVKC@o + [T[WE$*cO/"9+ol$A@6)[7)MJ0u&eGPuB/T:iO\uWKk?9j2_+#X&X2D3G0pG97_2+j8QAcM + UboO1T%;:&B$X"s'7._G]p7@]pW@aB-%'QYVm!.]P!45%8j2b%n(p"lQKf1]@X?cpu!,^`' + AnCrg^&HHq#);u,!YK9`OPXh$pff=K92 + <@+887hh-7&i+[t*Q8=CBVqnIAo*&iWHR2TD1I=!.Ym_08Wq-Qe^'B4H98kDl27A9a2n.#P + Z&VC04AC-ej=T?4)3s\=nj+Pn0Hr(FEJ)QnVLL_*N`!SLq.7kFBnMVf7;GKgCeO6C4i;^f! + di2eR7k!o][T?A2J)h#lOYSc"Q?acf/EqCDnodjP=]/\P4Kc/['[.ZpF"_,3V)5Lsn6ScAD + NF_ERe(@US9_r&0P2%]L]2JC)jS%mak]MIha`LCa>*Ui`2nU9muq1^ + uB6FR)KHqM(-?$;T*Y3?H^&DcP6j_bD'kZ6ic&[VKW(go:a(f;0Enll)&FC28I%5Mp"]]pD + aSNE^F<^An_AF)A"[Va@L57]im-gZMVm.ctn(mWNHo16'e-NS(H?KWp5fhIBC=VjcK.)L?0 + CHEI*(NW=FO"LCV>ZcC;K,G="5)RRQI[7BMict_R&-CT)oeYmLtWKs#C,aC`(UC?OYgkUqNY7!QDDMS8G>M/2C5Y*qrmSr1gf^Wf^VeaRM1Z$#oH/R[;6mQjg#0O#EC:3m26-bNY\lL"u=BZLnXQS*\dt04&$^@\$ + ;,cDfaJ.HL4m/GG"ppWWi6/I\:jMIfSDq(3S\%4%ZB/K,.oUJIb#O/eub5l3$'C+<.$NDOC + B<7R&JVFJM$dE:$PeCLa>rG$e!C53hSHuEkPrb@a<8tL!]O=O%ifoPp/-R>aj.,&.cg9%OY + Wm5]YeoZna0MT@<:`QX9A?Ra4h'[=#D;,-X"F+\k,>IBID=$-k5dBLNZ>rFlkIBGcV;I + &fOZNYHoE)$VTfIZ%59] + i-9k3d9tX2'IJaX[jOLQK%SW.]t_N/8+a^1`nJo#g4H")4YRB&ORD,rE=BeM+N8C7mn#5%OW;AT5/uhRn:bQFcOgfVJsG\[Q7j: + ^%jLRa5fr8>b%ZJ!7C_rM4V]NZRI%gKO%Pl0:A$>Pbt5^qdq\R_d.U7L(MrN2/GD*LG+UF6 + p[O'dM?M]KDDBfBZ/#&e+j3&HOX$FYXf:7q + !S1+X/TcG7Z1+c.LkC1>YAm"-P_JdQVtT6Ng:W"GaAfb:qjL$RK[%3RD%Xn6g]CAHm0h#-r + &pEcAI#"Xe87-a8"HkSGWtJq?mW#dTEqnrSKEPe$!H.Bo?ln=_<[="8!sL/P,\o!&QNFUN6 + "[a;\NYe]JdPq6mr/?m?U:sct;U?[oqlK#no'&sI"k)GPi%aseV#jDjn/F;fT0CIOk;$AXn + #r&>!0_#`00bfeu(rckD1%?DB0dSSh9eretQ*W1Y1Gohe30r#Uabb@$0h!p=8MmE+2!hT;Z + W.`]=V[p:($s0;%p(ZM>[S.^2\C*i8`)IhHT0?$T(.EZ%t+..N;/-)))INqC*,I@SN6563[ + ujFC,m30NB6>ke."neD+l18]c6FV*%&KADoj!&b\[m;Vep8%1"t62M#J"Gr_qt3O6kNYYob + Xl+*751n,D$-fcX)r+I!5f:_;BV!?lD"+g`6EYTbi!-R+X&,0,<\&2PP-2L-u;Z#/pd;FKE + ;FTf!E"S,B:E`E9`=Tt_T"m\fMmNDdp-9P1E#82)J%Q=Wq4?h2E#Vq*)/klVs;F+3E#u[*] + :1FUuBLC4E$?E+uTh + ::[$H9mp6\!?;pRNYPQrc!FHNE?W7@`a7##6Bi[SoZ(=%;U6#AuOLemh5$B1NM(#`_\/p2`duG + =aDo$*Ihh(5#3pLItQYDPr/.:>!1r5;G?:epBi2X=35mnk_9&aofW.%o[Bq'JD + *rQQ&n*+&n:c'i.6A=";G!@rj;+(:@XneRrt7Blm?pFG]=*bl8N(<;9=O=BAj3QX]bfRea: + `G1E")'qEa>G8g4'e5*I$W`<71>5U7feaL[De\aNb`n'h+4giRQp!Tf+JCnl,fZL$s.]V0= + SKH+NX;1<-D62JI%blls?n10k/]f1GcX?Am@5KIiZnGk;13iFLYu!YPmIpa,0gq36Hfk%h;:9=X-pG:N$/Bb + [gd<4(kP^C3#oLYk`,gf+8YnD:JT'%d._0$#Y + SKDTlGUNrLjF"NOR@a0-!C;_mmEO`8O1nkUbm:GBrC*6TuroFk9tG:?Nn/QIj1@ + ERLbOSQsk^#;;F*$"'*OI0WQ8E#W2QO+%t3IT@6?cnO<,&"6BYZ + 'hY%b:.rS:9unb74U`q11=_(bCQS_SIfjR\_2S5':nWHB"@)WW&($lQY3l%KW%hAYc2u/kd"9QGgXD3A52%U\+8tpn9C#8W%]R`L9j_[e$ + ?j\s/Xp'%[5_fZKMKEte9]VmtHJRXl1i,H.!qW;,h&%ojB`>0Zo92_=3n=%:N($TLi_OVND + o3k[OtAZT#[U>!d/R4b92doq#WGUBJTn\D!s76I%'Ph2sX77h_q8_?_KH[UTIWJ-MAL!.pqRu + 9qjT"[:KC.P%lZI6M!+\c19U6pX0%_W@T_n,W*UUJP:0`:=-];0\H:bLuDmdIf5YGI9VV:? + H\&LY7n!K:#-N0Q&Tba#n%ePj!2<#FE6)t/ee9obEANmhC[q"%M`"-:$eL>LX][SEGrltX4'PrSXu3hoEQtYme#rUC4e,@iqY+9> + X$2lR552@_Rg$fSlTb(2Yh-j\Xfn)`&"#$cZ*jnY2@Di3P-:C86JF)@fqZZ92.E)JReQj)> + LD@=n=5jE]iXH0GVSDeGU!B@NDa)gR,4r9$*A9" + G.\*;>1-rJ#+HL:"pSr<^#_%8@e6U0)uoH`([#+,JW0dTa%R4YaDqK2:SGuNFF'YEaQ*H,su;5h^\f9KRTq"LcDK>;[ufXe&DSWU` + GIG(#'X1b.Aq&``7,?\.rdl]-Af6LOo6X#\a>22-?gc[c'jcl*s`-UfUS54GK>K'eAhA+d/ + e_dSI[?f(*QP9=a:]mrppW$;25o'F)QdqI_`L,-uR0RTM[M?m\.q-%C,C;46]/Rj]6-9g3Z + h?>b4KDuIY9geR7G^+:e7E21WmJN9Au=f_qO!cc#G:aZYX_*EQ1i(`DKFp-Tr^mf9ie-WG_Cd=H^8/#/0eU]S + #9fhVIV#k>GRLgfoRKUoe1LNnt'.sF1\A4Ld-:A0$!b5Q09NVr@"N,dETM-=V$%W.b^mECo + mQ(K`JM,kRW"S4q\BMaSn0PFJCB@[QTM%6Waonu#/2_AmHjO'[MN?JI[JIk(+"5&E=_&6\5G"TL3`&2TQ.8fRXKF&Cc7?1.h[++@A0 + m1E]%7">WT*&B9808.`Xh$khh.0;(Z&">6?6iWLjX#S=@o$RcRjJI;"+"=kT]WWXdo6CJ$+ + :P]RVJI2YoSq.3t.Kh)k6=L'DTL)WuJI*_9OF[]$&<)/G[)rLq+@6tL+Ws)\7"GUL&:T08a + :NZK#F0$,*M>^H"<=(#`GC)0kR_Q]#,i)HJHg9)";r=JM?Fb=6%+uK"iq6YJH^i@=)"U8Ri?J"o&^2NFQs)?,a?kpcUqTBSrH + Q(R;Y`0[>MRVmVPa80h+Ve>jPJ#DK+K=Rpq.ZU?tl;@PXTB^_$W1W@Cri5IF]!AH=kPDi@X + =*kaJ#oREccN:>>2$HgBDU\=Y,D-aJ$16rpX-1FqZ=UVQ#"Fm( + !rdeIW#=0ai#,)Y.KEq>e+6Z[RTlL'd@4E3`W-o5O;>uCWqBmBKUjo,Drek3b01IA7)P`Go + NX,DB+6`?HU[e>F@Oa`9W?!:GoTVSgB`CZar@!a!VE`M1<_DUf/Z&":Q\YEG+6e`6VG[>\a + 80M/l)ck@o]ABeOT/(NrB$)4nitUUs%foY5H#;$Tu["a+6k,$W3Q>s8,A:.l:":D+6pdoX"jUU8,B]ZlK)3#QtO7fqGf'*-fGOWrU]#hjV@pbuCCqZT5_$$nrl%D)(E`!SJ$HQXa&r3^A>B*d&,&a_fgu-SA,V_? + VI%JLRlI,Nfpsq8rm-As5TjnLKFdVf5KI>)B[&!'2!1I\RZSR3jEQ0;#-cY3gKeU^KsA'A? + pDbps!E`%Zo5qZg`)H!DM8XOP[XPh)q0(NXo6&F2[\M9_#GoPr2r#g']Y^9P&cRZ[1Di\5K + e$G/e2aC3TiZkSKjp`_u.:\o)q;%,HGr^\_&tkB^H4is"]6)b7F1umbQ@+GRk,?4@;e,bs; + :d:FYA;f:MV@S(2h^k^T)lFD[$mc8s!jo,^j2s%l)]6:^hL+J^9;OV/g/&+q>8e?JsO&jAfW.4 + HR=`0aNArDX=#<'SoDT9I]\;G(Y#.M^>1=+gHY&+tK(j`IeoP1j/6Kq(BYJH&eNqHhA`LG< + C'adFZ8J$)*:\Yac"RT!+"9o689Qa$Ks"9!XC$,8I_/E`Q[Y'$tBrkf!<%\>JnH;A8F5,[K + >A&J8,&,&FWW!rp'oHo:=[U;>QP`KF@7Yjo"HI(:W#,?9`O0jY(8;NrT,>Cj]dY_$t)Tu9[ + jIhbNk/]dOXZ*.0WO5[AGYa21FW^8`U/YauhWd[/.RdLX&,MntC7C0%Put=-LFPORh-I)SL + !D^$aBf87V'#B-[FX'glQ'PW0nr!JO8A3oOn>mmh#.Rh_>J)2]tH*9V"LY&XM,Ue[;mtL>HOZ"QDFJ+k + ]ZreFEpAa%f]bdmsA5(+F1lqPLK.qCcNVGq)-`$\^L]/+-3,UuP$p::!KS^fGNtUH";^9TT*]N:F&0PS/Th.n+G-8,b`o3=d=W$"8u46Hkc@s!Hh)UG(a.<*N"8E(lu*QEoXZR + M/%BY3"TT-J8@Bq56*q)8hr2'*M_WY^bh0m@G\io$;,TN%rHN5P,G_-UTMb$%?SnYcg;,VS<9%q"X,hf6%CLR*g:t&M@NgaTeF)7doZTuur"g@W8BTctGM07"nIRO,OJ- + TYul3dUcLdf:TPWtQ/J,:flM8i9sLEfZ,B2G)H+3u+!k,7-#4_ne&Nc8a>.41Z@ZDq\SOCN@m&KsVIM6UF3te6dO)TT1GW + jS;K'6_J3A4#4c;=uF$$:Pg_cgB-d1@'!e7R$JA)nc4tG[#@YZdmk*a+Z.'#uhb\=ecNuBf + LLm(W'HVhH9Pa\nD`rf;0o2W26nu8n#WRQ$tTsqG9>X*8&S&1r@P@'g^@(%$OWe&*gUj][K + aL5UYWo;/P!R3Nq]/I!35XMk!6FRt6Di@V6[i>[S_;$R"h)A0V2e.%sd_d+m`CTTHSqDC!b + RpqEm&[j`\,l*/'7rMZclZ068V;_hPD6Sp)Qd`PXc/d[Z2qJR*j*Qg/a+nP!UqaT[ + Mqpj->_$QFVAjY,W3haqd"B'KO(%6Gi8ddds0mTTS9.\h#P=MBspWZFXKo3ch5e;Z@rq!D@ + L7UDp;Ggc;TB2DBNj]+R.d,I9bt$mY'J9EV`!/%s8,PgR.\@Q`,b77/Z(CG3qBdAEtm]f]E'6>nYjg:_NJ4bMEV + dlOCR4O*KQVn:culs[76J2B+C^*84o1hF%7LW4@k5(%%XN+oZ8U.2KT7_tq@dZV!G;F^O^M + 'MN1)tCrtZH#&ua%Q&oC\=\(>IDt*[HOJPS9hrOH^m3G^W_,@fuLkmXIQYJ^^Pe0*.j^YK< + %#]85oa`A-PSEf>rQTS[=6hS;P+`Mk0d)X;U%hj:4`Q%j#g(/:2b'glj\diB]ks5ua-l7$g + 2]QpH;u6'Ba-F,7rUM@WZ,8`Up87%_dqk/M6#RB1'MZA]&GlDWb.[,?a0bO!7'm@'hh54ieY!NnX"R5JJUa$Wu9_t?N0p.',77t^ + S,PPH0hqC5u`2Cs875d3K6ImR(>gF"%Yi`2V\JEnAIkF#KVl1[knFN8BscE$qSn + X2iJ6+F:ZJ%&BPgUaXe(H4;4=a'Wg>G\29P^8F&R#RDGD^T?Ne@]UZg\!5[CD;;7*t"-8N8 + U-^-#;BqCB99g'QVS[/IdVG7;PF@UjX$X1p;R;t3gRo/.YJU4Adefh-+XTQ5ZpR6h,0[J_A + @FpH0Z/MF]$mh*Z`k+=4A40e9B&+XoKQ"P5U7=80b$B0S3son:/"n]b\]b[oLM(N=A5M_9X + RGS9ME*-@SH,`bl(8KUeqo7;GAuH9gWF9<)lY'<[O><1F(@39\MXFI_:/ke*/*/s*kLNUH$f2Nk>slE`C\D+IlKX,V_3UN&4DMDml:fP85] + CNrD9H.\YufW>^obn8UY&t\J(XP=Q<>D'b?P#6ps;3Qd_V3TH5s3\^;\AOYB\ + MU+m9'9@Jkdbc%b*/8HjeFI*S@R^_\bbu&Eq['hUWXmY>,R=:s4'ugNb>UMC`i]=MoSR2%s*Z' + Nk6a=Uc/")>@8`e3Tpq\AXWZ<1+h9-K\O<:Im3Pp6-96`-3Lm*Q/L + fC:._4=c\b*&YD(]"?001pE3_K9QWr0b/XLao[dp9.UD6Q(WYu?pn,DEHXS3>V*[);i+>CA + _?Mn$\U\kGi1<&M + ;,6e#cN1.Yb]5/(:0.dnhJ@A8"mAa6Uh)r@.W/8\!oMmq1K2sSUp"I6(V!SJ+6k3SNg)jE_B[j`"Y)^u[%cU + 1!>F$W#3_87`7U+FnBmNV8]Lprp/a9iKiq-#O<\\=f1?o=i]^/V2"#+5$fJ>->>iRa-I,)& + oWE$8fA)uT)r]f4S6gF=*h4ClW[RK#hNEtDJjHd40rG+80m^4rH?7nrJ.p"qk=R3t'??L=s + bP/F,^L!d:ca.(F_di$[=5N7ThYdH3$j(6NJ*#2`jlH\Xo""+Q@8N8!:p+:Z%a8Nb%H_2^k + &c_:L1ns]d:TN]d8PY5CP6Oo"6T9@3.r51T%@U%#WU*9;=4cX(>@H]GLA*gdRJMbL>HRV-Y + L[PkM#BB(4XcHJC<#"Y@cj/4YUPCZY3UNYMP%5:?cGX*RfA<6_gjQ`ZXL$[(AFa]2nB7%OF + 2k-<(a.6r*=-cB_F1QW.ji1#DV?pTM7L!C)p4@k+gsZC[iP1hSbKq.b + Lh:kfSpBu]#O<+&T%_dhu>4o-'30(!p8Z!D,hJF(3*`+1@9g;dH5PurcP@ZgN.M.;E^Ugep + :`qQf/)qi=mbZ%A\(,V,GR8DDm)TA"qq)0]@U2F?Q\s:?U?^kf\G>drt$KKfJ^h]Pc!$DVn + +A?VJZRn'h9!<">*k-Bp6&o5u@me7HA_h<@nQD\mJ!`c..lD?`<^@ + ''/`JECRW;G8=MN;t5=P=,.[TD=-l%_fspackUuq5U'@O[H*.SRkN"-3p3'baX1NX&[%Y:)lB"/_Y#&0"2bn)Zn%*\ + l0^s%ri)3+o1JXBhW$![nR""up_YVP8J[l/f'TOjK.@Koo+^rk"ZX:2'1.DX)*W#8&/:k=h + gAEoZnRfb!&a`'"8EX#*dOs":[)&`]JZbXYD1)p^V"!HAAA-a%O#!RU!?t7C8%!Mdo5fYQ5 + `Y&J7JW6=4=;]Hj1WR;N:bdn;@07>.+CaOO[K\:6MY&SW<")\-'L9V+0fH+D(BR?Q`qI14bdJ)0URt8 + /ZH!QPC\K>G,Q5#$R[2V-8G9BGk?3Q7*VZ>9IL'#$2pYC'I]]AR0n=Pt2cjJX$KY:LtY[1' + UXLAKh=UTOek)"j4oN+71NVe"?#!rmdY.Djo:d/XpX-[`A8cJ%'(fH@NEeqh+ + >sDC^b/TC,SUk+D'erog!BRJuLMm^odl]BB((J%R0+`dbY!qp%FP9E74g[.g1Ird9LsocNA + PJ"Ml&Ic,MM5Ni7Q5u\,A&5`BmKDc#coH=I$Oq^7(BRc_`'?g`nK0#"rfBYH6m(Y1J#%YpP)&m-MCCP6,p]QVd]!1="8se^o + XI-6nGc/oM(p>FbaO=`BclTDJ#;3(S-Sn2N[`@;-\V,aL\cE@l2Z=4+o\/?qM((]+[mfu*2 + JAdOWWjbJ#QlUV?csdOt(HI.Kr5>L\dhhlC`X,U&M(tqQ?&4_-&9WE'Mm_s&VSd?4Z^V5Lo + i7=Am7M/7jpL#PuUclSsBr!WKH]qU?VQ>%+Oe['phOs'+O^E=_``5M%Uh>m(%J9h!^HQ\+i + Olcaj^@K*tGqYD<"no:kq!5OsH#TrCQJ$>XG_[$&K+7)=>YpLmU=:*V?br]V!*;l_>[6"RrWDkiOq1ir83BNs!e-KWAmBPiS7(aENV.&&+ + [Y'b96g9c;D]oG;A=9l^]Y\r4+FUi^LFe@N+mlV'SD0gklY&+^e.*LjN^0(%N-dl9 + S9nGb#%%rcX( + mgj[T"r4f`;s54:d4bN\,&+e`\i%tdlO?*Y5"8kC1"-c&I=pi*!(5#GB+8`TatO7]=c,.q-EfN`@J#@;cSk&X(O"oWX8*L$sU_8M+l7@F`dJfp%9Sego3_ + 2gk,c=0/T-*?OJ#YLb-7%ZDPS/jN.hVc^a833/&tW+Gfj?:AS?l=mrF:o]P:gFb]U.(K@8' + 7K[R^2K+7")]9UVA+k)@cXZW210p"hpbN8'h#H>lV.aZ114s'R)MJWKL43p0K1SeK7m:IZZ + qfVngZj8Fq_\b/1c"Tk?]&X/:L;Eri:s(/PiKi%%X7&ZprB4Ln3O7n#eg'J!,m1lD'QBot` + 'dTU"8Z>UN4@fc'>p&^QR+!t5f]fXr-A:?e&,LQIWWR?\PmjE%JsbH9rCNu228Zk,TN6sAN + Z[ppX4U[WaUM#XsY"@!FU"D3WjbX*EGRe0p + bOV0<^7nG-f.?FAhI;cc$M`9lPV:-F0#ru5I,FXgrt4]eZ^@EUt:ORb"oQW!,q/JY.jj + s^8P)+uGQ\X/T5.d()Y=F]Gf^R/Wogrt]r![&7 + cXT=6Cq;)RZdfC^<&eAhg!MT3`j + r8Pn1J;\5oc8n/753+5AJnp&#j:&Q>1q=!YjetSXkXai(3p)6%k0'u`CUf,%H:BN9LX(LaW + //,8N9LJ&kt%E1Mr]brm#(5.9.m6'%^*S1beRo=lbqND%`H1slG;]P_Jo;;8H/"816ARuOR + ,=GY3M/;m_n?>`G$sDnJq$)54D6\PcSnimh/]?(7#ILa@U3ha`-g)T(:!To*h4Xm&$1(5$W + "mRSQDrM6P21[.QlUooEA&$-pePd`rGHp;u=g%.'SPoUd]5(iP#!08@i2%abUrd?0glMB_l + @,bjZWUFJ1NC-$&955Qg!C$JJ5X\]dk^_LQ6oK:qXI)MS4&KkpW"bDOV + (#k_dRR/T.MFcE-=Ci4pbd^p<1ikhbY[nA2'i_C4p@,m*IOgCPnoON]nN%d6fnm-bN#`@3@ + WWA*f&;Xc=E&o;HMb]bi2'U?u]n^0>;M/LEK5k:n'o'\@KXJ2*kX#2OqRL_gYO^-)OZHQ6X + okD;9Z#%ZVd*9\^p8/W!mrK<3n=L-aT20uImtCIuOO2,]d7P,KAnLkBT,K:0UCAoP;64HWY + 1)O&)fN2)YI\JP^86feeWJ#)i`uEOdetoOD=Q?YZ/5HAmf"\pfBn85m>o,hoEEUiu,dK + '=\"EP1]X=$4Tn.-Zr'-V!c+faCAnf\&I,m$smG7lI1VgfpF1F$isGjmc!/aD4+7c.]q"L: + f+nksij#W@=657*L + D$.>LS#ZD('XQIfL.h6emn?jd.\LYaV/.fWK:rJ30aM&.Ol13?h7'@&_h$qfjN3_OT;X"[I + gCDFANfs&G;Y^idr/\/a_[-W'E-aCPHuOSM+KJ-.l-WIQ'!iC% + iY!P54W9S'Ji5nF%VhK:DED!'e,[gCp`hQ9f=Y&?En-$Z"ffXE>K:2(K5RLo6ei_m5QhQ3, + s^5WW+sF#,'G1),lq@PFS?teV*esb;cg;ebn8T!2WcRsgYQ!5WeKAf9+LDL1&.mT*r?77?+k.LeE$F) + T,pKQD,4mMDcnmS@3?um6,R:"g:dlXk8:(nAZH`I.E`h8;R0D#I"qkHq;J?>uD$J&R#7Fr! + c8-in3'NFT-r>Ug/kG'OO%@W_8MZarn=E!dUFL5\.]?o.n?4>rZA28b]P`>bP/?GDLCA4H% + 'n09P1'jqf*uE(%BK?jm^4Zb\kR/00(A=)NlqrNcqj64&+]m!Y2KqPk#-74&JGmUcM%pRr) + E84&i1n4mgToKEt]3E'2plVZTSuN5njWP'MOte%lZ?V4BsU@23D$!afdT7@5^tnS+119ojI + JJEqY5$2mI]golBehK_OUj373^G'nlAPQMF![3Ur_&24")9W7+b?3t\^o'=QCd\Q\U@>;O4 + J;or7mb\WKiV[q<@NH"jHd69G<5&Gj7[GO12%6l>g09%RHCgtV58 + +t^s@2AE?SeD7DehA.8%Q6eoCm6h^C6q=@IM^nrF:uIFB91.(,]69Q!JIW?P`*A2g7bmf1T0UFVkX + 931!]JpKL`QM]"113O`X((Md/LTc-_)3nJQ(Z*SZIWhgH7V/O7UNEZ7dcWi9T>]"7]Ze\mK + lWkutrcQrIDson*jZcc/fl-`?dK'gb9f)OsaZp.:IHl + O./P&Hh_Vh_7PgFu;[r38c\X792[$p-c8a@qBo[m]e@TH$PA3bJ%+_NF&CjJJ[nScllP@60f#!Di`ka + :Em#q)/lmZdf0("\V0TP54E>V<4=;Umn$M<1KA/$+cAur=F+j;3s)j;(phu-PDj&MWB[RE]qD5)H + MDk=_HTOhdqb9SE=,3!)[af<9e]MZQER^mfSQsIIJgs\*'1Rm@#p]hXEkh9-o)9:pTiuA*Z@Knm\to`Ct.VmAq9g4=8QXc;pUbBW, + K9ZO,rD0,QIO,;VkEIDs*YE4VEdOZ + Y.6uHPLe=2f[i1YHaS#_?+2!eC+:>. + iA]=DdgR8;J+:cP,dS&^DO%uSmPM[X1134Vp(]e^MA1Mh]&FYgaVc_o;Wo2/3Q]CVtgiH!7 + ;(%5#7q!G&a?)dL.W\J_5f1h>aFc^`mOKAW$\J&(j(Kf?/dJPAT249VMT>LCUGM:Y1RbJe: + 5?hA[Y#W*:OjC2ZeZTri4hOc9)YmZbrPeHc`\I(h;tlTAqj,_4QO:L44F(;`&RZOsQoEIK( + Y:tigB)^N@@WTke2;]U&'=H.Zam,d]W&7r43JHGS(tK[oO5r=aaou$[C0AbfHm*$e$aKS86 + @[#=m8Ktj%4Of.Qm$1I.+Q\NOVlo\0h#0m:!A&S_C7CX<[]e'Kft%mJ\m61J]cA`;X_b + M(::Q9Z(m)Vh]@/[q:_r*(32<;[nYK4tV3)k5(AlVTs&*$6a5'lrqrBg^a0'\RH!F"FouY03Tp7`CYI!K5).._QB9.+ALLAUV@ + 2gS^2rNM9j[1ujGeBSVI%dm4/[NkuZkQ6A>d$RYZR+@#A=HH>ekaL&DmbgJ[G8qq>gFf;AS + /YXB)"30*8fldQ+'_\KKSM.]^8qaom!@*[!st&_m$]3hSj7"?E,BOp!b[a:R9\%HnAYJIS + i0"?%Ai=p-]*6VK1b%1!NjJIKU2b(0t`)?_df6P9MUTL/iaJICZQ]R^Hh&@d9!EOl9)+@=3 + R/0I9lJ:S'K&?:9gL_-G7$;t%1.%inY"=Kj/FJs`sW">>I$"sm8/tbO'"=,*V3WpZM67gK7 + #`'%HJI"dXK/fMj!X'U<61P."TL%Z6JHoj"FFaZF&91%06+R1<+@3"1)B_>:+Fs_f&7U1p# + S:?:TL!T$(8*s&";TEW&6+2a-kK4+"R$Ck@]*e=@5&/p*#L_(AETKlBX"JA"H"9[ + LO&.F*iW"95c!-d-"!?aW9cm#+W-4>H6_#aOb+@k]"INV/;+FtV*&b:Jp#SHNaTLZ9jHD!d + &"F6Y1Q:QQJ-kYBg*U"*kQCp`_"EknX=p/sj7o"#S*=*8&JK2``JqKaF=rN3hk^i_iTBN9R + MkB4YTT,_FqEg@;kop%iTBSrHQ(R;Y^mCoIRVmVPa80h+Ve>jPJ#DK+K=Ijp.ZU?tl;@PXT + B^_$W1W@Cri5H[]!AH=kPDi@X=*kaJ#oREc@;rYRb"pLl^@a_+7#p*]:\E2rk7qslMeT'Cc + VL4+7)Su`LlL2rl=_+M^HTPm+MB_+7/7kc_'S2rmCL8.o+U%D0c-4+74pafq7Z2rnI9DbBD + aP-i8FD\7b\rJ%4\=P(1#l)k,s$/uej8+7?]=m%<_!rpHEHs6/sbD_'7c]a+GcJ"G'eHcPs + P+6UoNT2Y0,:[%gCKDbb1oE%8()#ljrr<'lH&q\JF&Kg4%J"\UrKh(tU+6[;LTsQk9d0_0A + k`C:gEW1hcqC1sLU&Lr[qO\kpKR^!^/u_i3WE!]GJ#_K,X@N,n+6q@*X*I + ICT=U&MY + oqX5Nl`.+sNY.[oJq-ToqILl,N5M-BV?u-m*0Lc\la86;flo]d&);`d9jt*1[^t)F$Xk@ar0\)dB\D,rC2Js@\2Pbq;$Znd+6=ZY2g4oP>PitjD@ + ETWo!CX(j,%ac0ul9Z,ip#>C`hcKJ!UBsk$75EF=rR#Qf7pO#Pirnjq6-)QWi_2MmIS=8:R + $nragl\R!272U-15:nE)^>C_N/.6d+6_E"_oRB?U*N3aaUirt@K)Dpq + FZUL1+5R>W>2/5=`cTitdr>=^&[jSf#j!'O[!7W=!.Upjrh1S/I? + 62o6HFEc,#k68;T&H,8GO8OUnj(*DmPHV[f953M;4TJQh:&,&sefjtD]e1-2Ll6/QoP<9rRpj]XP + #10TDj+7u.hd^iW5>0S`I7(KQ5qJ/gib@k`,n=Cm< + !nagE.e.feJb=ES5iT@Kp]8.;?']IojDiYDR#O[pur%^BWY:?[lV!">YJRfG(]e+=,QZX*S + \30k((lB62t@E22JM5/`kX6BPnlas0>['b<;c2Akk)%3KKDSg&"-MhcoERa(Xl^#OF\BAZi + HPnbu`KgjBX.#9W[%h:pR$")\/A5_pTm&,V?,/lWmEf/3pZW(oSFQ.3Cs@M_As[Yg2h2]qd + GnQnl5&#&[\8'))_O8Ia\09u0dd5q0$,cqg%rVXF_!\VII#+6,[C5i>q"Q6p3)l%Qf:C68M + 8!3h*Yf7TBnc')t`>k\L;#eIYQP7II+c;NdUm!&'(ZQKJNF`6c`sU4!8s0.7EW/8FEl(phA + WX5EaT'A-2^d])JM8jRgftL8.W5_o>od5in5:lQI>)7)AuA,f/8D(n8S_aL8Z)N]Aq6IW=_->JdEX&AE&WuC + ]7VN$b/2Jm2([C^A/2$LS@g2q#d=ZHAcVJ;tk*T*p7PnaijpoXJ;q + 3-"aRK%6L1f:UNMO(4-A)i^u:"KgYe\Ieg%+pp=cih4`\T];?"UR/NKkb1W6Tj$g"S"-1AS + Z_f/Y8SFb4>&Z=+hBH&U.Y3T>5H,eVkTZZYM(P2qCT:p0fm`<3o^>f;[+IVZ'2N"UT:`*W] + dT/5.bf'4+]g]P7]'M'-qY3Pk2T#lPCi$)'nMe7#SpY/&SXOjtrNa[(;0O'2=oFNuC)V#bt6S,OR!HWi9F-[9/YNCKJ8#Ri/-%"^CJco0)N.nS3jC"0Tt`A\`V^l#ap] + "OZXFq!td2hVVk.H@L$jL;YP2p6Wc)TeS^bK2hs*rCOK1_qYDoIV>U3,/.IH\fMF-KPQpQ,`Ti13MA"4,uSN5a^0+&^Q.NUVg*]b + gH_[?.4;Yd%sV\4W\3g;KTl7F[u[lVYd3npgTRft$@#>;\7,Fc#$6p<<94ttd-4*j4TMn-b + V&gV6,9M<&EX1gu;(aS,[,kJkfPJ]LN9/6!<1(mYNH"/spai+''-0$C"o?A'"c91_u1=Bbi + nn1*7GND_ujh>PE1 + ocHjbj%ZulGgI%`lY)Ig6.npDa*f456PsEjDl];Z,\rta%Q&o>P4um>d`X;[J6U`S9hrOH^ + lX7^W_,@fuCelXLI_:mX'gQ+r7OH9#Wat+a + Z3Xj/),g'@GJ4q$@F;ra:!AkmG\:4e?uP\Emfl)<*I2"HaJe*TWcmkm2q[8< + &W)tCs"os2GgVBjF9DdJ/kqI5SSf8+jWD/ZVX# + ,^ftad7#/R*LsV'%5biI\jGZ@BNDS)L_!?=VKTO"YOjP+t5qq7`7$U&;Q6.rM6$/J[JbMHn + e@:-fahs#I<#nQk*_Go*8d$8/'HnTP+tagu3D?80@0o82Va>MQ\YLZ7\J%TB.n[c23W(J?& + KOLA0?XeX\l:FGBdZPA1eUh*3ik6'"?4M_36RaIbH*bJ]K;mI4Kt<]]2ZPWBgb>t_8I>1Ug + 1gU4N,018]4gKe4[SFK>Eh+b!`&K<0P;>bJtADcG](qeD&/8'?lc\dmZ+CLFW + -ieSE`)TmoMRMABnFkW*ErAMrm3Nl+WBs5,1lm^kl* + dOu41W7f-/aI;UKt=#GqY25P:gATCRf>u-/rc]Pn:U8>W3r&-q@=.K9AXT,__!8#a%SE0gQ + .r;ZTKspif==Ukj,BLr$FY!->X:'6]P`E5Q``T7]\'ofJ1OrT`'Nj`;3&MIS'c.s'(bJ,o; + 59"7`KjBGQVlLt;=0e!q?Kn*iBfCG\PskXm3Pp6-97;=3NT5a/LfC:._4ms\cf1iD(]"?00 + 2KU3aB!pXYSVD1V0)6]!DE@lN4thYe($";l-g![Br"a[8Yni,R(Y2r'FVO]0o(SgV#u/bJ- + Gd^s&(Y<.2P]Mo4+<5ldTe&k)]bKV?R<=R#L)pcJrd7nK$1PO1 + ]$sh-D42&kr^#daDrRFpViDpuNegc@(4%MhhA\Nh3RN6':]kK[Lh`fk3h@sq[h""M4o/20l + 24C)f)P962F1(?/c^f5TX`lZTGYck8**mk?_uJ?+Btt_j=7$)kqea,ADb+_s:j%CeK6';AF + NCkE:q_W\bBUhWH:\!l;$DkT'7N4lJ#pVL/DLun",+L=(YLAWffP#C9cI5t + 6Hof'JL385H6UO>2-PWdL=[DVsOe+L3""1cnr\l9kEe2%k%j1ifj_(iX7 + *4Hmq4'?i5&a0N%s]`cm!)_g'Z1-J"Tc(ilqm9*]m>!8\<7IAOa$U@uj6,ke5^+4:!@noTa@1Vd5%#CBog"4a?Zos#jnQX9LgR;u*bG78'oZM^Cg[0Y=Sm`eCP=>m"3I:f?r + `IDQ?5^`gZMia/cH,M1?)]dSZZROb'frGh@ZH1ImUiEkS=o,rdr#kW9?toU4.ha9s!Q5*U' + (9gB4WHUTgtONQ^&`B_Ad;jsA4r&E7guYtgQXD7sY,/0tdn`3$jiXtV/^S4*%hC$%6!%\L^ + 'a_DkV-B=iiL!=@54DJas>m@65*^@X@h:)V + %.IRBnEZ'PAH_X:'Qmt4G,baFc]5_N?0]bJ@m@kAlkSpLV0fY0!4JcCA_$?0ealU;oK[<7f + KNckQ=J:EA?6!YAo/">I1KqIa)'mQd3`YN7Vp1McK=4(m5Aok72`V")`Y"O@!6YFK9!eFOD + U;-i4Uj'dWq@?iS+UASn@*)fTQ97@pTP69 + eB3Gu8KkiFog9Kp(#mV*F`>Dp'\1V<)k.;<##l"rlRHqA6N^uF`Qir)M[$R>+p1=YGBeG_; + 1Y5;^G;WE1)@uE)1juV%943b2rZ]*]/*F)kp4Rb5WVoGc41ICBO@W6e!jDAHlFD/CL$KRc6 + cH`dG*_^?[n*>)cAE'!BQP!:%oj1gnnN?R3el:Lu(2NSenV->kQPo-9!-,_X?Pa`!&+&,1nr8UU2?,5Z.oBX$B(c=IhUG[u0ApG`o+oqTk; + -ag$M.$H=jK"ahKsQDM'u6KMrA76T4&[a$\S22<^5*FCd + FLVBG*S8FFI(oWF9b=%mN)5kO1eBhqOn-7[MG/(AGfZ-N#b7D[KU_XDY&C!4W_h+m5$;K&\ + YosMol4j*6E3GLY*l:k@F>&\Wp4n^3e1WD[[k!=/l"SQD8E,Mf=?YJqgg@h[?cF7WU3Mg9" + CNfAe:CV/VL/-S]=5H@;hGLZM20/4V][oWda.C#k[_M?[r:,_pC`Rk=0,n!=*(V^#cp*!3% + 0bB*a(?(Z[k7=#SbKq.b1M1i=H*gCT$:l4r3tM\d4P?hh^[:Q/+"@=m4=Xl4W/*402\o,8_ + 2JGIb40CR<(Kam@>EfY;T9;2bI];g'=!K'e!64hdJ-e\`SFj`du"pieR^7XoO#=$ID,@&?, + d]_$X$&+[u`6JeR'qke%Ir"=?D@E'dNU#YBU\+G=t_)@/cs_$H,h*"[f,+O)$^#U'*P5(X; + QK?=$&G6ApP#;AH_+p^,Z%A8>U+OUNOWPJd86&Z@`";fZ4K'4>c#V:Q7m'&cT&5r]G5m6[C + 28TVFJdEQO3$=+M";&BP&4$.)4Tl8R+G%TVD?q/4#'$k4`"4R)$UFiu5c.ur'7p@[JJ]Ls6 + NdY1!RO)J&/bTSlQC_V+=7@"JcYSL5Vs#["9LjhHfuRZ#Q^3Q?i5@C-^#U%^S$Y?,Ou-;l+ + nH<8'DS8"FKkcO(]ch#kW^2i/]NR&`X"=5ooGbGJXXQJib*8\0J!Zl2AF=#U.KF*69;H![* + 7B#]ZMm&dWHLLBJZM)sAHXJfCX3\I9U8g'DOg&.NjHI#[a6Ynd&RFW$-D; + (MFt6JeogYEASel\d2L_KrPD^:+.8tJegm#@Y,@/dKipIKlRH"TS6h\D#Wn]3[J#1^W$(;U%VR!GJdsaq#WNrZH3cGPK5M`^%>Z.XJdk6 + ndu5E%63oB?K/*]fTS"R\Jdc<8`.ACG+Mj?dK),a++G/ka/g,c&DLr6e+L6S,#U0J)TBJ<7 + KV.I2re@'/I[5eaBW7Gs$)T)ru_FIJVX(*+6XhsTV;@;#PnoPkX#fR,UeA. + d/QHXr=0A14?q3ns$T6Q&jldqM@i`=+6^(]UB1@QL\`hLkh7,RKQN7enj4G_"Fm45rfN!48 + 0@(G-`"\NPS0-[+6caSV1JW3L\b6tl$>"["N6]A127oqUjo8XrgS]>E$+>e2lB(1SeL&^:L + j>f&+ooee.DXVKDe/."V@Dm@ZV\s4Fa=RrhTkrQ65C"J#TCkV\J]p<.k-HO7c12eNj.76iC + $roj&u2K!JF7i.%eIriV%Q]H?G6J#ircYa-KQ=UQp5XKhc2L\f@>lUZN-8V4@9_V/4PJ:F] + krj[a[j<*]TJ$+X&\sHmo?45,0Y;-$iL\gcflf`i%ahkf[!s2kh+FgV8rkaHf$m4gqJ$B=> + `0d;8@mg3RO7kOtf^SoO"9">mp.7N;1FQg.\::g3rlbWE1*>l0J$WS_c7#/CB8lYZ;3lr'# + Z2!S%5`Qs+oXn8q%d^>7B3b=ZI[a_,Tl*7J!,B^8t-K&Cos88[^Oa^#PgD&jR@Y_k2b<%X* + 8J6mCeb#r_nUJ:`ndj_)N5k^a9WaT"b?r>q$lI + hCZs8r8Zk-q+9-5LOfV8gF9``H\L#U?#X>&V2WsoYs,E.0!!2Shij7fc-]>E)*2,4-0%**M + ]]]O)akXa;G&R8,A,cl8D#NBb_j5!RR+R$.#X:lV.`4s@i!?^Y:J$<))3[\J+SeK7l0er[H8,F*p'Ae/`g&Ftc]41i.#hS!,%4gB[[>VptjB2 + `Bhr8hiqVKDq]Hb+2KO)hY/%BWjD3s&LW">]NS3YEm&\>b($XXL4Y,\i3,`$itr6cFAAU.d + :60UU73O:s0`SIR!/sJZs&-in.a;C5m;]+8.J1=U2&$XI6^\%t&l[M_l#^jdeDE2UFXg7/L + gQVmS2*qHCeVGu%*5+83k2>A+BFD9;N:-h[fVqgWR&*#=.X)$Q\_,7$gf*nLX?G + TL-tt,h7L9/+iWA/B\jkmqoa9R:$[WJ,53@)QP;sgo=h]jr5FJsIhLIBN$J?&i&hBuj$[Rs + 8\I.)&c[LQNY@HCh[:hI#,1)hs214N&4hWiLt&Gk;fYQ]iga).AB^I]$Dgb&q+*a?[Q)<*W + `-eWejU@uN1:52l=_2WVRAN4>p0c*IP&3ppcG!BHiue*'2e + NQ\3i?#$@B;qDO8S[C1\CL83X(SM(/$pureJl^/qm-(*6d*:3MN;K8ni,rcudeXB_6V4C'L + ;%>)oF(R\*R-f"Fa]"Z?53`O'DAG2'"nE2\9$?8mjl;HrfgE"tn@Cj-JsC:fM,B->n0eCmD + Jg5a,BWkVB]lA3%:bQ*T<#`Phs%Z + \8_Y/8#rk/'[Sm0*FU8Gqk62NWk]ONuudDX*APm_oJ^`JH59`D5n/5k%H^Pg"05%h_r^(@e + JXQE5t0m#r+o.[TTVam"]*Bo^@+;Y19eoLuibXMUFmb8*lSS*sP*C!+]bcH^EQp;u1c%.^! + kqO[/)A$:KW%u/HR%+.ZYq*nihMB_l@-DKl[UJIn'W]FiD55RrAC'm`UbtMm^;#EplC[,MJ + /RTn7ACcgmVl&=L-Kl=@3cY-/OK:f'cKLCnm-bN%`CVW"diRuB4Rb!/&r^^mlut5r'UA,)'9%[3b`8##-s?!i + o+=U;.?)EKORqSRoIi]LbeBOi`g[KGdj*O"3BA3VgBa0`;#060;$XVhq0dk7 + )5&c'$:k^L%/MPX*E7Z\?[k6qFN)JaI;X"[Sm#?&T_5QHKE;)#iqN"JP__0U/o*XnS,7sG[&Mk2cP + 8b+?*td`t&hIYa:CArH&6CSB1N>==P8"5#l&=t3KK>7nXV]QTfPdt3g$C&au:7-Y8] + .$4)IC_U,;c;_Yc40eW7l'ia!QXdiEM^f'hDG6A6IVjW9WNfMCqfU9,MUpE-a>frtH.&-X2 + <#p@8O+V55/:_\#u(p32>geoEQUEK]%/HX?SGS2k9;E4i7OTWc>hQ?;nNV5:B9dL?J71KO[ + Z + #nIOE1^>P78)F(D.'LmdBa&cMCMF+Yln@15SXZd4I-d0U8n"a;$>u&O,bsRl#+T1poU?EDZ + 8G__mQZ2:YUsd:2bplSc"`2YCVS0m*,D'0")GZDD+:?:ZDDD7eT&a^b&(B5En5)E*R/W'Q-uVuI+U1AfSZM3.]V/RR32s2 + ?M"J01^_sD%q!g!FHdQCclGF>`r]9R6C&?Qc.>;u+%&PX6]2NZ'L:P08RjSM@rtK(0N?tp= + %/9Z7Eu][P%rtl:I`o67h.+@9P"i[r:&)e;Ki@D[gMZQ3q>'oEE,)?Ps4do9_4HJE`GhSPu.+8?M*i + %F&cRgQ"'FVE;!4UFB*=&Q#uatK(lAJF\N)Y(L6b*R992r=Z:*kpMX3dF'9#4q[GbnZ+AGM + Yric/4AAfQD-J"Q_*'Zp4`+s4NH$!Sd6:R\5)k*lXbRuUiBMJH5HU7Oc((ibn>n;O?]D;k1 + _jCT).7m9hF(n:ckRNA!/r[KPUqR + >)l-e)H/,*gPr9DS6/oJ282T3Fl_X*H\m.Sh&G1BBkgJ@P#:am&SCeG@?%e"BXD`&DNFWBm + n+`J/AQ$"LqmhkTd54VC4EGV*7mkls53m/>0&lW;N\R + ZN`A4o>L\.P6u(S'&Wip_3Q96#Q(L:=ZEB$6+(P*id_mn&G6KMnh]pe,;d^S#V\Bt=h/k`_ + ]:c"ag1L?Pt<0]-ZW.u3?;UCcs3\iGTC5D_;NmEl.+/4HB+'ZBiJDX:_fo-VJE[8JQ$VUIP + Eg3&@2GGh];ES?&)M3k0'>B8G[Net6EEG]dNT9"i\W_n7fg9$I*Z]NdBpp$(Z%3)B)U=*5e + G7$1UENmp751DSIGW@^-D,Y\cbBWL%Y-l<7e(^-$iK[#pYF/Z[fjR**A?)+&QIGl#&d=V"$ + ESN"5oU]/2pXe7_ZC:hZ<,eKVg^RMY?YmI(0Pos<9GRk=`2FB+gB8XoTOS5r=4\] + Z?n@@\*V[MdbMP_.smMWDBdK3@MQN`uh8@CM[!KQO$Q&?b2CKnVPnkW0/G\e,?tPA6J!9Xn + q6(i[7%TnelgLXb@?$l?M-M,*i*0A)C@/2`9,!PB8AV%jF-0c9AKc)''tDm'H[Y7J=6]r(6 + ;V_p9.EC7Ha)iZ^BNHIgPXL5fFj&K4E=*!)*XB9.1PO0%`af`P3;fdos^.6acmIbPY,qugeV1]hd$$NQ$8tSpSU4LWrG-_?@6NpZ + ibZT_8fLaYuuR(]RR3;$-7>BR2h3lPV:-]SUR)uZW8U!2t`X;WO*KA75tC"=hR9%\OK`B-N + (\k>fF+Z>IF$Q[PWQDI+(W6f-re"B7"^F(4FJ+V73h,\,>\eSF\7XLM<,Y9:0!XpgCf4Q-b + i!9_Pa%fQ3c^YG.9=UMY5 + q0oU66N3&G]SS)s87rg]]NS99^HB2'PP88NFF1m3IokSY3$'3f;pH#?V\uqZ2R<>'k_7*df + o:<`UQ,7sM=hUtO>VB8c18GmK41R0%gc_e\_csIl>PdTKGEg[FR6B/lrYkN:HsL$anQl"mQ + ?TRd=1(:0\8ltaY!(U:=dZ2B;B*/Pl/-Xh?PaYk0]E]^Ta4gTO06p.:kgHT2>.: + _!5FPO:a.n?u=B7W1[[9UU>4'eCZ--Y+TAt7D()<]8VECjEqT/]3`Rset_nV$`Bc[1N3JcO + $q5M;,V>Rcr(J[/["L`7B>`e_F_YVma9LBCsMfJ1Gd!X?DjYFo[a/.Hk,?,5&g29ZML0S-@ + aCM4X;#.0o9eo3L2%:]KB:nVRu)S--TJZBo.\nhgU"'!(d&2cUS#,ZsN?tr4NNWu5^^sk%q + ":[Qt:KjE*fG\c7Rt7H0Bq)150`t(ada0hQq?E18Uu5r8)Fk;?83kSl1is0G"%HgoBXes1# + )Ro*1N505%1ND+^sJ0"*h!:bJY6Ca#TKpB*QrTP'W0iWaUXS[`VpX:4=q3P + `p:1QOR$E.OM:B':,AY6-[Jc#>I<%+F-cRNQ3e)4Cb@JXJZ?1E6hB"#.O7+%R8u#$ukI?tI + Cr[f<"0dKV7q@_r="_$CmZJVpBCW.Bh>(o7P3@Yt@<+C]X$-UW\,RXp.n:@ + 2*$3ki"B;u/^+D7,IH!Q4Didm[,);]q8f;]$uTP%^u6@k[FIG+6\:TM.qd?/;tfEnc"Q@klLdG+6asJPA?"A<0eiPOoC`?l(S*G+ + 6gW@SSa5CI%VmCqM'Kua81mIWCQfPJ#V2fTW'Du_>^L-lI#U6+6rCqYTN0I*3q-=6J-diBD + UD5Xp=gaJ$+S'mE_sDdeLU"lhUOr+7(0M_]S58>fAFVF!/UIm$[jr+7-iCboc<8I*XVY'1g + Upm5b0r+73M9f,sC8SCof[ZZ+bCmFhKr+791/i?.J8]]2!^;jcbjmWnfr+7>j%lQ>Q8h!I1 + `o>H-k-i:u7]Z9orJ%\AJm!n3.p`CaI5L6;.56Li^&+fQ\cg^s"&4$=>6k"[&q?\8-0RobS + re(OQ&g-=8&>H4=Cd6=_s$ooe*[B`rO + HMH,/&+l)NdU<)Hd6T0,,cHukd/Q``r@SWQ]KajFs%H:@1+$PYRg8e*+6g:bVZHdeL\ + c*7l.S+pK_1lN!<5jTrBUte#X?fms%rms77\^AUQg@p+6lOLWF>e'#Psl2l>V6PkpE>D&u8 + M0rDSdM<'So@s&Hu8=:b(9.2AScT=fquC5MXt07rHf(JnitaYs'MQ"Iuj:*3>`\=@-fFo + YbD'68,Ef=lpQ?.1&f.)Wu#7sD3'bO4?qL)s(#XE*Xj4L1%=c9KKFQ#_mnbrNg,kT' + \L+6Dj=Qe+pq>t_5@Y.`GSZ2S6'q2ZW[7GBn*EphcL^N\gfJ!puKBZKqFGg@,c]XO@$hKcF + Lk1"mMEW0i^ZdjCUD=5+3^2_3haWK[sJ"5-7q-Qe\IBU?YS[&0<8,;%kYL384Vtg:b"9:UF + r:l?Ek5h5,$%[%R#Jh6$JB.Ki+6XaR_.Y\2+S6e0:l,R@oJ/YXgaIjFXqnnL@gl4*s$^Gr( + 6A)p%O&JHLTpb#`"[M^dJ3`4,Q/e(LlW2.CeopC74=5hVE`M-s%;fj/&f$1(ZPp49V_PBO7 + ^m=j"tM1Oh*MB.--siqKj=Kp,kiipE*oCJWOm]7Z[3`5LbXKOV0E>8I6[h,bgtSlAU4m=Z% + O:m%9LtN`+#"C-U7Ys&UtY]/L=QB?j_hFF0V9HSUMcjmj62n=uqVE=[Jn3)^R5:^ + nd[H@sGRsK.5M)^bRko5+c5FY_B.F*,lkk5VM:XedFRYl#dX+c%0L+4:s'q8`IF%`l5j0d) + T^8n4ZJkf,-uBBe'M=6[C+R\dq`pouFeZ6H5XWV^:*9+oPL>n#eQT(-,\3IL&,Kp5BtZNCX + d5OlEd$2mrB[B)'tQ=rOA\\R:N,:mVc=)"iERs7/#@Wu\H2_2lKqr!c<@Ih''J#QIdl2Ub77t*kXOe(+V4J)HgcscM(p@S,da0XL].+b\,QHIR'V>V + qI>IOrrh8m)]Bqj&5F\!43')UKs8Q8O"of-W)X>%j<4K@GaB)bW>1;Tb*u?#<.Ep:AW7tjS + &Xa$=0">T5On/+a>1&%A4;*TAZ5XN3@lB8gmk_eQ;O"e:1<7#Z'M7db0-iZFY;pY5P#q-bk + #^hk,%jfQk\[)q854*8_H0]]+AFF>'l>.qk*KhrL^Y5OtpWL63mLId@*+O;!fIP)Y8j6=sl@Gr?A!9,-q;;A# + ggFX=usr0Och!q)>nm2nL"9UT4fu]be](GjGcMpaBoCU5d4]ifbHC2lC`2lB# + 'Vc2=eF5/.4h)"&5u + Q%$)UY0-KT;OU\83%bC&+liS%,0j\?h,[inY_$hb"!3TOX(o*$VOH$EdX0\P`pJA!]N&l6. + qL8s>^;F.:%Pn0+h&+hOA/X.[$D0<]C?YEC-A;'`__VaEfM,-(\f];h%[X1HM7YYm6\FLo' + c2S0X.6dlFM>X\^"]Y%+SbYk;g/#GB[bu;udHdTMX=0j)e1ITp0@W4JOfL<\;Vb9(qj4gJigqDKNZ + grN$']Qh>JNb==7T2aS>=Zt[k,=d4`fj&oe*8dBKuV$s7a\-Rj6fD.mmdD[7hV2Xr,TP'F2 + 'hZRm_Cuq7"CcpIBl2)nYnq>@9?/Ho<[[^XR]sjF8/.J3X6g5S;5U,-nY`CrfOm$k*>2F9` + hFLqnt+^mp:Qe;LC/i5jCW8E:7On`<=D`u^2%_&SWS/"D + 9(MYL*3dT3]*Z(gZV0VkPRKe#$p`#T6 + HguIbWJ7gCdbOD]Y!7F]D5FEN60#.b,%5D`4X=4b#cO9,Ghcn`;IuJA5OZL@&=oB9ghrT<) + k8]<\jj+4ZqC\;1(g.gI8L)-Tp3ReDlVa]uE5)g$cRW']1K]L(F[&iK:NKdUGbVs3H,#kqS-42R]R7K9`';t + W2Hsfb$YYH7!QZena>qX=9E`FA"eATsX-Eq!,RHChb/gpt8AturHk!QHeB%OuaUJfje.O_( + hT8/"8Q?Kb//G`\kfJc#adjP9l"i=696=cu;, + cF%_WBua`6DEnrURf9FT+RTr_X+JSl_?f\UlmjH6Su/K1T82qWY4*r_gJuCH`f`02T)o76c + ?Y_UqT4W^I.QU6j!u^F1BFM\eM569N4GS@S9C:7neS,,kOY_e&"40bWJa/`73(#j\3=Nb"W + =@73tdT43kf:E^a6a`GF/'[+N?Vfu9Cu7B8>[HeD-Jg6cDWc2:qo$@GSg@EpE5W!$V;46!t + Bk.Xue7XXF>NFkAEC;-cbRRCtk*:>['m^4a0f#!e3;c^pp==N'F.J$`N`-8WFF&/?K:TImL + ]lq`D_b]!e^[2!/HiVd3!a!VK2SB5po`Z@)"tPUN2]RZ51;6j_^UIEk8DABja>STn:,tpFS:HY1C<:&#^qorA^e@bb$od36h-OAU?RPMS1c/ao,NQj]fiCi$$gJUN>iD12)cQcIT,?MoSDpM^.cYHb"CL&DQF/i18='K,u`;Nbjr`>:q=/>oKZ-1b9Z + 9U9r2Uhn,?%C:=J[Z=!2_9hg71.[I$b'p\[tKdoKb%:N&3%N>2r'U!`=pnS'Y#+t\29Q*"W + 1AW))u^V3/ZBl6JB93Q8mYAdJ]H\%@OaIRaO'_TZs"0Hm[P4R)4h2=qrJi,FlW_Sk@h7dab + 2Bj.\mCUWXs^diGF:/#U9XWCq*0dq,Z1F0.fnY-<>YY`q9)/$m.\4kit#gLI_IF[95`7GF" + A6s[DdlpoQ:^!q2=]IgnJS\V(=_6Pl;4H.Wdji'qG`\OVo]^ma\M_E%lb.U2G#okNQuX'Qb8Y#"lsK)nf]E1riUgM')-J9hB-mfF23k\q*k:4ei1-Mo-4$GjXr:u2/Rc:O>4*Epc6$`UZ9'U#]0d';1r1mV,hmY[ktK($G*Z* + +)e,nk1#=Hd"!QpIcJ1=L>Y[%Z>:I5I1hn?pl8?^I1fun61uk+\ZZ\E8q`APgi%s5jea#N^ + ']cVj6J[8bCE2SE[^4P3lYBbmjJ;5)[.%VCQg9r4:Gu!E:/ED-]O`A_jYV5D7!^=pEnbe,XI0X?n#\G(`jsn,^[j>-n%G6-SAp+![^& + 67urP:D=f\\5^m2"@Rdq8:T\8DDrXotB31"fV`m6(8"S3>1F[fc!O`2T3^pQbA[=4E",q=+(80I + @SQ:nh'W@!:"/f@j)AjDE.;P%05412$/MaRn@m+ + mNhNJc+0MsU^a?h8hV"VtJ[([XAJo)4a![KS7\1/Zo\B3#=[:>/jK2W2T#o7l(!B0'\N&G* + WoH2XL9]qfNgJ3V+_#Pe]46%cuZ&4-4*I0:V-#E^DWmKbk*%UapFg^nB,)aO\46)5')-@uZ + !K,>`J#VVO\"jfPO&6T,Nc6._;+JoDmJdL@eC)ddX";4!'E'Y3o#U+d*+G';1H3bOl_#oca + g^l=G%+l\RL`g"0(4l]tJP05Z-Nj`A!\clndKgA8"/(1s+>O31^VKqI5YM_$"9[X+J7p&@# + R#_Znh<7s>ROm=IDBNjp=6#jLNg*=t_'&^:H!p)oAd,E<&hJiI.u%ic1r"E-RFYX[f]#hsqhTT, + <`@L1T__&CZiX:_C_)K5``Bcr.f#\Y?8HkM#Ka<@"()2KH%Jf.CZ#\9T_63q(oL,:rC(oSU + 6Jf&/EKRt$q63psAL&)'^+GK/kJes4dG(LN$+``/N&`O(#TS9ZW>+gSFMLlUW+_60?-m<"H + +GG+I=!333#Z`(%>dAqr80Ll_'aPsY0d)0*#Z@=L+p_&=KbW6m'IY+iJeR>k4Zad>l3L--K + \?]++G@u@JeJD5/qO_W+Y,u(KVA`DTS/I68CD/p+G(3h+WQ(GW$*$S+G&0JdMc+Sq7:%63np2Jmo!3TRp3R + JdEhJOFdc%+H4NWL\Q[W+D<5;J"[,D(4W$UqAt-\-i,3g,,i(.Nh>Oorf<]9$3$'ZkpcUql + fh#BQDQ&+@"5%dqJ(MWkPB8/-Y_jpTW"dbLjuAdqN??-BDS+4.I)efWiINDY^`]dqRV0WkP + E*:/8H`\[&p8&fRL$dqVm"-BDUr?0'g[R^9B!^!.V4cq[.hWkPGqE0l1VHae.p^rlUl"\c0 + gZh:hr+76?4g`Pq2rn_tgo75dZa8:aD\Hi"rJ%:@3S:A* + l6_s!.cI)XXTC1\;miV!!rp_*!-h?jl%o_7JcY3>B"8qs*oB8EbYl?p!./b7*r.'S!!?^M: + J"U6LJd;,ZK.&GZ+Ts'EL\_`-k[8n6U&KfPqAt>=JIs(o9T"W%.3IcXJ"kp$N!K27LFCOh, + D:0"L\a.Ukl?4/+o[T/qF6;j+XJDPTKgkLs%5ZW.M)0Q5LR@I92TCU-02k0#PqpPl'QstJc + ;*nqJ78<\i$AgjIHt"s%_VQ4V.2[5L]-%:]pY^8&Yb-PX:(\7\M + li_gB62n]UqZn;1."AJCg;B;1&n8cWMN@Hb5M4?_@tX`@&,&:RR1giVbc$#sOoEN/q^ruW^ + ji[?)U0/+3+kqW,*59C5_pQfBT3Ir[$I$,>'j$h_u,H(nhem#UKD;+EN_8)^e0CX/0Er`ZS + kk4g=pC]D<129PMuL;#Pg](c.0J9[een9q+r0p8:Qmjr`,IEKlJ^s`jkaa=U4b7+6B/FQDZ + :q>g&UXY'nW_Jc8u2q0X:Gq9qB+;X3(RYBAt]J!f3oA0%_XG7Nlo46LqZ%2l!"0-Gb5Z2SN + /q6,(I1$CbJW:cb"fJhjgi/dJapR^^0HuG;A^6d8ia8+7-k?[hrkN)R`ZhT#Gkjsl,dQc&_ + !.XJJ!l0$o!oR5Y+6W9GTD0W6+J]d*&8DXsdJed=q@Oh5:(Y8J8I;(Y.YUEHJ"e[sM+@CiL + +pI_6YLHLU!be?khLZ_OoCC#$p]W2)C._LP`eQ59-Lt*Fh@W"h + Me3@>PDs&Gim=-*#a.-2/?PnL)t9#Z6Ded2:XA,Tl[3Fse=`4D:unS+'WW^#(Es'%8h@8(B + t18\U+>iYd)O7h*]VMs&oo4Djaft+o<5Q` + MLS]/fum=fXu+XcAt$f(0;ZSUgaCQ.il4B5Lu!_4%RIHGDWn"^rH8L9VLCkT`_6s54a5(pG2u9kh="O8K`F0Q_ArGXXfoo`lRorYNI3DF-lf4JYrXN?@qV'&n:;, + p]?=<2ufjO8NLHnZFg8P*6n:Q$Y#Or]eIa%jK1gBp'6Hd?gX.-KP*"Pia70b0,KZbgHHVo' + TkRF&+MD2dUC?"-McT!bJ5b+H.8L\pc1I+S$ + ;_,T"m<.Dp/ELSGY\LP%.MSB-CVK7`sXJ\Ig-V1AD'\gZ1g^<1e9($k^c8*Ymh/1e$.fssR + #2U_lYpYpq_eS'6Wo$GpHYY0ZXo^U9#(4]'ZffuJBADHu]&C]tiX8k!0sPqNWfa^3%[@`ZqVnd0@-9UM15TU7:0'X'E_0079JT$,6MoS);sagC^ + LcC>KL3TVW",dY7CDS6JmW + ra@hf)2nLUaZ'<8^9fi/S6MbN@KFV0Q/mdZoU:R:.]-q(M"Bst`Gmd9bLWdu!%YdM,MWjQL^*oMcZI%jWXQg:l%?(. + Blif!oZAe4[l`fZjB]-_to^%D'm*@-OY5Z*bXdm*:m+TE<,VEuYo^nV5fUo6 + n:bcLcOgg!JRbpgNSZZ,UEd + e6IN(Q@^P9_C@uG+VQVp[O-fC'N&VPk`B:q%9(Cl6Oem.&,%`BMkf+VNCZ>5h#*h)m)^Wcb + CGQ_]3:-*3[O*n'5cGd\fRp*O"3+n,FLa"!D56+KE + M)1(aO"'`h2LF]'3^7q3_s,9h(RG;(Nl&i0V!h#gC0GqqSddR+-BUBF44hbEto/c[m#<@+k + P-0Nl,0OZ;IA:AK2[8%k(Ed$H[hZo`86IF( + V^g&o.gTo@9>H=G]*je:$dunJZGsT!R4Q_./J-3bOOCm=U?[p"lK$+u1?f9hm#BH`%eB9'. + .%O]..$BP0M^>!Ym2u1$B`dN&JGrm;]:hj*l[A,1/T8OOXDp+:GWE*Q.%Z*;`bYV5*ke,a_ + ?/[O[h7U9/R$:2,([VPk2fWt!WSof+I5is3T+Qb&msOmdP5' + c5),m"BMBP"mT/oiE3f5XQbqpS>XW%eU)b-SAO1?4U]PB19V6*_IZ-:c#AGm+irDVG%&)>c + GN?1mW*g>sCDsl8p[3'>]+1(t"ciDcDh&qdc+OgtW0G<,m"X1)h+nQu6OWOOE_LgX;$?Gi"Xh7mCHCCV&LL6g4)egZctb!6q'T![-]iM%OF"A'2WN5Aj + (FOU?7Q9k2]So0X3-M[--qikX9nO:r=iK`p$=D8heXEE7HP=]. + NO./hl4BYiNUf\Ei_VlpUFU;Ypufrf?XQ&/,9[8IlAk6Vrg/&MEQP1E@(6+]5ED&l/^4ZS) + s?1K)O8'5njn1I2]G78rY,'TY"RZVqSP=&fbu'rBe&o48[nBUeU1(:.url-C.sjS!M/3"L% + =nUif`LH*EY3>%<4;3IV-QI1t\q2q?GnYJ:K18C,3U[PNmm7-uZ_-<,B>Kp5S'@0oQd9MQL + er=Sgc#fnLfVn1dfMV(hWhj$ZWnC+9+:Y!F(&4kIWnS.!gM5PPMW3D#a!+7&@8ngeQ5_&Ch + ]oQU,Rs'KZq"Tt9&F_dA!Bl='NVQ%>=Irn"u]1FQ;L,s,=`MR7n# + 2;pQm,:G4R!+]Pos<:<$dDa_f.0[,YjF,sH>eS0+_D00]1FL?=7l0WUEr>:l)ped/U[q/\9 + B_bMqq6Qsp24o)4X`q%UUc3idb#:DP=Su+?e^)KFF4FO%f[eC$f.l5iF6?i8lI[cTfTGc3F + 89.Kr7R//g%#;RF:2H_%bgC^gJShqF<+br+P]d9goC$UCAU@7j[5BuYcp1FM]$!I*s@ldhp + >4h<^0$=6K$Eb7Q*kf2GUY6D.RT6#?5nZ'ROFe3G+M0B#l?4$\m`F;(7N+\^l;B/n!g^Woh + L8Ba_ZXm1fG7eGbQ + ;!lPT.mZS@QlrS*V>jm^Q12d<92Zh$\%e3IWnZ7dk/kE4n#Vb2PIAsS]3@)*C + AB_,8mRXg_PYqQ*Hf\S),>)dVZ(_qHMLle(UX4-msE`*Eu2^o[JtWbIWZIS!S.d0R?)dlP9 + Us3,Duc_=7)G8o9shXhiLOhlSF&H>dN&hA;a0P12aLFa[[joJeEUC(aiprJY!LYJBbQjl*lG4AlCoee9ZM_SLO\a1_UiR& + aRSSf4/#?)`Djjsi8P>p806!@qN(If_&OCE*H&YCRVt!]+RYQo,NK0>`ohfDqXPKl)Gg:W1 + FNjK@;i8p>$Wq6XX0\@?]#0[#Vcjm^XS7-HbsM;E8Wu)iPB4gqO3#lJl'+,qf!h87pS.X*p + KcHT55AJK=^\8!"dYARQIH/+$H97fGsOH=6(*8+)]b<1-(*+0R1_0YPVlna4.4S_RM&&X;G + +5TX$mspRlCR?c4:*H't!`JS5rVK:iPF+>FcTU8+&GE/jZpj0:jdjSog6hYa`+&KnNF%KTr + NjbItDF9A!L_Ru`;'abGu-L=4_hG]QTkUPHE2:2[`TcGR6i2i-&9m4eP,S%FNG8FBY + U:tebYHc^2NY>NrY;E2,*He42K08qbGN,4]l36tP@do:SCb5:Xeoi$l,@?,D@bh2;`>Q^$j + T2uP=(U%hoqQ#^%=SNJepj=$C3kY8L_-)*&qA^lG;m<%M.m'7YGZrq@]&?lk6^.82`1$(XP + MMJPj-9t2YFJg''D#O7!L>[Qflt%n2no>s%q"+9?kaDb>8`eedbHe56?h.,r/G-bQcV2LZM + C,%LS)^)1!3]`@s^KfHUUB88]rr!bAq=)(/qVG_.B.U-bEYSgL8=uK?Z02[[)&g<0Ms!R=i + \V[s[FRPc8?NIt[XskF)KGRKj5tNG;`&C6Zu:C[odDf=C[#U4!ojG/r#L1PhSL]/9?3pm%X + \27rXU:q38t(oG9abLC_4;AT;G34Yn^&Z1gJVU7K>(DkX])cTl\^:;jp%m?jkb%THW>.H6&26k&=^TI+JX + uo!4gdN5%lWi8n>nc1&>4n.>W7Vog58UR(3s/gEBjVPX?X!u+2oOG%a['"Q!IGbngkB/N.= + KA7aRCde[Nin[-U]o_Z.u*BgHV/%!Qs.eA6cNmftkkD;b$]&SCeq-RpTcTd=Spdc$O6g(3r + JpICD1#T+5A'<2Z@MXgf.3cZYZu&,"!Erj[PGTBg_Gg'G*d,%-4bN"HR'6U;9f6mN?LI"EK6L_q<;# + _0_-&(!]1&GZGl_%0ZS+m'&TJfWd)Cs3IV"?JgYE'oj$j.q8H+GTY7\d30(_$uJn>S,Eg2! + prjL`r>qAqCn.L/&-g`rn+_$nt$R.L9C5(SHK7+`[imlG3j)6Hg"G"=s5>KkMW1#ZQBii.W + gX&>K@V5md$IGKL1cJeK8[\03Bs"=0Xl63ng/JhdTU^rRXSJd?$4KRsI`H3bW9JbfWo+G&e + `*^`I@G(Kri+EE&=&K1ooTRjBS)PDYU#T:V&+Cp'.-m2oL"nB/0(Ee9D#SnP6>_%D080Cf^ + "UH5GJcsM*#SNe]+p\dRJJ>&7"=PBXJck3Z4G![@q?RQRJD(8<+Fq\_Jcc9$/qO/G+=_sEP + F;a`TR`12#bZ^$pjrP1+<5t6W#uq/!H^@."X&=f#Qu9#4Wo=Va<1hA!/Ma&9V?nK#QVZW.K + <7EFX9Qi+6W2#I\;JU#^t7E+nU@.-mA)3*qd)MHQ\*D#^RVKRL"1@80QuE*XEqGJfWEG#^2 + kr@L.+LLJeD"g;kGaJfNttb^phCq?V*aLDgG<+GU:0E*Z!X^4I=+fp86W$/*k)L+:KBcr.f#\Y?8INX4[a<@"()2KH%Jf.\E#\9T_63q(oL,MSS(oSU6 + Jf&/EKRt%$H3dn$L&)'^+GK6&Jes4dG(LN$+pNXlkTU^jTniIaJ"dib,`3eedJf)ski)N%+ + 6`h*OWWg7\@Xn + +6Vj;T?&('O9,JKL`h2?EW1QFq@"J03.IV-5(o#l(./@HJ"a.HLPP^K+6\N1U.AUIO[:NdL + qnM7nc"K&qD9;XfRKZPIZBQM5"J'>+HQ/N5LM7c8H\o;&+l8(&opf@8Q^J=;>ujdqH>!*E. + =_Crg4o;@SDWH2%T?-5LX$?9uHoh&+npIe"h"Zal,B1iVoH>qLB[Q#_/d=rh5,DLlc@#7O[ + @D5LbMh;M4p@&+qV@eC9X[MKr#J=YQf)3iO4dXFI7tri>,fYuYVi>`\Ps5LnEd=/5_$O7e) + hef:ttWuY`PdJgHWqTg8L7";8mf9g>bD6;@*5M#o8>\!_QO7gd_f1>pIF&@+`p#i!]WLU\skIoA]l01^\eq3XA"Rr]ea8s$1)m!l9+5#,(#uKFi\@O7Xndd + ('*C0V/qEW*'M%KJ5gSr=k=b<^4uJ2ho]E*^f.B&/!Rp8#-#)`+Y&A@U)WanO=q&nc"bCqG + W:A=tN1a]bht.@SC;116;(R)C%@[NNp2Wa#N4Pa81''l0^[SM"r-g"G2_u&OhcR)F)`!MNK + YP8')Vr,h2&X;t+'hadFk1eP`JL&r_=@+o\SKqR2Y%SlNqd?S#cYZWP-DA.S?u/nMu6QdZ" + E9M(&KL\fdJl[!,9R@?"pN746%bC=-4U1T%:O%)][Hs'2V$G-;D/gK1^6B&37^YSIS_=D*T_X@] + HMmlZ*PlQKf1X4=MQo\Z/t^d%2AS[7dQo3*B5FO%Mg+82GZ>0$(0mNW]"/deJc9oN+r7`qa67]`,KY.tEZ*8>3Y):5EEdApLU2X/c#qRE)R\t,;& + ^mfEdgN>%Bi2dgTX?6tORH:oX`h&(/Sst0)X/CplU$Mu+`!Q"iYep$)QtD<3Vjf.$M + >S]pED,`&hBe&F/CV%.PKL+3ghP1W\:rq![B2u,W)H1*CZ[%/ + k;8Wd1qJYpj6IUEO/WNS.3YW=6uOq;X>N@F58ooY$C]!s=IVrd[B'!Mn[U+`GW"Hn2=k3?W + hl4(VoQtjS6KO=lDpGYe(l<0Ub)-]Y?O+5J(F76lQ[_6P<'S\tjtj`*4!& + ]LO6r^dO*s7%.".b#:%]bWJd)4CcE"lQ[^f,u"ciV>JHKbYp9cA2:gJ4T]:['@KVg,;1Q:0RZ?\UO?o,rQZg)tQ!K]JYi^QR.W(TRX>NM9Jk.Z4W1ocMAb\J+Ila + 65E2%4B1+H=,5E5)g$Rf%3@/9AQdZbK,'25=BrHX-stprAm"a/Qkp]DKXlr1$FYWhIL(qu= + _G!6?&%a==G8"GB$.Kg8Ul*DD5=J_3MP#frMBaJmt9]"]9hNBl!R5idtI9TUf6kXca+aXe' + r`"T5iJ2eO7\1m']I$ha/R@f_4_5s-B\c"h:ff6Y*+eY'p68YK)7&;$]VClTq + 8pi#/N$ui;(!l@nf?j9iP+>FB10WdChBi4\9uhUt\>Fga>MG7F^0_icmo`4"%]"7MO + iO,i^9Uj>8'5cDGeVLlVra8^nbPi + W70n+%cYY+C$'Ar?40H,Iof;b$678D'c`?-omD"b+pLZ[442d/@k!^b3Ub'r@YZ40bPH]9/ + JFt67L)W2+qI<,2>+2'SK]uNIkshdg..(_DdZDc9CX2IM:BHhH + '_4+so2c@mf,XIkXS176pRAPbW\aKIX'rc^Gu)t::ZH$$o4LT/I8Cr5:b-qK5s/ijt+3\pKaRef + B7X1EsAdnQuD?*?<.YZ$7\,?;$'F?J;FZU=+C>AZQ.Had4=5hh_s>H8H"]=gm\79eipg[cB + &X2D48_6OJE>W^$G"\r<6:L%tbgkAV\P%Iso/]DkV4ZlkID9g[[cb4bReYUZkFjdUsgcaHO + ^%4KpCI,ZRj%a+FZut*0Ms!9_lFs!P[,c&1rG&_Rm`tcJ:CV2!Q2fZb(3h%VgX'j1\U+$CDl,T0ICLV^B`;8&8mbDXd(R*k1%dJD`\"-L_fP:fS$/n: + 0WFJq3Wle3QM3O>6ubFU@=VCt<0\g4OA4fM?pW`(.>dl"5U67gSa!5jLL3nuc#*BDk+3kHC + ogJpA2h*&!t5u[Zj`&5,*-+d,4]YnSTld,tkmn9\`?:V;4nPFAgWs + c:(ILeMYM"6det7buJ4jeT3Q9]idL_?/6f2h)/HNe6ouVin\0R?$0R>/7h"5k?Xoph6gh.K + PA/i9id0I^;GJSgTsqYh%MeYr8:jM60cUBA2Ih&L.,kbLLb47h8W"O:#9YkC+0h`[2ug(%!UVB(["NC`59fe`S7bflN*s38D-o + `IlZYr]BC^=M9Am]q5AkSj5Ha5um&67P=sOI]ld!YZKd#MSNVT + N"Z-!5R)fT+25en;J#B[Il8T!p3%k:>p7O6n3Zm55_t7k[`30M0:8=`2i4/XUTAT^A!ei70 + "/jWe1(jmCAS=p69W(>e"6IC[(@d^FYBhVq^_5[&jqBKGt]/Mca3*U%uADN1jlG)G9,8FF/ + QFKQp'pIoJl\9-kr@\6Hb*gG/DQ0Dm4<-M9jN\AW&Sk6?N"-; + rcR&@p$CCO"^#^[@9&q/:%&0i5-%]?XB"tr1`$AiIG!+.g$k$,jE'MFKkFqZNb"u#jL5S![ + gkn,\5*mNE=DF.*->u(Ebi]0=$IEiNkS;\^N"YuEK#<^'mfVNHdDqDlojlMdq\"+"D.3/lu + dpN*J;_(K^>9*Aj^_'<=NPN%d_`'nr8RT->G*@.oB'hi&5InhUC.:0BX)Uo+op)f/$g;Fn8 + A]q.6'o/Y-am&*K^RB=0)L`$oQrUN=\U;SAoE*Z'V4^]=BN^u2EdF:;@U(-oiXkSU<(.=m@ + !@X&`Y1BS9*`/l\n$q2@kLgXZt(k)Z1JVRg@0]WX$!t@N51M@V7"rDiETOCq>;M,&X^qro% + N!pk%JV2lgkSQ2^%"X#qYV9#b'*AA&_"Hn.)?p@rJKS>^4:DAq!5Q[O=8g/#F1I)Kn)t_a# + 5j%dn$"b#%J'[L5i29L)qkMhJ\<1E3#g$c"*hW<&3"tGh3ro,?uF%)Xp40B\ob/86k.HEF$ + SNlkSoZhj+4_5DAX=FEs$?rgX%kF%Cs?,[bu#$)eK<,J[PRct`J[/["L`7B>`qdF&YVma9LBCsMfIue"?m'%W#%&KaljeT5L`(AeQUi! + 7JX6q2#$[a3Z3FL*AY_58Q=q.HJX.]%@1j\oH3RFnASMEM+D"eaJX&bD;Lt)=),D4pAMOHf + TOf;O;4qJ7L4PR;)*ib:kSZN1+CsaA:*=*$##-4NbcZM\#T57GP/nLk0Hao##"bIuOp4J%- + lF.YOm!Z&JWZlK)*/mN=p@DT.Ni2 + h"t"W"s.ELV(#SSJ#13^@Xk7fqJ(MWqbhI*VlBNIJ#Gm6MLVSfqN??-Hd + \@\W[aI?J#^QcZ@AofqRV0Wr)1D:XK+qlZleU:rjJHbHKiYV9="&:Y=JHaJ$7ZA!5U@J62n + colr!c%+7+"Ha<0c8B$)mQ_`3.PBDXf@Zj6IrJ$b".:#\#>;cqZomVQ##_/L5rdfk$#_K!("sDtLKa7Gf+6ZgVTn32tL\`!DW-Jpu,YUGM. + /u^+6k + ,$W58J.L\d)Sl:OFC74b;Md[hQGFFU:krhtVKU`\lj9<*\FWtfZ\+6pdoX$Q`eL\eM&lKV< + K`I+m*+TGPRrF6B2O?_;ms&k!QB1mrO[$IH=+7!0]XeGa'#Q!:!l[XJf.?_4X1?`"rrH41o + gcsD@s'A(kH4T]92OD;W?]4u7YOVV-L\h2rlkk5VM:08.@h)rV9HoQV.R2Rqs'm;PNR*>?a + 4UhFAE3WP&,&mcfi\8cU]$P+L18B[X#F[$rLFJmH9^*Xs(EYtK="[>dTTjJ,")9c&+V89aM + Unj/QJjZQF>Ad0`NF$r07f`=P0)NASgb1[C3A_5KVj`-c>kT2^[P?>J#0!D="/2nt84iOT- + ej$,F&P%cU_tM_%6nZ4HNMjBR>%EmA+<3L;^39A+f:KD`NGo*.G'/#dY$Z.D&BAF1D2Poo- + nJ!lXFmTo.nGV9Nc]Mh]mbuk!'Y:\iukFhI=UXjb2oREA#rbu3(gO&CCn\/)Mq9Ffr3b/*Q + ^=V$8+-Z>Gce.cKo?';D3<),pp&72^"T]`&#!V)Fr/^IC5L8[*JWN2)5tER2OBDNKU\tFYo + HOTKj<0+POqU/m5!RF#s$Uh3'uK`U%,n9HL?Qj2UJ_#MiTr[_&IK^MBTWo?3<)Ppr?]DGRh + T>%]WNQUgmZMt)*J7S(cB,=65hl+DMD&cS<\Hu=sAdQ9sTn=W;JK-0@mJ#IVl+/B + U(OO>=@.8g)@a822Gl>B,5kp7W$[$[$aUjoDLri8QcYESO';+aDS.O@Ep+6rcRX;P:oAW3s + ]ZJJj0Q(gLoR/^?qra/>JM(tkqb*bneJ$*ej\n6WARWDMFc'c%!f?!u!A,Ul%)8S<\2!CK/ + WJ-E,)F)l!s'dTdM9e3J4m1&bA&J8,&,&CUfd-WjoF?K"H4rVJOT/pFrL4>kEC;4'';Dj>T + oaj?6O8<<+7t#DdQ1"Mg79W;"HfhtqHHVWNAGBfNgg\KE8(Wr4/]IbTXQiB;$oT_DhJ%be@ + M,Jg`(mG7<#Ij_>dO#c!,3`9!9#iiE/aL@rp1dZar3H>3ft(F]H5sR.DZl8,[V7($XPd])$ + )7)5h_srk[5k%eC`QMDh?eh7[h.A1X"1H`qV9SAN- + frjG>8qS7+ND=,T[\$.mu>QbCc@(?6H[iXVc\31)"EZ%6KS:B?VX**B;/\=QU(8D^c5OSd8 + ]TDt3??CXX;CkB]pU9hR(nVK1U/O[`Ah=Pjom\Xe@#Pp+1T%\15O^Q:_,rHP7gpH1e,4J5p + eqQ/N&;_'"s$S+:.10@7>W`W.$>31'rj,e-:e%h``U\/8dReDgJjO']RAr'njl;s."/%FjBU!4>B + ;V`Yde5+8Pq%kWK;=BF]i0N5C8Zr>VO(Ng$1o7nYZJ1IcK@8COqkVc"k88\X>aCDrq52s^KA%7M^:#)sCOKccihP4]>kGI,e*d]CaHYrgCmK@ot#d]<9Zj57BA + %(@!*jl7D[>4Ia&9?do#3.4MJLbhnCOHI`7"T;I\;2oN#WB5TQK>&7jm/^r/$+GBCdfsqL5 + pAfk]FINGj$E!k\,k;X4W8Ei/+V(8hQWkcChp#\A+uTlK$+R0"/Qof"icg_6E@oB^4rc-BD + sqO/t8O%c!/Ki5@&[`2OZo0bWq(.dq1[PAFipXD\_I#aDM$a/N+\.9c8o"eEp03.U6cSA8Ei*-;A%%O4:(^hP^Yl3E"]9C:9Dq_g]q0@:!!H/mW + T$4,0e\`%GKY-2R%t"YnB7Wa.hH#o`U0sHV5k8%K_#Q#2l^hZcCY(;I\U?k2F[%[7Bksa8" + Z3hW#)'#Kq(;96c#J69oEXjKOZSa>CFu39>fGjj%9A$`JbPYptcOL/)dPE3d,)G.b,lkX^H + lNf=H?gkgsN/C']ANh5Mif"Yn0^[g7I#g2I0k.p35_._Wj7.T])bn#a_O,PiTcIu-uhX3** + `+^(,koB-q6LR\F&^4^JN,"R&#$.o7nF8-Okuc#J2Y"n&ndd#\%%*B_TeqfcR'/F>Yu8aoS + BJ6BoSK[AcVYHOba[tL2U>^"mpd/-jION]SdFKPC$bT!LUhE],UJ3_sc`j2W[+&hd)pc8=#.kjN`uL/`*6-5D$?C!gf):`brR'J>dGh+eq]:ga*ma + 9s#7VbIWc>A,33Z=-E*"?`dj=Kj-88nX0P7]TnL!aD-STThBEKW_C4R"K#SMgs;M]o[ + N4qKbC3h;Q1"Z@1(2hk>$@SNdsW=]ds`2/4c$WONB'#b_f6D^@%ZZE + noru`sraD%S5,&Yj3q2mk6*P05Mnp;Z.-T!>#nIOE1]G#o,/a%l#dP0ki!iXB^rf+VGG7&l + U3CF"G@g==;*)f0,4^peo&[1lZVM;,;ON_M'm!RoWMpX!`:WLu2Qp:l0lK!*Eh/ + D>(R'7`dt"$PK$UFj33eB$nW,[[#ruie$,UERlbPr)fN8+VQCg + &=$02Zr/G#0&^L=edlhPcrN1/iOl63njZ\ZWrlps!pHPdKs5MQ/1'Kq-$?NK`!>H7& + O;K]+*?l%<,"HJoO=;C#/9fGpYRTCE1-FEG@g!E5"B%d;&krMW;$@3@"\U]1NXmHH'K\![- + BMq2N[4o?.Qt(_#EjL*XucnA5X7)_#dTL^c;=mC<^O*_$.>M=mUll;:C=D2$M(KX1:IX3]* + kQi$gZ=+Y)t9CU0Q@=O[05 + o[&FSXE0p*>.eJ@WD,4J$619i>bodK?-1g%"C1XS?B$$S4'75U,tQuPgBY;l.F=S,&:("6S + ,'4dT=BblnL(ro'pPGm;3R,m-sl=;Zgmds)&PQmSOD\ZP@B.&T8B + un$*r''.7_K,B+AEnI[JFCl*,TNt_7%o!(\a(EZUX,4i8k<;.l2="_]O@rlQi(:@Xo'k_Va + B,>K'2t(ljF+kH2I/#FTpkDXgm1f@,QT=N)d^O,C'Wu2%`1>f<37.rc42F-3/77GcuIJ-@Ac5bh!E8ldcA]ncI/ib=45.C + 6%\5#TUns&6/RqKp;jmH\0DJNpMWG'e_kB*tCFL6hq\@jT69Fd6p[]<*1Y>"AZ9fBOVBZ!Q + G#4#$r0$_8Kf$;,bb3]i@m;+e"loshIk:mJ5`E)EGY4h>5,4I.'DsVZ:cP&*1)/uu>E:l-[ + a&Ymhp+L,=YAVZF;)ih-Fd%rM'o@)KN;6>>q + 6Qi>eXLatT$pbb)XT[,26AsD]6J81>ITZWk/hmEdp0AQPih4V0BHKKX-MiSHOojW\%.h!^R + $\^QZ-F.QJpKDFg>p4Jts9:qSIBb#Cr:4Bk0#qRUYT_>7sG\\m(nV7h.^`"R + QG/^3NKT8)N%sHKufT_IY6P,RFUq!4`3`-Ktoqe%_PWE.af*/$r`MV;0EA&[R0.b7,I5MG8 + W&H-Jf]>"Ba,[Q6c$Gj<=%B8MrtlUW=0I)jO+jVA"d(O+G$,cc$71iIWN<*YP)V[&/ObibW + NEMEPEX%Ne'4*aDm#L"4df#-q,"$$op(a,Q.,8h$E(*GBg:9f+;o/AHOW6jrBWGl6$\#)fn + CV"l'Sh,Z?_X_<&EGC38T! + .U=A;"&Fm?_dtmYhM)>*dCd#D?T29d-:tVYaS&^EZ)2g?oMemOL358A$__[\#1[LX*5G`>XHe&ckGc)u32`7<*qe^:Q<;gM/fHB[`Bcge43l, + K"U5Sq)6r,Vjb%q#6_?o/gN$KK3L-*fOlIN4KU[NWbZm@##eZZJ^[H*)SoXgBuRb?,.Ar4B + ?88S(k>AXcbPq9\/)eOTGg#^^,q*8>+*P@pA'KDFlr)=^IE&>KB0*=j4d^)I_;?i>9UnDE> + ljY*?8&3O!1i*U=8:dMnBW)gr#)K4nd-rkK%1<8)5gXYp)@?\"JY4,uq^`0S"$XNHO>GZ#o + l,JR?tY95h?J/9^s9/?U^ZDg3C(kL8/]8KDh4CNB&%22f`O+Ibtp2k=pAYkRG_[j)3tJ;d( + mkE1DC88"#+J_Ab[-h#$leH+D&6f%(-0g^rm9E^A8%7JX'VS8/Y/,;WPX90J\:iT*$H_TOc + [m1'UC&P.PZg9FR$c,J_CI1,#(#7"LHXA1/<#hZFuda7(hU%!r'tI\:2\(j(=a-l?q)TOGD + 9)^&Rh"r\UmS/d*78/PfeL'SW'$_UpK"r(bC5iW#-s4TO=2m#phHJVY-Z1SA,R"pCT,63[P;#T*u$J>a:jJUhga"p#iS$d9feoG%Tt:k8ZHIirCh#(@\-h& + M!<8/^uLT*Q>'9;#q'#'uqTU'>n9B9bl9SgYK7JXu!Bh,U+\C'Ji(B3GL^+D4DbJXm&ac@M + M,)9ZB[B-IP"TP"lAE1ghIP_#=f)8(NiW#<-[TOum^D'3H5#&GDo]tAoba;M"/RYViZF.d- + .#&'ZAJd,lE#T9.`RA_!jJXL0hQ$o<;8d8fKAi^-+@#,\XJXD62L4P^_)2!^;Ac`0DTOmZu + ?K2;/G_)2p)0CFr-lI#eTOk\=>9ILW#$PSo).nGc8/YlfQ5Q\,=.j,F#$.C.@KqFWW&aj1T + BKGWL?Sti,)N%mao75@kh5rqTBQ+MOR!2k8s?)#C&XD?l$<8qTBVdCRdCEmEh0,kqL!dk-i + /RIW2KKPJ#PNPQDUYHRJs0-lDac`TBaPtXe4nI'X+Sg)U^GTBl=P^n9s2rke>e3tfN;kPH6KZ7#MrJ$Q!L0AWrcgH*ZfBDY)H[&?)uM-5Loi7=C_;=O7eMtek#gDEoCW3oqJiaqU?VQ>^rlm(%JO7h3kf6I=%1LYR4c,]]>+7/'c5+J!Apk<#c!iE,HE.\f/ER#@dr`tpSo8GoZ6fWPiRIi\@f_Z/_s#U>\m6;uXrEm24IrG#ZStZ.1#Pme3$7AJJ" + sjZO.n0nM%M3a7-L/)#Pq1;ks0`p.'"(,`*/(]H7pTGrg8K;A0:')1<)l4)P^h\NQKOsVd] + Rr,G]C@n`1n7\GDn/qMJ.-6:6h,,X9eOs&.9#7EG9L,il%nP3SEaWe(/LV!OV9&rKRZBi-> + pd/R1"rEi1]>:a?U[?gCG>cco`Zj6HUQh'u]9M(4!-RlOkWd\' + s'Gm,I81*`39MjUSMR*q&,$]%fO4_fe&$=T3U8ikbkYb$rJqK_5X3p:!2&lnK$\fW6uWqB + Tm6UL=*!b9#]1$S)DXe/r.!R]eU&rk7Yo[8,:'4Z5OZ#T^K9tV7;MmgP4W*'p_*a;N"m5*2 + @WC&au>CZ-&"%[FcNtC5[i=@LZApg`,Ze0id=ZLA8Wqsb(3G^JcC\6VDaXdHQ9(4BW`XPs2 + Xp?+j0UfOd7cD=d%uujNO0Z-3V-,CM@Z=$'mgHc*e;TX'Zuhd$6T+/8Ei/Y6o;54B@L[TODQu)[.PPUP`_k + AO1D7D[]-+JEg\fMD>A=S?980K&pT7U&?sVfq8E$TG*?HUQ;'POKJWjXs+1_5m02G%QS"\Tb?R_,F + OYRR^p#rTo/93Rde23T:t#4Y)`Q)DJBV0sFnC])j + k%'*t@k$DX)tPOl2o@7(_r&0r2,4-E":6:JMs:-6Tj451UJdi,%B_%hU>,qHkfnl;t.4[-`-FY(;nBD43fUuB!UE/]btuV/(:gKDDOUt1Ls\&H?26-3@A;u-Z_F>oA(e# + hD>:_1a7E+6tgsF6=FikU=(-)ADD7o1q4MVPu;J[4mUu6WH>XQl>7Y)Z*WnK + 3>U_odTF>WYBWaiOZGg?pC*VS+_A.`'0*jF=V#bI40]5Us(1!jp$9DOj.5[g + WKlOk?_ALpo\*[o<_cn_br1iAZkI2kt^bqSjS.a<$OoNRNBe$kt8?n1=,"3'cXd;hdSqe/s + :n8Y_-7_htt:*A+8kXj!BHncZK*O[9uF+HkbW1R+Q]Q+:]X/p\,4S>Wol'tL\$0%q0qqAMB + a(chbm6L+3;')&%EUllt!\nj/U\g];d.QX7S3jYnTHNKrU"J[3FP@Li/*'>pD3AA+Z]2CdZ + r'2M/5pRXA6n8or;\_tn]Hi]S46/mdRSC'"aLiEg]IUn<]-&D0,#$J+-)8ODPYa,M?F#O;] + ZO]rgWmc2/LGNl9k2TuZdV@$1FDEF-MuC3"5#c$>r/3uZbgq"abi79hSpL#-gO,Iqr/J\j$ + #kC1kLIhV!#I#5`i5[hlVG73O[det.84YDr,LI@P,&^\!#k!Qr1jYdUTK83:[Hj98(Z#"WI[aF"7aN!UN;$7jfe8A#@ + %bRI+rj2gN(Sog&[%$FbRR*qM6+Y^YZ]*#dNXq?r + aoij0&dV)T,0D_eTYr+Y>F%9sV`BkK6B%m1RM\Yu.n[H*9$/-rg@HKkY1kF`!a&m)n;\3_aHW*6qU!<>8 + Op+^J'9qQ#oUAUe8k:)bg]@`PYSMWaLn=r4Lo5r/CR$Me0\_V79nD4C2-1a0rEaZ7@` + (#XP5*JgbXh1c.lW"lsEK`H;4i4Vqg9$/E92^j,3jQic?V9[Q + W7bd?#l)I5LQHoq>^EZheFE>2bFO*lj5A6]SI!@l7GoPgj5HK2r\\^SRW]!dfa7EsP6ib:B + !QZG182LFi6j0&;"fl]`2]RW40ZZMLMEn9N2foJ;LseiT%`n;Q\',FCi7pmT'1k>#3$]6K3 + 9EeS(Wh@I\9o2)oG^B7*(e9PakRq/llR?4+>*2H\Kmo[39O(%\C.uj!85+t6,n*C#j23uQbe.@m7-)Y3oZsAhd)?^H`?Ja01FkT + Jcco\A(K=I1HrsBQeO?7aQh9%O`8&n$f51;R'`4o"rQj525 + Q,rU"anZ1CJZ=,:bgBp6FO[H"ude5fL6(u<=--F$b(MC=G72dPn#ac&3&+$fYnHTeIoA+'Y + #][=ToRD'c/iG)*!6!fg==Wc'C?=*mrf2dI!@4'q3PcS"R0ZY#H_#l^1"e-<_-3=sKP(X.@ + DPUscZId_hcqo:nqfW7(XDdgN'@4/g>&XOBV?do3?cK<@k:8SIrZE.#*)ph#bb1/r( + ePjsdPL[p[cIIp#eXP72gY5Hqdacmse`5OV,N-j1f%(knegoh$CZ[IUg9ee5?-82A^#%&iD + I*cg:Ao#e>OaRmEn:0[f*q;ZZh:`KU";?#5F$B")uEF=GYc;(2I1W)m<]hDHn,=$=6",470 + D0O"P=Z4fI[>13SN+X]f/l5aMW6R/VpJqHFLhS\(\sVb0)aHJ]UiC/IdfD,DEXLRCJ6?dA< + )TZ]!5MQVl04dGj$"'d,Lf,?_u0g!q=XD'[g5-)!IKY.L/`bcD=R]?+Mb47bbhq`/R7@m75q. + _qY\n>T-^L.jRO]`4W0KeFgj^"irgna]0q8-C)b1'@T*6fL$V=XWnuQXWpX.`)R3l@!io>maC;X9BVD_1V2g7.d9[>]Bi&#!ute:b-C@g>SA=G + ][&?6SQ+Vu@q=&o^,Oi:0BtCH>gB0Ub&M04>homgj9g0IUg[P(XCOqSC>,o&Ud[l`O14?<"sg,hf`Qi?=m$BB0b=t=IoB:p&38IriE9Ki!g@X*>Ms3dHrOhd=qhHXp3 + "bfjKLRm=#CTFW\.6+uqR8kGAaBj-N)JR-i`BkNeW#r@)Cg/FF7M@Iq//qH;]Zo + W2B=IUkMc(l@Ke^M'*iEX,?(`j9BINSjM1-E5MLMtDZ.*kG*G[1(hm8Emm`Z'ogl_`9KZYU + @j[^N6cm:TbAX8M@r5(*oMn$arF;Fo]fr7BDPb=]!8RiD8Rn[k)93p\eet0;#[S<`-\+'?6:F0ppSl/ln>2Ef`??*LF + FhDUMZ0/m0bDB-Pt!%3+\P$"mm,D2k!*WB'2ji);Pk0^-K4R`Vc)W + TDE\s%>GgV$12)%mmWG[S?*@1LY\p$Ukf^6ph)f<84*7nXFNu8=*[oMZ.J3W0FU^b-2O<@c + ;f>[OF]L52[oVsO9m)Jf@p`DX[E/$\39i/&n)c]3Ais(B4YqQgFsYO9^!^jX60bN-lFgQib + [b[0fQNP5<_fm+^MDDBCLk1t?1hsh#.EUSiO)\FcQ2&\2S)s+'3?IQhKkpd>kr1'=C/`ZC^ + k[[V=*Hk)sf]gn_RX12]ljQJoVV"Ak+'3T8)!8$eTpOhmR4-[V=+fC;D7C=PkU\m1e4PdGQ + p$\7T^-NcC\h0NhI3D.T%#FJ!E(+)R?$dLS4X5205sgiJ1AF-NV?jX9lSUJdYYD@REF+Fl\ + p5R7(=#U"^(i.:)7FrLPo5m)'ke.=DOJd*?KGT^/q'nQT70L2->,m4Li!YVFS4pVXM"(6Z# + +>.F4"[N/C5XZ.o5(Wg.J63p,#Qpj89Jj3Y(aA,DlccJi + GP?7f3k3"E)$pROBCu#hjkg@#]se?X!YK5oQssU_0N5Ji'-[(aD?QcelPVcphg`R07*;)-j + *b-4%\E1#S".S.UY^@R1iM7MHGehL[F(MteLm#efiG(Q_)@&Tn4]_&"1A,2NU6Jh:Ag:YZO + oJegm#@Y,@,+p_8CKlRH"TS6h\D#Wn]3[0 + hKqW$(;U%VR!GJdsVh#WNrZH3cGPK5EAq%>Z.XJdk6ndnq6?63oB?K/*]fTS"OoJdc<8`.A + CG+Mh8)K),a++G/ka/g,c%Jq=A$+L6S,#U$<^+G-m).\MBf#UuEuQ)]EC-m517$0WM&D]jX + H#UU[G=pQEZkTH%?#m_Z6JdBMAjF;uA+GPIR80EP5+G'Y#+/"2U#TfXijpH\FBHVDK#:L^7 + LEM/Z#TFn;WX'LcJY"WK#"TkGJd)K'?]cI^EX3GRJRSm"j_,c9Jd!PF:kAi6+AJ=JJLUp<+ + FtF:JY5OX%"FrUq@nFQL\`$f+pa>[N$%8orf&#`iVnl[klLdGCM=tdPU2+]R!SL99qrh#hJ&cSLHl7r:6De`1;V^`%O"K8?C_>^PYlJ_`GEGGWoZ7Q=Xc@;rdqUg + ;"a84_DY$BuM].XQNrk4rinc$o\_ + s_P]0BSffUXXr'/Zos%igr5nEVo5L_N?;$naA.-2^=e;4-&KDeFRoe8V[e)rJ#]4AWsAL(PUaLP.n+DAe[YW\6iC=%omB!T!<6/!a^Qf4OL#2gb9-%0J#rbN["nM- + +7!*=XbF-k(BFJ>j8Es.ouKAL0`PDl8TcZ)gq4Gj73IN\9M0#ks/)B\s/-q'g,SKsJ.1dbfgtS$9D[ksF2o:kFb%Uf(mL@"B;R0?Gqi)]ZKR]:Br`NKiO`IU1bdk2Dk=_cR0&ulB\i3% + ASO9E"Nk*aYOoAh1q2KQXc.fjsG4/`6^GDY_c]@ZanQmH]Gu$0X4U7Wr8,9J5k1/c\=0hPV + led'P%"FdErc-!SaaDF"oY.fgqql\N+6R0aS[&0NG#G:PcJ4KGDob80ZFgD5LUJL9V_PB`e_qZj(rXo0uZ + 27o^4rmaT#%Ui]G2jq]Fl-JPdZj7?@*[5Lb(:ORb"naS@&+<9X?\j8DfrGqCA=jIVSKMGYl + 9riF0:[?VArsd+o];*9^&%2\p.""jMZiN'Hc[DJ$Fk%4t#FjTG.`a11C1)# + Q$!E'HVtTg)i^rSJ,X'rLOPnI*cuQ6YNSBUpRRs880(jC/%HmSZFnWS_B8p;Y8ZO`;7"Z;Jk:lHP>pFbU` + peM4aOrm(?Q5L51Z$*;23/8;u)5C/P&BFb2]_A9K`1,DAdTfZlpW!$d>ON>:c2((IIPDB1s + +#&0"cY77"=Ed(*/FM&_>$M,a-cIPPT#==6iRVSgcpU*9Sp]F>trEas,(f&/X$fW(b1eOX5 + t2u`n9;l8srV=$EmTS9OTNM@BTO\!hBT3`nBMOP!9[TA-63!bQY*Wf + 2"&2Y4O[leU:8Ek:;A$T9eoaD5C\5TMlLJ;`>?8).9u0R@ehJ3UIC + DM5uoJ^X^hod?o9.kUM2[->mI?"lG-fhY4kd<*\i[=N\CL2NaAq5eX#OXR&N]aeL,e,6NjJ + 3FLkW7fUP_OQfErMMp\UbOH$ZUl3 + Ns^W=L38Belrkj,2&lg,IKN$+/).1`T.O3Z7m8I35U%)c!OmV*[/XAG(==H^u)<:9[Jmf:A + ,9#iAUnE"i`.:D[^KU0i@QOb?EmjOPV/BR.:b%[%1V8i,q6Ha)EbNZ8(%o1?PBCum8EjS?>Ks]*:7-N%:n%Neu+8^W"It>B(FQWk,ARcro0q-lCMuFUAq6nEXK,q/Y7"mU= + sPpX@GUYdM1G+;VR2E!UANb9'7C8b'-S*h(UOdLPE#G38On+hG*5;.h[/d)^MQZH]@n+.k5 + p^146533URC90P%P'k-X=:iWI3[:+6E`@Xr6/J?CdomQ0CtLpuRp\8m\la>W,i<=,^nKSuN + R/n0NpB'->!]-qF+ZF&eNHKWS)$gZ#mbLJ.]Neu&F%-uu3X6b`3U.[,9lEK3^#g0r=cKg/; + ld!Z(@9VBbhem$BOO\QpCVr%.I + >B[nFu'-pb.C?/InGu(HJ[`U!K,%dA53J0%1E6BTK7DW]\cC]$t1EqpE:Y&]SV6b5@CIr5Q + tZ$?4R5D&r"a-njO#Drbiam/F9Zrt4nUdJ2B"*?XbM+>Tokqp&"<> + .Wqp=])XTN]#+HQm[iLs_13Z5@0*fcZ5-fkJ;Mdq>70qrb#r7hREghYZT* + b(`$7Jm]CT?NWD_!G^7I[c:Ye)FLM(C?u/9&UcONP9/`p'_Wl3+:Bd+p;gf]s+2lX\U"nF& + "elKiKbm)8oX&HORbr9_l=mNj580bZ9a%du+l<3[T%;'duS8M\[F1D)=+OYk,i(@fj=ng0b + >;b7[e9UO:+'baR^8Y$TT[8d`/(,&H!F)&qf=S;9-p.XR,d=!thFSBd0pVo3QnW,[fLA9/` + A^R&0&YV6X.lrfl3n9ia&[;-%[9@E6qied!'>n$K;d5I1>K4ci$?#fBaO]h94r)O18uDX5R&a6TX0;t=D63gq'4;Lj?qn=BPTaGTD.*e?!qmJeO>fO-,=@bDhNfZ[2D + 0=l19rM.i"B/MCH5oU52ctf-E\>r<`6?.-K6Va/f05m + L%K9%o!N`ui)SS0jRBPqU![&[m(F(m/B$eCd1E5bK + DV+`eGl#>#6db/Cmdqa'VlHnPV1@&a5j_T&&lnJ(uP5T5SpMG$Km?%V?o+,^r$#XkomdV._ + 9OD]hAJ01_n<#A%G6LmR#k=5j;caNsG8//]96&98'fAR'F\Qn[72>8a2K)ModqolQkB$6?N + qI=4F`R42K(kIeFZ"_mFbKOPPkaV`FtFdS2er1DX*6-S)_F3se%:d0Kp'p)ePF38WbH`Ueu + (Hr4j&DAOm-/>;0r%>?7M]&=^QO/AUG6bg5lfulHbep*3GWU@&iI>dOq^^j$O1VR5.%3fpQ + S\J5B + OYQ:IEdA"0i>S*O4bH,iEXb=B+g[p*@5FGHEmPF_93\N/bCRs1IV77pkaRX+\74])B2#gN%@`o(RNYD:,u,@,_)n]m'^_Ypo:q6t]6Zb=qF+4a8Ar-XV%jT=;^&!$ + -H;K];ENL-Ge$`@)\^O@^,X*0QQ#H-:@ii$W*%XC387G8hXqibF,sOHeRrt9H,-m\Wg.e.e + U=J-"i6Y<=IQo`g;,g%,HQ$W_UY?^'=X-+J]$3r`"fba3Al(E9+4(U92BZ.sstr.cJc-"1",aVGi;;EM3!40r1a6l_sIgHB%lVaV + K(7K\?7KH\Y7 + As.FUDcs)^-'Zm%Jc_69k\c!=[eDG']VkU\Mlkk@MpkKC7[;DHjD:J`+)o&2YRdSh#;)k;6 + 4\9R?9t_>@]i-`#PqB]*>>m[l1gB']S*ALj+4enB^D0PC[8X$s=fEssNa)Tc>Qn0>T['&:f + b[@a[o'tFZ]G]QOB%4#MA=ihBA1!GG2+Rr4gT@$dulSfP&\7So>SX/iB4^5*?+0I>4'9DbJ + d?=Y>aW?[G-s,<,gMn5F8k9S8BBq%Gs0_hj+2C3u_RTKpVPgaL`fdglm24Oia(K@[s-[fD3 + R95N9+5792X[H*Mn&'7f^dJM;#M<`dLg>=Xud[JA4%DEi`[M1XqEc.7$_)f]N&FXgU@8iqI + HoVp.l\%#J)+:4,3rWN6p5go-YZjeMoJYaK'3#YBnOc$s&&2\bD*u9)R]-b1u"[8L`)cgAq?@XAkU>V`re%]bV1gW$3jjgQ_7pB)0,pc`k + ]bo1<^03""WK+AS;r^##p/+W#T-4#KBO.7JV12<"qDb`g'/!/@*Cle + K*W;HJV(r[.Y326=p>;+@$1^"TO(`7gTEV]kC+CIeG"<_)7OF_r'(^bhEL + _p@FTO8B:!4Tfos"-lajL>aCkOJh+TP*6gIE]bMoRWV_)=W3Ko6LUf+D7\YH6?jh#'j!8)< + -4=#T;KMS^\P^G+`JW#'HSO;?h6ja;N?USELj7JXj*Y#'(i!)?t1(B*ni^<(In@JXa^u\q- + ?9=pAi:B$pm"TOu%FCY$QEXFZh=)5r+TFnu;V+D-K8BHUo8OF`h@)4H,EL`)M0R9#a\A>!O + $#%O<<27S4)W#:DBQtR@jJXAAW#%/Qbq?C:LAaSE,Q\ZN&JX8nFEe0Png'1cSA[2MDTOju+ + JX0seA:^$p).A8mAU4P^+D#9lkPBRUW$hFrJ#K:ANdn#ig6SV8lC%XN+6oj)X.S\!riMgXmhi + 70.iQ]_XN11cJ$!A[g4-7&g>]ZGX1J"SY=JHcJ$8&4!e7G&>7/9Q/6a0FZ,c_cJ$N_a.Y"c + &gG7$[XSYJ:Zq(!cJ$eD9;Lc*'>?]Xe/ZJa'+76W"`kg + gfMFE3Dhl9QNV!.Ue!rfK_I7j$tB-D\#;PL>iu8jiP,O7]UL'$=L^LUqQV.-b^ZZjriP9S\QQLor(++\GobXrG@Vg].t/uiEU/`FH?+A5M'$;?).@BO7hNk(Rk#'lfESVp%Uc'q + #=_HrIL%'$T]+d$"7X4J$@o2`(0\<+7)sVZ#Tc_B?M6(XF64lp-_-u.0!i + &SCRBpo4c%l0V+7/?DZdJcua?bkj"8n]#np&qoK62"UiOq1ipeqFn:*8R`_)N5\q>q>_W$$4=U?0a=<3*eVO!J"\%bKa7GiKWpUR6E"#pTl + MD#ka6joJc:P#X>G\Dl5i=VI#\I.3ZmSTJ"u4c&L'V8M30hH,f0JDL\ai)O\RFGOGan6l4M)$E6c9KcSs%S.E2b(m?)rlluNj7G&Vr@WJ#Ps%5Z1:.N.1%/n7#4`.rCRUn/L.'-Ocj` + c9?ESWWJC>K+6ok%alu5C,rDQc;Q3q4olr^OoWXVOcD1hhZe,"[OS!?AiKc$XFdJm+EAPR2^%]GYEZr`c:s/Pa(XgpqN=,U + L+F//`>elpC'>pH/IL&f(OdJmHeSTV+'dFqZs-tXL`s0),#_:VhFnLQu)230SDf\7KY?CTE + LL?RJ6#J<:feXWtlOn)ZhS9,79miV7peCqCsrG?Q64GTX2&,U'XXi(Eof'N8UW#e1k"i@d9 + )@JiHP(Jd;+!:5;B;C7f'RWbMP>+M_ZRU4T[RpX_L]3.%OBho[j5].M,Tki6NYNec1 + WNHJ9'lB&l[T-@K'ktcJLp].1C9%rmX"hu%:;MS)34F14RNeK:9;%g.\2j,5LX!A1ka39^2uqi + IrV#d,'PXumph8e&=7k+N.GTc345H^Z*^RkED3Y50$>*%X,H*P)UMU'gUg)Yh2XV'9-@0=i + R8g*sV$.ls`3'(IY01,6"#Xs6RE,?qC9UTpShZEUo'0\S]P@731t6G%j_,[1s.CV,hk]VMm + IZ&2:2W_Y_h=?Id+]JCWUCEY!N`g.ji]Se'^j!Q/E.7G3"VDHK&_IbR_B/9Zk4X+Z)1G^B< + 2(%oR7B>%<1YB%.Fu.!Z4i)tulGmuQU2ma*sETesam5!1>ED/ai1Q7mTVI__6^9Z + B-*DP+/t*D5R1;6XS&1ofTp"o=URr-NTK3c>Y?E)&H6PCA,!&r*__V.aP5`WtWZoqN_f@FU + &i([g3NusM0SI&"&ii#uZU\%@ScYqed'<5^l88itM96us6AlPn'+_5/[!] + KAim!`q-&brg#N4G6M9@U??l?bF3k4O_SE6S0X#0.)%nQXeIW4BSpVDR3ej]lAQcK@r]B4" + "f,:$^T4X51JU@C-r&1d'e^,(i'8j@3WM.!nQ]Hfq?>keK:5Z$3U%CKD(!*b"Ce>"K"M%Va>d0+\\jfdMPTX. + n[H*9$/-rg@QQlYZ'*ns6[V<_"*1M.?-I47l$7[`;VG7r.iLI@P\6^\!#k!R&7kYg=>*5W`h@jFoj(L/;B"^k6\:KSdL?MU8DJ5g+D3, + `Y.VO&5Fq_%>?e,a,u#PFh]:_,Q]9@Iq*7.\K + iB03,2,d + bh]%"8hK!6SL9tX_*c!%f^?C6CQc3.P# + &q3S$@a6f?W$Go\A)k:&k<+IB/F>LLcs'!SGg>/o + !KXe6RY03lM>9,cZ/N^R%4PNk!U]!B]$pmo$\jSuu<&M9e6bZN"^!pLfe8lYK[7NJ[9jB8C + gc\?DPYaKDdG/S8>^]I3lr:Y$em,=Vgq?_$6s2ZXg>)'u>l@hhS6`h74l%VQ7MXFe"CkIAf + 2`pE5"4.*7G9/\gGHi`?.+eJ^#)T=Pg8ic56UL6C[tNuo@F-;[B0&Q/G>R'pSp%F:Rbe-[< + Ks9GgFiMcfKLLn]K2[YVr7la>7Z`?%AtsDmpF9[jo&C9"m5_G0%RG/3Sfj;gPpkOLO&(d2e + 1n.tH#1O&8L>d9=r6Kbq7H)HfKI=]HD#]c:1'*?[Kd/aJKY*25GKjB9pm\QbCmCRD94Te=N + X3R"Naipp8No=>=(9)GBeQ)QF;VE0+33gHdF7BKKeX@n4,>6Z9*NNt764ki?2_u2c'D*M6O + \D*!/gR:Z;Wu"0@]Y")4e8;s"ID@s._,R8J-'cA'6c_B[d(H\6giFu.gWrSmd'F2)1F(@39 + \I*h2r+!b4cA#gj4iB9?!TOaRkRpK'9.Ga.4@\MmgGcF57=)+[?b^CtCmSE,Njj\k5k$MIMdcLrB==.M7ESBPC$J8 + s&?a8VQHk0>VC#AW"?j2P"'GS&,ct;p:XY+SG1=kB*S1U$4dE:9XCnTIaGi79`kG0D,mX/F + ]'Be."g+Im6=rZZ>/m<.F@@AG)9JY>)L>h!F@I:2\SZcK:3]d8!@QocU40uij[4q;%bSq/R + Q+8VUPY>R(BjF04`\1#d*od^GZ7_Wjou-+O25V.]76S`W(-/7XU;_i1l:sL?(8aOFd-??Ol + CL>u6f1?Xi3YtUc;R3tp"?^T8^?pL=ki + H@N2@K@>-GSZ-m8och5O2tK/b!?+C?=gajno8JAV&`E#2a8'?[BEPSb^X?qU!LaXA7!sh%/ + E0Ol-)#/B.]f7a^-PDp`W\_39[l:3,9@Q8lf'\DGiqY'2l9GZ##s69a.,jq(Ec&Q33R0#lc + ,74DYF.cFk.DB9WmhAK5b)D@uKiPdQ\e?r`F!D@=o;g#:JIM]E\"BIP93/`'hM^mrgJN_oV)m:2/ceDlq)jKi2EG;raW-n)c`4DEV!S4 + u86#A-H1J']3FHi3W\Uec,ha?ERV;1RK9AT$Cet0:hk7:>n&8Qshl]cGUV/ + Yb0'A"TGa*,-lNkTLTqJh18lihZN(E1o/)or6$:_iNI-1]DGo;ccKneHc'I=pmGph!0Ak$8 + AWC^oaMM=Q@Xd10omY:@pXd,66go%)7B-SK*R#4i>TdD%HpSp#0Ef\j^k@+?FYioP$l38*s + Ng'6Bl/q,gpIo;kg6I+OnB0Y*m0%u'?iN@kqDMD(BLEa2r@J<7N$O#H03FXX5m^Gg;`pII5 + -Zmr.>DH!`VN^Z_nl/C_l#&-H7eL!snpUZP0be[S1l3hq"pfWF$1ef!sfNjRFS.cW + :feIT:Ao^"6U-jb<&@QGCi()d`5Cn]o&HrI3*NJ*^J5AeT,q,mS$=$#Gl\nkFkc`JU$?ZpNH2JS=ROR.B$sOodrOgmEr;BnS^# + j[('TT5JR&^^`&_&Ufl/V48hJiM\K-mOHPi3gB?n4*$^]**"W+H]CmEGTtiI[=TtjYXP&oAHZ,O(*.'4^'Lln.q"7U,-Sle\3JeA>4*eG!F+W>qEOYR22TS-2K7%f3$?@iaP+Uir6W$)Fu&96,(5p1gf#XBMbr.]e6a + <:>2%u;A%Je(b"#X"c4_?`5rK=%e5%]CN6JduH:jFRjt&dUH>K6de^+G4L]JdmMYeq+?%+O + `@oK0fi"TS#!*18'7FrdkPl+N/j?-m6>o+G0Fq0-Gl3#VI6Oh'R^]80G3i$O@lY:*>.o#V) + L!U'N3@JsB)_$7I$iJdLW`SQI"dC'Z./Jm&F+="#2SJdD]*Ne.PY"c.YaL`hG(#Y6(jAfu[ + ,#To^jnd$;0J`X%d#A>6%Jd3\HEH!%O\d05tJZ8to+G$*7Jd+ag@Y+di+CBF;JT;#3TRgPX + (#Pr4<.Y9%+AdXmkTETQ+Fu!J&g2`D#SCMo+@:Y_#Tu<_"3;THNZ`l3#S!GWdKg9BW$!dG! + pCaXJc_kn.@;6.RKs3BJ;OUUtXNnPU/ir=F[0fqI-ZV8YU$l+6goHSfd4erh(@u&cSMBW\T[4.ED:RJ#WbMUjoD"qQ, + 1I*&=n(/'AP(Yb15)rj*^462n86lXqiZ/dmj/J$,^Gn:.W3qY5QDa85ne0ME]"`?4G0h;?#]"mWZt?3_lHSJ%Fh?["#]Cqn.Ek#Q)L<4HD;Fp)iJ!J"GWuHjBK<+6V"#T4ejd& + (1;?"8r1[oE7D*+TF^Er<*Z''aBb/%RLFtJ"\UrKnoLA+6[BfTu^,eOTH^pLnK6lEW1iNqC + E`P\::7ZEf?-T2Fe&BJ"s:JO,*Qs+6a&\Ue$Z2P!Vc4M*QQdnc"c.qG\R$=F[0'ZBg[5?;( + ZeJ#4t"R>:WP+6f_RVT@2TPCdgM_u2WWo^G)od/QmorBChc!?RIJ#JM/UBgXU+6l+ + @W?M8;,[-L4$>E9Hof>=f!<6"crDF1!9L%&qS5i1d=">HnX@N,o+6qL.X+C8QV-:N5b5l$& + :l7OS3<*,+rFM&_RkC"Qd9:GM.8O7gCGQQ"sjl_Sccp"2L\GlM(prHXIsl + Sb*@q-Rq8J$7i1^dn8(+7'\kY]9ZZB3PaPX?DE$p*;lTW;g>erJZg22F#j\r+#)IOg9!+ab + TaB+7-(YZI/Zpa87TbXNd3?G'6+'d/RaRrL]/q#XOn(6YPj5V6ngB70iW(+66k0[3i!+)Uh + r,D0V>/dULmbq(j,Re:3[*f%QU7E,JCt]/O2Z5KZOs.;eUg\+]s^gae/!j_TF3dJd5&CQ*9 + D8]j&+0]iafs"5Po\[glakZo.(FRH!TQneSK8,7p_m^_"47r7T6_3H,)>^r0(rat!`^3EEc + j#i*YC.J*#+6Kq[ReNEFSs.ZMcXH/ZdJe()q8"09%I_!n`;(K2k^<\(J"8=nF^K4WIP8tB^ + N]8J:FQ6*j8APap\b)b,R/f2.KpoVrdMo`rIPSE$,K^s#%64*6)4A`O7XY&@0@j/d%V7AUc + q#j#ld;&r=[!b@1=Be3/:>p)3=E)5LI"@7kk2j6qE:M,#h0*j8C6aoTh_iCf-'%;Cb1l[2+ + qXs%B-c09>bC(h3\ZN7"@W7\nm*dtn$!EPaZT39qUFb^5Cc%"G3Qrh8B]J<5p46qF9p,8@Z + f;^;68aXJG\AA"=oEct3XZ2UdoqQH-(MGm-(<@]A)]cZP;J#j7]YhI7=QEo@PbIMf'#Pujj + lVN)5Bn\6Q/B=/7/nM1Orjdg\kTB,jBh]JG2P^CCt$ + IK@$m#gtfZ+s(&4-QEq*Qn6*)`F5KOgZkePI553rKcKX4KDs2])gL"c)"9>lc`;-$M(-h3: + ]XQ6W#i$+$J^@XA+86i;gpfcYY&YCIYcN?140*MlbVFoSE>G;dG!GF)j1Mjm+[dj1OA[W&+ + 8:36*!aT$utUO+[H@@B;I3U_Y%Ll: + "=ddJo&C4t2Y8:DPE;8ucFks2J0i)bN[nN`E[&Q)"@$A.40S-([P-b9:FJl$,G`AkpJd8n# + q+Wje?;'!i&,ahDZXi'c=hTD@AedBtrcQN^k'>98pr40"*hU@M6"it + %5q"(:AW40f;"=R\oT#-0Zr]mW$9$9'faQ?@IZ_#F:=Q[#*n:%a<>(a0fVtIGD%u*>CI3BM + S"@-g:$/30]m`q($\[/T4iLD[)7#/Qb]9hUX+rU7#$pGcfc*B9odbR^$fqhWLor.jB=U.XS3P"V(Z_XpDAsf!K)DiFB=TVsNC.=FZ6:J' + KT.mP'1Z1q+kO\#:A/,R3=C0]]9nK?KL4%Tl'c>ilEiKr_;/la7([E/*e&]EihrLjm#K]'* + gfkc4fq@oaK-8bgr9p?=6Q[Dj&Mj,19(1q + ?D?D7YIPAWmc]ee'G=qVP9nA]%"a*eITG@D,tI"`b_j&VWQ=)ERr^-7?:ga?jlE$VULGctb-h.&e-Xks + 4r$@.OBH-P\6Xmk4E8?um^`F:)JG?*9%NG[E&-P;Kh'`$KE`t#O?P + abC:q#7"W]TjNs"!#X5e^RcUJCjm\qSLg7Ot@-6NNk:Urd/&[4db_Qa^8+)2sd)Cs!i9jGN`5s.@;\ngN0 + ^ioV&aX+o/8m;)#aI%P''t(5%#1'>B^uIKnkhZoWIDu=K(DF@o8c$L/@Lu5^7$]I?4Tg(0k + ANX^6/jEZ5%B*s'Dp!Xe.8;C_g30*9QWG]G^H8!P=G4!YA%,Y+aXM]d@E + :B]*E"VOj`Ea#fieKti7-;\0#:hI+1*o^(>ihP65Ed\1uJ:Wl;#Vq5BBIO4fLub^9.?7FqY + a[*RSqW?*$cI4I"fMQVl0X1pP0k,cmeH8B-LaH:&sFs]a^$]"1Gb + .P1WaJIb`nI#7help'U):Zdo+?qRl-=02:5Vd$*?*ZbaYqS(6`YPaibJ/jS!M/2t(crOb#K + 3KfH(33:Vtg0p&'uPgPPTq3.QKk'7kDWm`F\4"kULtik73o64hlol6"-4ai=!c@$i=KBY0P)T8BdW$;-STNfE--VLGd + d#sj0FF#"9SpmNsO0sKjHL;97:mc + Wfqheoeqpe]BuaF$H65C"s:! + 3TTd3BDE6T,rPD;bSVk9Mr76rkm-NV&P'i9jY-:tFinQL)T<*H+^S&lg)nod+Q1 + &JGZk1Tqm!;aD)i3qCZfo-Leabc^Q@5rGi8bZ?@>Y>Fn5D"ZC?#*A]H7V,aarZc@lr_ + r,gPODf%M-^kk?:Q)DMR*9tnCg\F5h5`t(&lrg"$s@"FuB]1D8tAZ/DVfS@B0Icc/U&9kcp + F'Z0h,>P#1'%2.N[Ji/S

kLs+orQtjXQ(*u6MBqt=*IA?[nuhn;:?!sFieqH>dXJYCdq27(K(># + 5\2?i.S"?p\BK>[;LhE?AZ"Z6"KntMWE5QEO%u,nZ3:`1uo(mHqR+E&h,E;PQR[E1P2`$KJQ + &dtoF:W.'O)WEj"#u8@OI'"q)RVT-)lpB2d^^LsEN8lG.6CZaXRj'+0ticJ_l^8g>I2_A'@ + i=Efp%WUW&[X;HM*PIWBVtls"0A;(U]Qomb/3Tg3X9q=3!U$[fL?ZZ'Wq,D980P/"#fZZ?@ + ==PWO?D6%97_ZWHrjfDS,t!4/.\J.o9>L,?l(FN]E>o=7tE9mCkVfQt@1TnkPiLiW0EZMMGj + O\`TsM4-e.DW_T!mCX?5MRN*Ed3.p?c&6mUnG6]og1^$2fl7NMEE,5CO\Gr0n23XhcZjFq5XZ\5@aVtA2IecX&7'iD7(3"S@lnMQ=8#5f7Mf.[T&=4fK#O + nj0ojm8f1&jGY5T[IEtrZ96Q`5=C%S[NM+eATb,P\2R1XF[8"*?\_)>)::[*`l_;J^dWWsb + ]^t!kL*LBkkRlO^kFrVOV=(g6NVnuB7=r]+t9g;gF]i + rFV_mQkCgd-1riKQ4:D7iYL]Ml!+dB>:jYB06;]O=$PAKTY/?J>_)p%-3Z&$Y[>YrmG#S:M + k')drXM@5KQEHR4,$Phl/'6eS"5)`(t$V.2>Z@s^@h3O%GP[72%DIN5t1gqU5i;meB+[<-c + ']Zited3uV:B)?5c[WTjcS[S0]jq`YCrR0LNbimfY^ETSHVmdKjoG*2&')X:X=n2o,sM6YuT)Ck7LuO@%cl#[2fq@"jC[?Jbl95mjh_U_'F,.: + /[$(a23O:P'7aE'e@PR04hP$!>7l-4!.o&`A=U+Vud7,!cKR650u`TRm^tKD6Sc#X*bM2/k + k:&9S*q_$:oM+PmA^Jdl+?80H6.";sK00L:@'?c[g,TRtf=Z3VuE_$*Y$9Ft&('>Xh-a<6c + S,_?<[JhJYd6Ndrd"7SSJ&3KB5#9\T-+DM0"r4rIH5e74/+FpHt$:'Ci-@u:i+78)>+=BB-;qD#\G36=pS\>L`qq5)$hCGJf*%<#\'H]+p_VML(Xc"fE`XNJf!V + oI"E0C8dJ`GL"Zf<+GIrD>Zuq,DLrYF+_lTEQKe`YTS8O7=J1A%b^pSn+^BU6W$,8p'mGN@ + + 7efU?DA0J"qeq4Fa.3qF.N^M)%nn+6cr-QQPICrg=kmU&LNuM8FA+-jTTtJ#Gm6LjuADqN8 + Ij8n+LZ2VskN70c41e7F0J$b".9RjGTqc&'QSnhT`2GLIUg7RcK + rnS[`iVq^VmK^D`30#eZJ%6s(R")Zeqk/GM?YcV+3tB`PJ%MWU^jj!eqoF9"hs'>f8$M_0+ + oZjZq=GclfRKNErdLMSr'/7'!?bhMJOfPB+6Y,&TY^V[T^!(T85Taos?s7i;[$1+`K%[aLVWQk9'#gJ + $-We]8-7P+7%'cY=7fl(Z>=#A,Ulfp&I>0&H?-jrI[kB&AjfE&0L7$J$C0r`g+(L1hQphRud8b5M=upB?^X?1cC6=g.P(QA41p01&a + UFMbn/J=faKX\CV$8s!6Y&PdVpUfipOPD/H\hPEGi>a8%l9D99CKL@j@BiCb9S1k1b[r`!, + AJoK!Y`AkmT=3(,F+6AH2Q<,EoS?nT(:3"Pq1&bHKq0*qBjjCXe9^3WsXEB7;J!cAt@bm6Q + G-9ZV]=3+T9\BA$U\rHN2h^^m6cs\83Th=NrbP+#Z[.[,lb/XnpKmaS3+MmGO7SD-?R+c_: + U0XXj/P>h\GnW8r9_7#kl)[Qr.!&foT/Up5L4$C4n'3g5_p-W+ES)XU\t.QoE%8(*#4'e@L + YWE4U7()s$C5o$BOg4$"5)-Ki#&k6KCa'd5_.p0[^iVG]FC)gc\-CFW@/"r/?Er1*;k!)%X + @AN/,h:+#i-r%u^.?LUo5^fE2.C"CsY-ORp9_-7^;aif&YI%Rrh##brQuN/)9d7ROKjUES6 + E&Wl9I6_tY1N(8^ppub+6R2HK>=,UR?1)tPT)%J30N/%`q*#RWP%K(C.L@R)=\H*QWb_D(2 + hF9t%Bc.AEA2Z2\:Q['HCEk"'PqoTD)MlIKjeQEDZKa1`.*-(6,\/_&.P_m_aCaS1A2=gZb + K]7lAS39!1/X.ScM?U$,9`#)L+[r%"8lUQ+bkr1(5C3L_&3Xj(6!tHN^cA2)%57IN.p7H(O + BL-$`u=GKuu.e)M:m\,\/KhOLfBhi2L.++-NgA>E1MA0SL&WiX>kf?P;,\/9H.P_ZnaA)) + uA1"d#1(u(W9Ht]6]f31q'$/-dn#cCO&Wi2G6;)ju3Y[O+Jhdr9+W1RR(6!o]1(g$B)$mr' + N.b7J7RAC=#_Z_3q!T;%kf>l]+Rk>B^IIGsM&?OtA0!^L:MgBY3?o[,eN0r7%LC-7oqZ+;]';$[W5pl?,\.h@OD + =.Ga>EUdA/Z&ABC5Z;V5#0UN.WL$mg^'M"sd^rHgcH(BZMk%,\._(.P_C1a=__5A/4L + gt/GUQ%((lX0o)<0LKk+^/;34cKre@eT+JasJO/DR[SJ_S&A.uXk1't\2)$J8tN.P4g$!uR + ."J9jrJjM3urrEu?Dhl^B`T[+>-fo`jRIblOch\_Rl$YdqomXC%q]BJeIeVat+,BB8 + 5KW_N2s:,]VtGMRg&$8Cn,=ELq0tWnrI; +Q +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-ps-level-3_expected.ps b/testfiles/cli_tests/testcases/export-ps-level-3_expected.ps new file mode 100644 index 0000000..3fa36c5 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-ps-level-3_expected.ps @@ -0,0 +1,134 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Tue Apr 7 23:58:53 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%DocumentMedia: 53x53mm 150 150 0 () () +%%BoundingBox: 37 37 113 113 +%%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: 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 +q +37.5 37.5 75 75 re W n +[0.75 0 0 0.75 0 0] concat +/CairoFunction + << /FunctionType 2 + /Domain [ 0 1 ] + /C0 [ 1 1 0 ] + /C1 [ 1 0 0 ] + /N 1 + >> +def + << /ShadingType 2 + /ColorSpace /DeviceRGB + /Coords [ 50 50 150 50 ] + /Extend [ true true ] + /Function CairoFunction + >> +shfill +Q +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-width_expected.png b/testfiles/cli_tests/testcases/export-width_expected.png new file mode 100644 index 0000000..f05cecd Binary files /dev/null and b/testfiles/cli_tests/testcases/export-width_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-with-filters_expected.emf b/testfiles/cli_tests/testcases/export-with-filters_expected.emf new file mode 100644 index 0000000..ef5d7d9 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-with-filters_expected.emf differ diff --git a/testfiles/cli_tests/testcases/export-with-filters_expected.eps b/testfiles/cli_tests/testcases/export-with-filters_expected.eps new file mode 100644 index 0000000..a1559b3 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-with-filters_expected.eps @@ -0,0 +1,122 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Apr 10 23:27:41 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%BoundingBox: 0 0 150 75 +%%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 75 +%%EndPageSetup +q 0 0 150 75 rectclip +1 0 0 -1 0 75 cm q +1 0 0 rg +0 0 75 75 re f +q +0 0 150 75 re W n +[ 150 0 0 -75 0 75 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 3 + /InterleaveType 2 + /DataDict << + /ImageType 1 + /Width 200 + /Height 100 + /Interpolate true + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 200 0 0 -100 0 100 ] + >> + /MaskDict << + /ImageType 1 + /Width 200 + /Height 100 + /Interpolate true + /BitsPerComponent 1 + /Decode [ 1 0 ] + /ImageMatrix [ 200 0 0 -100 0 100 ] + >> +>> +image + Gb"0LYml4K!5lV0JGlC"dZfh?MWBs[8C#%o^E!2kgZRMR@eCIkJqo97!.!W7(I + DqoeQ3^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m=ob + E76LPs\a*"!`>!.!W7(IDqoeQ3 + ^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m=obE76LPs\a*"!`>!.!W7(IDqoeQ3^t*\LK#E@?(A=FJ/^ + i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m=obE76LPs\a*"!`>!.!W7(IDqoeQ3^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6 + Cg#?Z@K=\6+0uU#=m=obE76LPs\a*"!`>!.!W + 7(IDqoeQ3^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m + =obE76LPs\a*"!`>!.!W7(IDqo + eQ3^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m=obE76LPs\a*"!`>< + aThpGdpk(`M)5K@eCIkJqo97!V?]6dS>#~> +Q +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/testfiles/cli_tests/testcases/export-with-filters_expected.pdf b/testfiles/cli_tests/testcases/export-with-filters_expected.pdf new file mode 100644 index 0000000..c3df07b Binary files /dev/null and b/testfiles/cli_tests/testcases/export-with-filters_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/export-with-filters_expected.png b/testfiles/cli_tests/testcases/export-with-filters_expected.png new file mode 100644 index 0000000..d988a05 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-with-filters_expected.png differ diff --git a/testfiles/cli_tests/testcases/export-with-filters_expected.ps b/testfiles/cli_tests/testcases/export-with-filters_expected.ps new file mode 100644 index 0000000..13f6215 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-with-filters_expected.ps @@ -0,0 +1,159 @@ +%!PS-Adobe-3.0 +%%Creator: cairo 1.15.10 (http://cairographics.org) +%%CreationDate: Fri Apr 10 23:27:41 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 3 +%%DocumentMedia: 53x26mm 150 75 0 () () +%%BoundingBox: 0 0 150 75 +%%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: 53x26mm +%%PageBoundingBox: 0 0 150 75 +150 75 cairo_set_page_size +%%EndPageSetup +q 0 0 150 75 rectclip +1 0 0 -1 0 75 cm q +1 0 0 rg +0 0 75 75 re f +q +0 0 150 75 re W n +[ 150 0 0 -75 0 75 ] concat +/cairo_ascii85_file currentfile /ASCII85Decode filter def +/DeviceRGB setcolorspace +<< + /ImageType 3 + /InterleaveType 2 + /DataDict << + /ImageType 1 + /Width 200 + /Height 100 + /Interpolate true + /BitsPerComponent 8 + /Decode [ 0 1 0 1 0 1 ] + /DataSource cairo_ascii85_file /FlateDecode filter + /ImageMatrix [ 200 0 0 -100 0 100 ] + >> + /MaskDict << + /ImageType 1 + /Width 200 + /Height 100 + /Interpolate true + /BitsPerComponent 1 + /Decode [ 1 0 ] + /ImageMatrix [ 200 0 0 -100 0 100 ] + >> +>> +image + Gb"0LYml4K!5lV0JGlC"dZfh?MWBs[8C#%o^E!2kgZRMR@eCIkJqo97!.!W7(I + DqoeQ3^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m=ob + E76LPs\a*"!`>!.!W7(IDqoeQ3 + ^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m=obE76LPs\a*"!`>!.!W7(IDqoeQ3^t*\LK#E@?(A=FJ/^ + i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m=obE76LPs\a*"!`>!.!W7(IDqoeQ3^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6 + Cg#?Z@K=\6+0uU#=m=obE76LPs\a*"!`>!.!W + 7(IDqoeQ3^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m + =obE76LPs\a*"!`>!.!W7(IDqo + eQ3^t*\LK#E@?(A=FJ/^i8J/<'o.BrMq(lK$6Cg#?Z@K=\6+0uU#=m=obE76LPs\a*"!`>< + aThpGdpk(`M)5K@eCIkJqo97!V?]6dS>#~> +Q +Q Q +showpage +%%Trailer +%%EOF diff --git a/testfiles/cli_tests/testcases/export-with-filters_expected.svg b/testfiles/cli_tests/testcases/export-with-filters_expected.svg new file mode 100644 index 0000000..6b40fb2 --- /dev/null +++ b/testfiles/cli_tests/testcases/export-with-filters_expected.svg @@ -0,0 +1,68 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-with-filters_expected.wmf b/testfiles/cli_tests/testcases/export-with-filters_expected.wmf new file mode 100644 index 0000000..830da28 Binary files /dev/null and b/testfiles/cli_tests/testcases/export-with-filters_expected.wmf differ 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 @@ + + + + + + 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 @@ + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/gradient.svg b/testfiles/cli_tests/testcases/gradient.svg new file mode 100644 index 0000000..3f5ab8c --- /dev/null +++ b/testfiles/cli_tests/testcases/gradient.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/lambda-background.svg b/testfiles/cli_tests/testcases/lambda-background.svg new file mode 100644 index 0000000..50b9fb2 --- /dev/null +++ b/testfiles/cli_tests/testcases/lambda-background.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/testfiles/cli_tests/testcases/lambda.svg b/testfiles/cli_tests/testcases/lambda.svg new file mode 100644 index 0000000..ef3d688 --- /dev/null +++ b/testfiles/cli_tests/testcases/lambda.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/testfiles/cli_tests/testcases/librevenge_formats/corel_draw.cdr b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw.cdr new file mode 100644 index 0000000..ccdb02a Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw.cdr differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2.cdr b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2.cdr new file mode 100644 index 0000000..4a74dbc Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2.cdr differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2_expected.png new file mode 100644 index 0000000..94c3166 Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw2_expected.png differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/corel_draw_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw_expected.png new file mode 100644 index 0000000..b3ee3e4 Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/corel_draw_expected.png differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd new file mode 100644 index 0000000..a526a70 Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd_expected.png new file mode 100644 index 0000000..43ba022 Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsd_expected.png differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx new file mode 100644 index 0000000..ef8f6a1 Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx_expected.png new file mode 100644 index 0000000..5f1bdfa Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/visio.vsdx_expected.png differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/word_perfect.wpg b/testfiles/cli_tests/testcases/librevenge_formats/word_perfect.wpg new file mode 100644 index 0000000..02e1b82 Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/word_perfect.wpg differ diff --git a/testfiles/cli_tests/testcases/librevenge_formats/word_perfect_expected.png b/testfiles/cli_tests/testcases/librevenge_formats/word_perfect_expected.png new file mode 100644 index 0000000..aa5ac9e Binary files /dev/null and b/testfiles/cli_tests/testcases/librevenge_formats/word_perfect_expected.png differ diff --git a/testfiles/cli_tests/testcases/multiline-anchoring.svg b/testfiles/cli_tests/testcases/multiline-anchoring.svg new file mode 100644 index 0000000..0af70d6 --- /dev/null +++ b/testfiles/cli_tests/testcases/multiline-anchoring.svg @@ -0,0 +1,29 @@ + + + + أبجدأبجد + updown + أبجدأبجد + leftright + أبجدأبجد + rightleft + + \ No newline at end of file diff --git a/testfiles/cli_tests/testcases/offset.svg b/testfiles/cli_tests/testcases/offset.svg new file mode 100644 index 0000000..caa96e4 --- /dev/null +++ b/testfiles/cli_tests/testcases/offset.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/path.svg b/testfiles/cli_tests/testcases/path.svg new file mode 100644 index 0000000..57c27b4 --- /dev/null +++ b/testfiles/cli_tests/testcases/path.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/pdf-mesh.pdf b/testfiles/cli_tests/testcases/pdf-mesh.pdf new file mode 100644 index 0000000..8d4c29c Binary files /dev/null and b/testfiles/cli_tests/testcases/pdf-mesh.pdf differ diff --git a/testfiles/cli_tests/testcases/pdf-pages.pdf b/testfiles/cli_tests/testcases/pdf-pages.pdf new file mode 100644 index 0000000..758c2b1 Binary files /dev/null and b/testfiles/cli_tests/testcases/pdf-pages.pdf differ 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 @@ + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + diff --git a/testfiles/cli_tests/testcases/regression-1364.svg b/testfiles/cli_tests/testcases/regression-1364.svg new file mode 100644 index 0000000..d37767c --- /dev/null +++ b/testfiles/cli_tests/testcases/regression-1364.svg @@ -0,0 +1,20 @@ + + + + + + + diff --git a/testfiles/cli_tests/testcases/regression-1364_script.py b/testfiles/cli_tests/testcases/regression-1364_script.py new file mode 100644 index 0000000..0d3b12a --- /dev/null +++ b/testfiles/cli_tests/testcases/regression-1364_script.py @@ -0,0 +1,31 @@ +from lxml import etree + +def d_cmp(orig, new): + """ Compares the original d attribute to the new one. """ + orig_list = orig.split() + new_list = new.split() + + if len(orig_list) != len(new_list): + return False + + # Normalize the final 'z' to uppercase: + orig_list[-1] = orig_list[-1].upper() + new_list[-1] = new_list[-1].upper() + + for (o, n) in zip(orig_list, new_list): + if o == n: + continue + numeric = "{:.0f}".format(float(n)) + if o != numeric: + return False + + return True + +document = etree.parse("regression-1364_output.svg") +layer = document.find('{http://www.w3.org/2000/svg}g[@id="layer1"]') +boolop_result = layer.find('{http://www.w3.org/2000/svg}path[@id="small"]') + +assert boolop_result.attrib.get("transform") == "scale(2)" + +assert d_cmp("M 0 0 L 0 50 A 50 50 0 0 0 50 0 L 0 0 z", boolop_result.attrib.get("d")) + diff --git a/testfiles/cli_tests/testcases/regression-2602.svg b/testfiles/cli_tests/testcases/regression-2602.svg new file mode 100644 index 0000000..0611017 --- /dev/null +++ b/testfiles/cli_tests/testcases/regression-2602.svg @@ -0,0 +1,9 @@ + + + + R + B + + + diff --git a/testfiles/cli_tests/testcases/regression-2602_script.py b/testfiles/cli_tests/testcases/regression-2602_script.py new file mode 100644 index 0000000..1a5480f --- /dev/null +++ b/testfiles/cli_tests/testcases/regression-2602_script.py @@ -0,0 +1,10 @@ +from lxml import etree + +document = etree.parse("regression-2602_output.svg") + +parent = document.find('{http://www.w3.org/2000/svg}g[@id="parent"]') +paths = parent.findall('{http://www.w3.org/2000/svg}path') + +assert parent.attrib.get("style") == "fill:#0000ff" +assert paths[0].attrib.get("style") == "fill:#ff0000" +assert paths[1].attrib.get("style") is None diff --git a/testfiles/cli_tests/testcases/regression-2797.svg b/testfiles/cli_tests/testcases/regression-2797.svg new file mode 100644 index 0000000..cb62158 --- /dev/null +++ b/testfiles/cli_tests/testcases/regression-2797.svg @@ -0,0 +1,22 @@ + + + + + + + Outside tspan + Inside tspan + + diff --git a/testfiles/cli_tests/testcases/regression-2797_script.py b/testfiles/cli_tests/testcases/regression-2797_script.py new file mode 100644 index 0000000..639bff4 --- /dev/null +++ b/testfiles/cli_tests/testcases/regression-2797_script.py @@ -0,0 +1,17 @@ +from lxml import etree + +document = etree.parse("regression-2797_output.svg") + +parent = document.find('{http://www.w3.org/2000/svg}text[@id="parent"]') +tspan1, = parent.findall('{http://www.w3.org/2000/svg}tspan') +tspan2s = tspan1.findall('{http://www.w3.org/2000/svg}tspan') + +# Expect outer tspan added as SVG 1.1 fallback with x/y position. +# Expect no inner tspan with incorrect "font-size:medium". + +assert len(tspan2s) == 0 + +assert parent.attrib.get("style") == "font-size:4px;shape-inside:url(#theshape)" +assert tspan1.attrib.get("style") is None +assert tspan1.attrib.get("x") == "2" +assert tspan1.attrib.get("y") is not None 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 @@ + + + + + + + + diff --git a/testfiles/cli_tests/testcases/shapes_expected.emf b/testfiles/cli_tests/testcases/shapes_expected.emf new file mode 100644 index 0000000..4bf1faa Binary files /dev/null and b/testfiles/cli_tests/testcases/shapes_expected.emf differ 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 new file mode 100644 index 0000000..bff07b6 Binary files /dev/null and b/testfiles/cli_tests/testcases/shapes_expected.pdf differ diff --git a/testfiles/cli_tests/testcases/shapes_expected.png b/testfiles/cli_tests/testcases/shapes_expected.png new file mode 100644 index 0000000..3e81da4 Binary files /dev/null and b/testfiles/cli_tests/testcases/shapes_expected.png differ 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 new file mode 100644 index 0000000..1b3fdcf Binary files /dev/null and b/testfiles/cli_tests/testcases/shapes_expected.wmf differ diff --git a/testfiles/cli_tests/testcases/shapes_expected.xaml b/testfiles/cli_tests/testcases/shapes_expected.xaml new file mode 100644 index 0000000..613c107 --- /dev/null +++ b/testfiles/cli_tests/testcases/shapes_expected.xaml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + 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 @@ + + + + + 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 @@ + + + + + + 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 @@ + + + + + diff --git a/testfiles/cli_tests/testcases/stroke-to-path-variations.svg b/testfiles/cli_tests/testcases/stroke-to-path-variations.svg new file mode 100644 index 0000000..2c8e04b --- /dev/null +++ b/testfiles/cli_tests/testcases/stroke-to-path-variations.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVG 1.1 + inline size + + SVG shape-inside + SVG1.2 flowRoot + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + fr + + + + + diff --git a/testfiles/cli_tests/testcases/systemLanguage_de.png b/testfiles/cli_tests/testcases/systemLanguage_de.png new file mode 100644 index 0000000..1dbfe36 Binary files /dev/null and b/testfiles/cli_tests/testcases/systemLanguage_de.png differ diff --git a/testfiles/cli_tests/testcases/systemLanguage_default.png b/testfiles/cli_tests/testcases/systemLanguage_default.png new file mode 100644 index 0000000..67cb9f0 Binary files /dev/null and b/testfiles/cli_tests/testcases/systemLanguage_default.png differ diff --git a/testfiles/cli_tests/testcases/systemLanguage_en.png b/testfiles/cli_tests/testcases/systemLanguage_en.png new file mode 100644 index 0000000..31679aa Binary files /dev/null and b/testfiles/cli_tests/testcases/systemLanguage_en.png differ diff --git a/testfiles/cli_tests/testcases/systemLanguage_fr.png b/testfiles/cli_tests/testcases/systemLanguage_fr.png new file mode 100644 index 0000000..deeb4bf Binary files /dev/null and b/testfiles/cli_tests/testcases/systemLanguage_fr.png differ diff --git a/testfiles/cli_tests/testcases/systemLanguage_pt.png b/testfiles/cli_tests/testcases/systemLanguage_pt.png new file mode 100644 index 0000000..91e5b4b Binary files /dev/null and b/testfiles/cli_tests/testcases/systemLanguage_pt.png differ 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 @@ + + + some text + diff --git a/testfiles/cli_tests/testcases/theta.svg b/testfiles/cli_tests/testcases/theta.svg new file mode 100644 index 0000000..00cb1f7 --- /dev/null +++ b/testfiles/cli_tests/testcases/theta.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/testfiles/doc-per-case-test.cpp b/testfiles/doc-per-case-test.cpp new file mode 100644 index 0000000..c69fafe --- /dev/null +++ b/testfiles/doc-per-case-test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Test fixture with SPDocument per entire test case. + * + * Author: + * Jon A. Cruz + * + * 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" + +std::unique_ptr DocPerCaseTest::_doc = nullptr; + +DocPerCaseTest::DocPerCaseTest() : + ::testing::Test() +{ +} + +void DocPerCaseTest::SetUpTestCase() +{ + if ( !Inkscape::Application::exists() ) + { + // Create the global inkscape object. + Inkscape::Application::create(false); + } + + _doc.reset(SPDocument::createNewDoc( NULL, TRUE, true )); + ASSERT_TRUE(bool(_doc)); +} + +void DocPerCaseTest::TearDownTestCase() +{ + _doc.reset(); +} + +/* + 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..aa25280 --- /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 + * + * 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 std::unique_ptr _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..2eee151 --- /dev/null +++ b/testfiles/fuzzer.cpp @@ -0,0 +1,22 @@ +// 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); + auto doc = std::unique_ptr(SPDocument::createNewDocFromMem((const char *)data, size, 0)); + 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="" +tag_doctype="" +tag_open_close="" +tag_open_exclamation="" +tag_xml_q="" +"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/lpe_tests/AttachPath_0_92_5_mixed.svg b/testfiles/lpe_tests/AttachPath_0_92_5_mixed.svg new file mode 100644 index 0000000..4369dcd --- /dev/null +++ b/testfiles/lpe_tests/AttachPath_0_92_5_mixed.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + diff --git a/testfiles/lpe_tests/AttachPath_mm_1_0_2.svg b/testfiles/lpe_tests/AttachPath_mm_1_0_2.svg new file mode 100644 index 0000000..23395c5 --- /dev/null +++ b/testfiles/lpe_tests/AttachPath_mm_1_0_2.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/AttachPath_px_1_0_2.svg b/testfiles/lpe_tests/AttachPath_px_1_0_2.svg new file mode 100644 index 0000000..23395c5 --- /dev/null +++ b/testfiles/lpe_tests/AttachPath_px_1_0_2.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/BSpline_mixed_0_92_5.svg b/testfiles/lpe_tests/BSpline_mixed_0_92_5.svg new file mode 100644 index 0000000..ea52e78 --- /dev/null +++ b/testfiles/lpe_tests/BSpline_mixed_0_92_5.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/BSpline_mm_1_0_2.svg b/testfiles/lpe_tests/BSpline_mm_1_0_2.svg new file mode 100644 index 0000000..50e2803 --- /dev/null +++ b/testfiles/lpe_tests/BSpline_mm_1_0_2.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/BSpline_px_1_0_2.svg b/testfiles/lpe_tests/BSpline_px_1_0_2.svg new file mode 100644 index 0000000..e98b526 --- /dev/null +++ b/testfiles/lpe_tests/BSpline_px_1_0_2.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Bendpath_mixed_0_92_5.svg b/testfiles/lpe_tests/Bendpath_mixed_0_92_5.svg new file mode 100644 index 0000000..4357bcc --- /dev/null +++ b/testfiles/lpe_tests/Bendpath_mixed_0_92_5.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Bendpath_multiGroup_1_0_2.svg b/testfiles/lpe_tests/Bendpath_multiGroup_1_0_2.svg new file mode 100644 index 0000000..61602b7 --- /dev/null +++ b/testfiles/lpe_tests/Bendpath_multiGroup_1_0_2.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Bendpath_shapeClipPath_1_0_2.svg b/testfiles/lpe_tests/Bendpath_shapeClipPath_1_0_2.svg new file mode 100644 index 0000000..4e156fe --- /dev/null +++ b/testfiles/lpe_tests/Bendpath_shapeClipPath_1_0_2.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Bendpath_shape_1_0_2.svg b/testfiles/lpe_tests/Bendpath_shape_1_0_2.svg new file mode 100644 index 0000000..20d1436 --- /dev/null +++ b/testfiles/lpe_tests/Bendpath_shape_1_0_2.svg @@ -0,0 +1,40 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Bendpath_stackNested_mm_1_0_2.svg b/testfiles/lpe_tests/Bendpath_stackNested_mm_1_0_2.svg new file mode 100644 index 0000000..41bcf0c --- /dev/null +++ b/testfiles/lpe_tests/Bendpath_stackNested_mm_1_0_2.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Bendpath_stackNested_px_1_0_2.svg b/testfiles/lpe_tests/Bendpath_stackNested_px_1_0_2.svg new file mode 100644 index 0000000..4606432 --- /dev/null +++ b/testfiles/lpe_tests/Bendpath_stackNested_px_1_0_2.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Bool_multi_mm_1_1.svg b/testfiles/lpe_tests/Bool_multi_mm_1_1.svg new file mode 100644 index 0000000..f7431e7 --- /dev/null +++ b/testfiles/lpe_tests/Bool_multi_mm_1_1.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Bool_multi_px_1_1.svg b/testfiles/lpe_tests/Bool_multi_px_1_1.svg new file mode 100644 index 0000000..86dec1e --- /dev/null +++ b/testfiles/lpe_tests/Bool_multi_px_1_1.svg @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/BoundingBox_mixed_0_92_5.svg b/testfiles/lpe_tests/BoundingBox_mixed_0_92_5.svg new file mode 100644 index 0000000..de0b7ff --- /dev/null +++ b/testfiles/lpe_tests/BoundingBox_mixed_0_92_5.svg @@ -0,0 +1,36 @@ + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/BoundingBox_mm_1_0_2.svg b/testfiles/lpe_tests/BoundingBox_mm_1_0_2.svg new file mode 100644 index 0000000..ed256f3 --- /dev/null +++ b/testfiles/lpe_tests/BoundingBox_mm_1_0_2.svg @@ -0,0 +1,37 @@ + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/BoundingBox_px_1_0_2.svg b/testfiles/lpe_tests/BoundingBox_px_1_0_2.svg new file mode 100644 index 0000000..77ad821 --- /dev/null +++ b/testfiles/lpe_tests/BoundingBox_px_1_0_2.svg @@ -0,0 +1,37 @@ + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/CMakeLists.txt b/testfiles/lpe_tests/CMakeLists.txt new file mode 100644 index 0000000..d79da39 --- /dev/null +++ b/testfiles/lpe_tests/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +file(GLOB _FILES "README" "*.svg") +set(${_FILES}) \ No newline at end of file diff --git a/testfiles/lpe_tests/CloneOriginal_boken_1_0_2.svg b/testfiles/lpe_tests/CloneOriginal_boken_1_0_2.svg new file mode 100644 index 0000000..65b7ab3 --- /dev/null +++ b/testfiles/lpe_tests/CloneOriginal_boken_1_0_2.svg @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/CloneOriginal_mixed_0_92_5.svg b/testfiles/lpe_tests/CloneOriginal_mixed_0_92_5.svg new file mode 100644 index 0000000..1f7b3a2 --- /dev/null +++ b/testfiles/lpe_tests/CloneOriginal_mixed_0_92_5.svg @@ -0,0 +1,37 @@ + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/CloneOriginal_mixed_mm_1_1.svg b/testfiles/lpe_tests/CloneOriginal_mixed_mm_1_1.svg new file mode 100644 index 0000000..cd765e5 --- /dev/null +++ b/testfiles/lpe_tests/CloneOriginal_mixed_mm_1_1.svg @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/CloneOriginal_mixed_px_1_1.svg b/testfiles/lpe_tests/CloneOriginal_mixed_px_1_1.svg new file mode 100644 index 0000000..543b3f8 --- /dev/null +++ b/testfiles/lpe_tests/CloneOriginal_mixed_px_1_1.svg @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/ConstructGrid_mixed_0_92_5.svg b/testfiles/lpe_tests/ConstructGrid_mixed_0_92_5.svg new file mode 100644 index 0000000..79ab34e --- /dev/null +++ b/testfiles/lpe_tests/ConstructGrid_mixed_0_92_5.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/ConstructGrid_mm_1_0_2.svg b/testfiles/lpe_tests/ConstructGrid_mm_1_0_2.svg new file mode 100644 index 0000000..8e3b735 --- /dev/null +++ b/testfiles/lpe_tests/ConstructGrid_mm_1_0_2.svg @@ -0,0 +1,60 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/ConstructGrid_px_1_0_2.svg b/testfiles/lpe_tests/ConstructGrid_px_1_0_2.svg new file mode 100644 index 0000000..1fba02f --- /dev/null +++ b/testfiles/lpe_tests/ConstructGrid_px_1_0_2.svg @@ -0,0 +1,60 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/DashedStroke_multi_mm_1_0_2.svg b/testfiles/lpe_tests/DashedStroke_multi_mm_1_0_2.svg new file mode 100644 index 0000000..a9448eb --- /dev/null +++ b/testfiles/lpe_tests/DashedStroke_multi_mm_1_0_2.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/DashedStroke_multi_px_1_0_2.svg b/testfiles/lpe_tests/DashedStroke_multi_px_1_0_2.svg new file mode 100644 index 0000000..196b0f2 --- /dev/null +++ b/testfiles/lpe_tests/DashedStroke_multi_px_1_0_2.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Ellipse5pts_ellipse_mm_1_0_2.svg b/testfiles/lpe_tests/Ellipse5pts_ellipse_mm_1_0_2.svg new file mode 100644 index 0000000..1f26c00 --- /dev/null +++ b/testfiles/lpe_tests/Ellipse5pts_ellipse_mm_1_0_2.svg @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Ellipse5pts_ellipse_px_1_0_2.svg b/testfiles/lpe_tests/Ellipse5pts_ellipse_px_1_0_2.svg new file mode 100644 index 0000000..dda5193 --- /dev/null +++ b/testfiles/lpe_tests/Ellipse5pts_ellipse_px_1_0_2.svg @@ -0,0 +1,28 @@ + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Ellipse5pts_path_0_92_5.svg b/testfiles/lpe_tests/Ellipse5pts_path_0_92_5.svg new file mode 100644 index 0000000..58eef8f --- /dev/null +++ b/testfiles/lpe_tests/Ellipse5pts_path_0_92_5.svg @@ -0,0 +1,33 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/EllipseFromPoints_multi_mm_1_0_2.svg b/testfiles/lpe_tests/EllipseFromPoints_multi_mm_1_0_2.svg new file mode 100644 index 0000000..526d3c2 --- /dev/null +++ b/testfiles/lpe_tests/EllipseFromPoints_multi_mm_1_0_2.svg @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/EllipseFromPoints_multi_px_1_0_2.svg b/testfiles/lpe_tests/EllipseFromPoints_multi_px_1_0_2.svg new file mode 100644 index 0000000..82baf46 --- /dev/null +++ b/testfiles/lpe_tests/EllipseFromPoints_multi_px_1_0_2.svg @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/EnvelopeDeformation_multi_0_92_5.svg b/testfiles/lpe_tests/EnvelopeDeformation_multi_0_92_5.svg new file mode 100644 index 0000000..0880910 --- /dev/null +++ b/testfiles/lpe_tests/EnvelopeDeformation_multi_0_92_5.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/EnvelopeDeformation_multi_mm_1_0_2.svg b/testfiles/lpe_tests/EnvelopeDeformation_multi_mm_1_0_2.svg new file mode 100644 index 0000000..9b61685 --- /dev/null +++ b/testfiles/lpe_tests/EnvelopeDeformation_multi_mm_1_0_2.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/EnvelopeDeformation_multi_px_1_0_2.svg b/testfiles/lpe_tests/EnvelopeDeformation_multi_px_1_0_2.svg new file mode 100644 index 0000000..511ab24 --- /dev/null +++ b/testfiles/lpe_tests/EnvelopeDeformation_multi_px_1_0_2.svg @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/FillBetweenMany_multi_0_92_5.svg b/testfiles/lpe_tests/FillBetweenMany_multi_0_92_5.svg new file mode 100644 index 0000000..1e49184 --- /dev/null +++ b/testfiles/lpe_tests/FillBetweenMany_multi_0_92_5.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/FillBetweenMany_multi_mm_1_0_2.svg b/testfiles/lpe_tests/FillBetweenMany_multi_mm_1_0_2.svg new file mode 100644 index 0000000..a05e76c --- /dev/null +++ b/testfiles/lpe_tests/FillBetweenMany_multi_mm_1_0_2.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/FillBetweenMany_multi_px_1_0_2.svg b/testfiles/lpe_tests/FillBetweenMany_multi_px_1_0_2.svg new file mode 100644 index 0000000..316df7b --- /dev/null +++ b/testfiles/lpe_tests/FillBetweenMany_multi_px_1_0_2.svg @@ -0,0 +1,166 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testfiles/lpe_tests/FillBetweenStrokes_path_0_92_5.svg b/testfiles/lpe_tests/FillBetweenStrokes_path_0_92_5.svg new file mode 100644 index 0000000..bf8c35e --- /dev/null +++ b/testfiles/lpe_tests/FillBetweenStrokes_path_0_92_5.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/FillBetweenStrokes_path_multi_mm_1_0_2.svg b/testfiles/lpe_tests/FillBetweenStrokes_path_multi_mm_1_0_2.svg new file mode 100644 index 0000000..80d33e5 --- /dev/null +++ b/testfiles/lpe_tests/FillBetweenStrokes_path_multi_mm_1_0_2.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/FillBetweenStrokes_path_multi_px_1_0_2.svg b/testfiles/lpe_tests/FillBetweenStrokes_path_multi_px_1_0_2.svg new file mode 100644 index 0000000..fa315e1 --- /dev/null +++ b/testfiles/lpe_tests/FillBetweenStrokes_path_multi_px_1_0_2.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/FilletChamfer_multi_mm_1_0_2.svg b/testfiles/lpe_tests/FilletChamfer_multi_mm_1_0_2.svg new file mode 100644 index 0000000..a61da2e --- /dev/null +++ b/testfiles/lpe_tests/FilletChamfer_multi_mm_1_0_2.svg @@ -0,0 +1,164 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/FilletChamfer_multi_px_1_0_2.svg b/testfiles/lpe_tests/FilletChamfer_multi_px_1_0_2.svg new file mode 100644 index 0000000..865db0b --- /dev/null +++ b/testfiles/lpe_tests/FilletChamfer_multi_px_1_0_2.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Gears_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Gears_multi_mm_1_0_2.svg new file mode 100644 index 0000000..8594682 --- /dev/null +++ b/testfiles/lpe_tests/Gears_multi_mm_1_0_2.svg @@ -0,0 +1,40 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Gears_multi_px_1_0_2.svg b/testfiles/lpe_tests/Gears_multi_px_1_0_2.svg new file mode 100644 index 0000000..ccf1f1e --- /dev/null +++ b/testfiles/lpe_tests/Gears_multi_px_1_0_2.svg @@ -0,0 +1,40 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Gears_path_0_92_5.svg b/testfiles/lpe_tests/Gears_path_0_92_5.svg new file mode 100644 index 0000000..a212018 --- /dev/null +++ b/testfiles/lpe_tests/Gears_path_0_92_5.svg @@ -0,0 +1,40 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/InterpolatePoints_multi_mm_1_0_2.svg b/testfiles/lpe_tests/InterpolatePoints_multi_mm_1_0_2.svg new file mode 100644 index 0000000..a5922e0 --- /dev/null +++ b/testfiles/lpe_tests/InterpolatePoints_multi_mm_1_0_2.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/InterpolatePoints_multi_px_1_0_2.svg b/testfiles/lpe_tests/InterpolatePoints_multi_px_1_0_2.svg new file mode 100644 index 0000000..42f8cab --- /dev/null +++ b/testfiles/lpe_tests/InterpolatePoints_multi_px_1_0_2.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/InterpolatePoints_path_0_92_5.svg b/testfiles/lpe_tests/InterpolatePoints_path_0_92_5.svg new file mode 100644 index 0000000..1db823f --- /dev/null +++ b/testfiles/lpe_tests/InterpolatePoints_path_0_92_5.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Interpolate_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Interpolate_multi_mm_1_0_2.svg new file mode 100644 index 0000000..3b7a64e --- /dev/null +++ b/testfiles/lpe_tests/Interpolate_multi_mm_1_0_2.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Interpolate_multi_px_1_0_2.svg b/testfiles/lpe_tests/Interpolate_multi_px_1_0_2.svg new file mode 100644 index 0000000..6edb7f0 --- /dev/null +++ b/testfiles/lpe_tests/Interpolate_multi_px_1_0_2.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Interpolate_path_0_92_5.svg b/testfiles/lpe_tests/Interpolate_path_0_92_5.svg new file mode 100644 index 0000000..b6555a7 --- /dev/null +++ b/testfiles/lpe_tests/Interpolate_path_0_92_5.svg @@ -0,0 +1,38 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/JoinType_multi_mm_1_0_2.svg b/testfiles/lpe_tests/JoinType_multi_mm_1_0_2.svg new file mode 100644 index 0000000..635808f --- /dev/null +++ b/testfiles/lpe_tests/JoinType_multi_mm_1_0_2.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/JoinType_multi_px_1_0_2.svg b/testfiles/lpe_tests/JoinType_multi_px_1_0_2.svg new file mode 100644 index 0000000..3589658 --- /dev/null +++ b/testfiles/lpe_tests/JoinType_multi_px_1_0_2.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Knot_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Knot_multi_mm_1_0_2.svg new file mode 100644 index 0000000..7f88dca --- /dev/null +++ b/testfiles/lpe_tests/Knot_multi_mm_1_0_2.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Knot_multi_px_1_0_2.svg b/testfiles/lpe_tests/Knot_multi_px_1_0_2.svg new file mode 100644 index 0000000..dd2722f --- /dev/null +++ b/testfiles/lpe_tests/Knot_multi_px_1_0_2.svg @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Knot_path_0_92_5.svg b/testfiles/lpe_tests/Knot_path_0_92_5.svg new file mode 100644 index 0000000..6f0b94a --- /dev/null +++ b/testfiles/lpe_tests/Knot_path_0_92_5.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Lattice2_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Lattice2_multi_mm_1_0_2.svg new file mode 100644 index 0000000..2290b6c --- /dev/null +++ b/testfiles/lpe_tests/Lattice2_multi_mm_1_0_2.svg @@ -0,0 +1,255 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Lattice2_multi_px_1_0_2.svg b/testfiles/lpe_tests/Lattice2_multi_px_1_0_2.svg new file mode 100644 index 0000000..3ddbc0a --- /dev/null +++ b/testfiles/lpe_tests/Lattice2_multi_px_1_0_2.svg @@ -0,0 +1,257 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Lattice2_path_0_92_5.svg b/testfiles/lpe_tests/Lattice2_path_0_92_5.svg new file mode 100644 index 0000000..839b7bb --- /dev/null +++ b/testfiles/lpe_tests/Lattice2_path_0_92_5.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/MeasureSegments_multi_mm_1_0_2.svg b/testfiles/lpe_tests/MeasureSegments_multi_mm_1_0_2.svg new file mode 100644 index 0000000..6fedb6e --- /dev/null +++ b/testfiles/lpe_tests/MeasureSegments_multi_mm_1_0_2.svg @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + 353.990mm + + + + 251.999mm + + + + 353.990mm + + + + 251.999mm + + + + [0] 111.21mm + + + + [1] 59.49mm + + + + [2] 97.26mm + + + + [3] 79.77mm + + + + [4] 153.95mm + + + + [5] 115.06mm + + + + 223.08mm + + + + 270.70mm + + + + 174.20mm + + + + 106.61mm + + + + 108.82mm + + + diff --git a/testfiles/lpe_tests/MeasureSegments_multi_px_1_0_2.svg b/testfiles/lpe_tests/MeasureSegments_multi_px_1_0_2.svg new file mode 100644 index 0000000..bc9b4bb --- /dev/null +++ b/testfiles/lpe_tests/MeasureSegments_multi_px_1_0_2.svg @@ -0,0 +1,748 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + 200.935mm + + + + 177.511mm + + + + 200.935mm + + + + 177.511mm + + + + [0] 60.82mm + + + + [1] 27.29mm + + + + [2] 54.29mm + + + + [3] 43.83mm + + + + [4] 82.74mm + + + + [5] 66.25mm + + + + 100.72mm + + + + 146.14mm + + + + 85.44mm + + + + 79.10mm + + + + 50.97mm + + + diff --git a/testfiles/lpe_tests/MirrorSymmetry_multi_mm_1_0_2.svg b/testfiles/lpe_tests/MirrorSymmetry_multi_mm_1_0_2.svg new file mode 100644 index 0000000..8a4dcda --- /dev/null +++ b/testfiles/lpe_tests/MirrorSymmetry_multi_mm_1_0_2.svg @@ -0,0 +1,301 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/MirrorSymmetry_multi_px_1_0_2.svg b/testfiles/lpe_tests/MirrorSymmetry_multi_px_1_0_2.svg new file mode 100644 index 0000000..8ec801a --- /dev/null +++ b/testfiles/lpe_tests/MirrorSymmetry_multi_px_1_0_2.svg @@ -0,0 +1,301 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/MirrorSymmetry_path_0_92_5.svg b/testfiles/lpe_tests/MirrorSymmetry_path_0_92_5.svg new file mode 100644 index 0000000..7432760 --- /dev/null +++ b/testfiles/lpe_tests/MirrorSymmetry_path_0_92_5.svg @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Offset_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Offset_multi_mm_1_0_2.svg new file mode 100644 index 0000000..58e6b12 --- /dev/null +++ b/testfiles/lpe_tests/Offset_multi_mm_1_0_2.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Offset_multi_px_1_0_2.svg b/testfiles/lpe_tests/Offset_multi_px_1_0_2.svg new file mode 100644 index 0000000..e26401b --- /dev/null +++ b/testfiles/lpe_tests/Offset_multi_px_1_0_2.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Offset_multi_px_1_1.svg b/testfiles/lpe_tests/Offset_multi_px_1_1.svg new file mode 100644 index 0000000..bc0a530 --- /dev/null +++ b/testfiles/lpe_tests/Offset_multi_px_1_1.svg @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PatternAlongPath_mixed_0_92_5.svg b/testfiles/lpe_tests/PatternAlongPath_mixed_0_92_5.svg new file mode 100644 index 0000000..6851a5f --- /dev/null +++ b/testfiles/lpe_tests/PatternAlongPath_mixed_0_92_5.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PatternAlongPath_multiple_mm_1_0_2.svg b/testfiles/lpe_tests/PatternAlongPath_multiple_mm_1_0_2.svg new file mode 100644 index 0000000..3b93c20 --- /dev/null +++ b/testfiles/lpe_tests/PatternAlongPath_multiple_mm_1_0_2.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PatternAlongPath_multiple_px_1_0_2.svg b/testfiles/lpe_tests/PatternAlongPath_multiple_px_1_0_2.svg new file mode 100644 index 0000000..0bcbd31 --- /dev/null +++ b/testfiles/lpe_tests/PatternAlongPath_multiple_px_1_0_2.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PatternAlongPath_path_1_0_2.svg b/testfiles/lpe_tests/PatternAlongPath_path_1_0_2.svg new file mode 100644 index 0000000..4f8bb22 --- /dev/null +++ b/testfiles/lpe_tests/PatternAlongPath_path_1_0_2.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PatternAlongPath_shape_1_0_2.svg b/testfiles/lpe_tests/PatternAlongPath_shape_1_0_2.svg new file mode 100644 index 0000000..cf3e6f6 --- /dev/null +++ b/testfiles/lpe_tests/PatternAlongPath_shape_1_0_2.svg @@ -0,0 +1,45 @@ + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PerspectiveEnvelope_mixed_0_92_5.svg b/testfiles/lpe_tests/PerspectiveEnvelope_mixed_0_92_5.svg new file mode 100644 index 0000000..dfa0fe0 --- /dev/null +++ b/testfiles/lpe_tests/PerspectiveEnvelope_mixed_0_92_5.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PerspectiveEnvelope_multi_mm_1_0_2.svg b/testfiles/lpe_tests/PerspectiveEnvelope_multi_mm_1_0_2.svg new file mode 100644 index 0000000..826df03 --- /dev/null +++ b/testfiles/lpe_tests/PerspectiveEnvelope_multi_mm_1_0_2.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PerspectiveEnvelope_multi_px_1_0_2.svg b/testfiles/lpe_tests/PerspectiveEnvelope_multi_px_1_0_2.svg new file mode 100644 index 0000000..bde61ed --- /dev/null +++ b/testfiles/lpe_tests/PerspectiveEnvelope_multi_px_1_0_2.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PowerClip_multi_mm_1_0_2.svg b/testfiles/lpe_tests/PowerClip_multi_mm_1_0_2.svg new file mode 100644 index 0000000..9b1ce59 --- /dev/null +++ b/testfiles/lpe_tests/PowerClip_multi_mm_1_0_2.svg @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PowerClip_multi_px_1_0_2.svg b/testfiles/lpe_tests/PowerClip_multi_px_1_0_2.svg new file mode 100644 index 0000000..827b373 --- /dev/null +++ b/testfiles/lpe_tests/PowerClip_multi_px_1_0_2.svg @@ -0,0 +1,280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PowerMask_multi_mm_1_0_2.svg b/testfiles/lpe_tests/PowerMask_multi_mm_1_0_2.svg new file mode 100644 index 0000000..1f049c7 --- /dev/null +++ b/testfiles/lpe_tests/PowerMask_multi_mm_1_0_2.svg @@ -0,0 +1,356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PowerMask_multi_px_1_0_2.svg b/testfiles/lpe_tests/PowerMask_multi_px_1_0_2.svg new file mode 100644 index 0000000..93a6036 --- /dev/null +++ b/testfiles/lpe_tests/PowerMask_multi_px_1_0_2.svg @@ -0,0 +1,357 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PowerStroke_multi_mm_1_0_2.svg b/testfiles/lpe_tests/PowerStroke_multi_mm_1_0_2.svg new file mode 100644 index 0000000..4748102 --- /dev/null +++ b/testfiles/lpe_tests/PowerStroke_multi_mm_1_0_2.svg @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/PowerStroke_multi_px_1_0_2.svg b/testfiles/lpe_tests/PowerStroke_multi_px_1_0_2.svg new file mode 100644 index 0000000..ac342a3 --- /dev/null +++ b/testfiles/lpe_tests/PowerStroke_multi_px_1_0_2.svg @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/README b/testfiles/lpe_tests/README new file mode 100644 index 0000000..a6a9209 --- /dev/null +++ b/testfiles/lpe_tests/README @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +Add files with LPE test with this pattern in file name: +{LPENAME}{underscore}{small description to also avoid duplicate like px, mm multplpe or 001}{underscore}{{Underscores Inkscape file version}_.svg + +This folder contains LPE to test. LPE test API has some parameters that can be helpful for fixing tests, especially legacy ones. +* inkscape:test-threshold="0.3" in the SVG element set a precision to all the tests. If it's in a single element, add to it. If it doesn't exist, use a default one 0.0001 +* inkscape:test-ignore="true" skip this element from testing \ No newline at end of file diff --git a/testfiles/lpe_tests/RotateCopies_multi_mm_1_0_2.svg b/testfiles/lpe_tests/RotateCopies_multi_mm_1_0_2.svg new file mode 100644 index 0000000..9c84d79 --- /dev/null +++ b/testfiles/lpe_tests/RotateCopies_multi_mm_1_0_2.svg @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/RotateCopies_multi_px_1_0_2.svg b/testfiles/lpe_tests/RotateCopies_multi_px_1_0_2.svg new file mode 100644 index 0000000..d51495c --- /dev/null +++ b/testfiles/lpe_tests/RotateCopies_multi_px_1_0_2.svg @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/RoughHatches_multi_mm_1_0_2.svg b/testfiles/lpe_tests/RoughHatches_multi_mm_1_0_2.svg new file mode 100644 index 0000000..0b18fbe --- /dev/null +++ b/testfiles/lpe_tests/RoughHatches_multi_mm_1_0_2.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/RoughHatches_multi_px_1_0_2.svg b/testfiles/lpe_tests/RoughHatches_multi_px_1_0_2.svg new file mode 100644 index 0000000..f369f3c --- /dev/null +++ b/testfiles/lpe_tests/RoughHatches_multi_px_1_0_2.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/RoughHatches_path_0_92_5.svg b/testfiles/lpe_tests/RoughHatches_path_0_92_5.svg new file mode 100644 index 0000000..efee85e --- /dev/null +++ b/testfiles/lpe_tests/RoughHatches_path_0_92_5.svg @@ -0,0 +1,209 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Roughen_path_1_1.svg b/testfiles/lpe_tests/Roughen_path_1_1.svg new file mode 100644 index 0000000..d677489 --- /dev/null +++ b/testfiles/lpe_tests/Roughen_path_1_1.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Ruler_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Ruler_multi_mm_1_0_2.svg new file mode 100644 index 0000000..935ad91 --- /dev/null +++ b/testfiles/lpe_tests/Ruler_multi_mm_1_0_2.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Ruler_multi_px_1_0_2.svg b/testfiles/lpe_tests/Ruler_multi_px_1_0_2.svg new file mode 100644 index 0000000..83434f2 --- /dev/null +++ b/testfiles/lpe_tests/Ruler_multi_px_1_0_2.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Ruler_path_0_92_5.svg b/testfiles/lpe_tests/Ruler_path_0_92_5.svg new file mode 100644 index 0000000..4db3fc0 --- /dev/null +++ b/testfiles/lpe_tests/Ruler_path_0_92_5.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/ShowHandles_multi_mm_1_0_2.svg b/testfiles/lpe_tests/ShowHandles_multi_mm_1_0_2.svg new file mode 100644 index 0000000..657d059 --- /dev/null +++ b/testfiles/lpe_tests/ShowHandles_multi_mm_1_0_2.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/ShowHandles_multi_px_1_0_2.svg b/testfiles/lpe_tests/ShowHandles_multi_px_1_0_2.svg new file mode 100644 index 0000000..81f7e4d --- /dev/null +++ b/testfiles/lpe_tests/ShowHandles_multi_px_1_0_2.svg @@ -0,0 +1,140 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/ShowHandles_path_0_92_5.svg b/testfiles/lpe_tests/ShowHandles_path_0_92_5.svg new file mode 100644 index 0000000..07a4778 --- /dev/null +++ b/testfiles/lpe_tests/ShowHandles_path_0_92_5.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Simplify_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Simplify_multi_mm_1_0_2.svg new file mode 100644 index 0000000..ba779ac --- /dev/null +++ b/testfiles/lpe_tests/Simplify_multi_mm_1_0_2.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Simplify_multi_px_1_0_2.svg b/testfiles/lpe_tests/Simplify_multi_px_1_0_2.svg new file mode 100644 index 0000000..a6ea9a8 --- /dev/null +++ b/testfiles/lpe_tests/Simplify_multi_px_1_0_2.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Simplify_path_0_92_5.svg b/testfiles/lpe_tests/Simplify_path_0_92_5.svg new file mode 100644 index 0000000..9301952 --- /dev/null +++ b/testfiles/lpe_tests/Simplify_path_0_92_5.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Sketch_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Sketch_multi_mm_1_0_2.svg new file mode 100644 index 0000000..13ad52e --- /dev/null +++ b/testfiles/lpe_tests/Sketch_multi_mm_1_0_2.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Sketch_multi_px_1_0_2.svg b/testfiles/lpe_tests/Sketch_multi_px_1_0_2.svg new file mode 100644 index 0000000..4d24ec6 --- /dev/null +++ b/testfiles/lpe_tests/Sketch_multi_px_1_0_2.svg @@ -0,0 +1,193 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Sketch_path_0_92_5.svg b/testfiles/lpe_tests/Sketch_path_0_92_5.svg new file mode 100644 index 0000000..1b429d6 --- /dev/null +++ b/testfiles/lpe_tests/Sketch_path_0_92_5.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Slice_multi_mm_1_1.svg b/testfiles/lpe_tests/Slice_multi_mm_1_1.svg new file mode 100644 index 0000000..b9c6bc3 --- /dev/null +++ b/testfiles/lpe_tests/Slice_multi_mm_1_1.svg @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Slice_multi_px_1_1.svg b/testfiles/lpe_tests/Slice_multi_px_1_1.svg new file mode 100644 index 0000000..b8d6ca4 --- /dev/null +++ b/testfiles/lpe_tests/Slice_multi_px_1_1.svg @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Spiro_mixed_0_92_5.svg b/testfiles/lpe_tests/Spiro_mixed_0_92_5.svg new file mode 100644 index 0000000..50e30d7 --- /dev/null +++ b/testfiles/lpe_tests/Spiro_mixed_0_92_5.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Spiro_mm_1_0_2.svg b/testfiles/lpe_tests/Spiro_mm_1_0_2.svg new file mode 100644 index 0000000..6f04353 --- /dev/null +++ b/testfiles/lpe_tests/Spiro_mm_1_0_2.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Spiro_px_1_0_2.svg b/testfiles/lpe_tests/Spiro_px_1_0_2.svg new file mode 100644 index 0000000..99c5fb3 --- /dev/null +++ b/testfiles/lpe_tests/Spiro_px_1_0_2.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/StitchSubPaths_multi_mm_1_0_2.svg b/testfiles/lpe_tests/StitchSubPaths_multi_mm_1_0_2.svg new file mode 100644 index 0000000..0a6cca7 --- /dev/null +++ b/testfiles/lpe_tests/StitchSubPaths_multi_mm_1_0_2.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/StitchSubPaths_multi_px_1_0_2.svg b/testfiles/lpe_tests/StitchSubPaths_multi_px_1_0_2.svg new file mode 100644 index 0000000..e466d32 --- /dev/null +++ b/testfiles/lpe_tests/StitchSubPaths_multi_px_1_0_2.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/StitchSubPaths_path_0_92_5.svg b/testfiles/lpe_tests/StitchSubPaths_path_0_92_5.svg new file mode 100644 index 0000000..537330f --- /dev/null +++ b/testfiles/lpe_tests/StitchSubPaths_path_0_92_5.svg @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/TaperStroke_multi_mm_1_0_2.svg b/testfiles/lpe_tests/TaperStroke_multi_mm_1_0_2.svg new file mode 100644 index 0000000..06568ab --- /dev/null +++ b/testfiles/lpe_tests/TaperStroke_multi_mm_1_0_2.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/TaperStroke_multi_px_1_0_2.svg b/testfiles/lpe_tests/TaperStroke_multi_px_1_0_2.svg new file mode 100644 index 0000000..7835806 --- /dev/null +++ b/testfiles/lpe_tests/TaperStroke_multi_px_1_0_2.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Transform2Points_multi_mm_1_0_2.svg b/testfiles/lpe_tests/Transform2Points_multi_mm_1_0_2.svg new file mode 100644 index 0000000..58e6b12 --- /dev/null +++ b/testfiles/lpe_tests/Transform2Points_multi_mm_1_0_2.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Transform2Points_multi_px_1_0_2.svg b/testfiles/lpe_tests/Transform2Points_multi_px_1_0_2.svg new file mode 100644 index 0000000..e814687 --- /dev/null +++ b/testfiles/lpe_tests/Transform2Points_multi_px_1_0_2.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/Transform2Points_path_0_92_5.svg b/testfiles/lpe_tests/Transform2Points_path_0_92_5.svg new file mode 100644 index 0000000..71c3fc4 --- /dev/null +++ b/testfiles/lpe_tests/Transform2Points_path_0_92_5.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/VonCoch_multi_mm_1_0_2.svg b/testfiles/lpe_tests/VonCoch_multi_mm_1_0_2.svg new file mode 100644 index 0000000..499f103 --- /dev/null +++ b/testfiles/lpe_tests/VonCoch_multi_mm_1_0_2.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/VonCoch_multi_px_1_0_2.svg b/testfiles/lpe_tests/VonCoch_multi_px_1_0_2.svg new file mode 100644 index 0000000..8120b1d --- /dev/null +++ b/testfiles/lpe_tests/VonCoch_multi_px_1_0_2.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpe_tests/VonCoch_path_0_92_5.svg b/testfiles/lpe_tests/VonCoch_path_0_92_5.svg new file mode 100644 index 0000000..fb0b2e5 --- /dev/null +++ b/testfiles/lpe_tests/VonCoch_path_0_92_5.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testfiles/lpespaths-test.h b/testfiles/lpespaths-test.h new file mode 100644 index 0000000..09f96b7 --- /dev/null +++ b/testfiles/lpespaths-test.h @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * LPE test file wrapper + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include +#include +#include +#include +#include +#include +#include "src/extension/init.h" + +#include <2geom/pathvector.h> + +using namespace Inkscape; + +/* This class allow test LPE's. To make possible in latest release of Inkscape + * LPE is not updated on load (if in the future any do we must take account) so we load + * a svg, get all "d" attribute from paths, shapes... + * Update all path effects with root object and check equality of paths. + * We use some helpers inside the SVG document to test: + * inkscape:test-threshold="0.1" can be global using in root element or per item + * inkscape:test-ignore="1" ignore this element from tests + * Question: Maybe is better store SVG as files instead inline CPP files, there is a + * 1.2 started MR, I can't finish without too much work than a cmake advanced user + */ + +class LPESPathsTest : public ::testing::Test { +protected: + void SetUp() override + { + // setup hidden dependency + Application::create(false); + Inkscape::Extension::init(); + const testing::TestInfo* const test_info = + testing::UnitTest::GetInstance()->current_test_info(); + svg = test_info->file();; +#ifdef INKSCAPE_TESTS_DIR + svg = INKSCAPE_TESTS_DIR; +#else + size_t pos = svg.find("lpespaths-test.h"); + svg.erase(pos); +#endif + svg += "/lpe_tests/"; // gitlab use this separator + /* svg += test_info->test_suite_name(); */ + svg += test_info->name(); + svg += ".svg"; + } + + void pathCompare(const gchar *a, const gchar *b, const gchar *id, double precission = 0.001) + { + failed.push_back(id); + Geom::PathVector apv = sp_svg_read_pathv(a); + Geom::PathVector bpv = sp_svg_read_pathv(b); + size_t totala = apv.curveCount(); + size_t totalb = bpv.curveCount(); + ASSERT_TRUE(totala == totalb); + std::vector pos; + // find initial + size_t initial = 0; + for (size_t i = 0; i < totala; i++) { + Geom::Point pointa = apv.pointAt(0.0); + Geom::Point pointb = bpv.pointAt(float(i)); + if (Geom::are_near(pointa[Geom::X], pointb[Geom::X], precission) && + Geom::are_near(pointa[Geom::Y], pointb[Geom::Y], precission)) + { + initial = i; + break; + } + } + if (initial != 0 && initial == totala) { + std::cout << "[ WARN ] Curve reversed. We not block here. We reverse the path and test node positions on reverse" << std::endl; + bpv.reverse(); + } else if (initial != 0) { + std::cout << "[ WARN ] Different starting node. We not block here. We gap the origin to " << initial << " de " << totala << " and test with the pathvector reindexed" << std::endl; + } + for (size_t i = 0; i < apv.curveCount(); i++) { + if (initial >= totala) { + initial = 0; + } + Geom::Point pointa = apv.pointAt(float(i)+0.2); + Geom::Point pointb = bpv.pointAt(float(initial)+0.2); + Geom::Point pointc = apv.pointAt(float(i)+0.4); + Geom::Point pointd = bpv.pointAt(float(initial)+0.4); + Geom::Point pointe = apv.pointAt(float(i)); + Geom::Point pointf = bpv.pointAt(float(initial)); + ASSERT_NEAR(pointa[Geom::X], pointb[Geom::X], precission); + ASSERT_NEAR(pointa[Geom::Y], pointb[Geom::Y], precission); + ASSERT_NEAR(pointc[Geom::X], pointd[Geom::X], precission); + ASSERT_NEAR(pointc[Geom::Y], pointd[Geom::Y], precission); + ASSERT_NEAR(pointe[Geom::X], pointf[Geom::X], precission); + ASSERT_NEAR(pointe[Geom::Y], pointf[Geom::Y], precission); + initial++; + } + failed.pop_back(); + } + + void TearDown( ) override + { + Glib::ustring ids = ""; + for (auto fail : failed) { + if (ids != "") { + ids += ","; + } + ids += fail; + } + if (ids != "") { + FAIL() << "[FAILED IDS] " << ids; + } + } + + // you can override custom threshold from svg file using in + // root svg from global and override with per shape "inkscape:test-threshold" + void testDoc(std::string file) + { + double precission = 0.001; + SPDocument *doc = nullptr; + doc = SPDocument::createNewDoc(file.c_str(), false); + ASSERT_TRUE(doc != nullptr); + std::vector objs; + std::vector ids; + std::vector ds; + for (auto obj : doc->getObjectsByElement("path")) { + objs.push_back(obj); + } + for (auto obj : doc->getObjectsByElement("ellipse")) { + objs.push_back(obj); + } + for (auto obj : doc->getObjectsByElement("circle")) { + objs.push_back(obj); + } + for (auto obj : doc->getObjectsByElement("rect")) { + objs.push_back(obj); + } + for (auto obj : objs) { + if (!g_strcmp0(obj->getAttribute("d"), "M 0,0")) { + if (obj->getAttribute("id")) { + std::cout << "[ WARN ] Item with id:" << obj->getAttribute("id") << " has empty path data" << std::endl; + } + } else if (obj->getAttribute("d") && obj->getAttribute("id")) { + ds.push_back(obj->getAttribute("d")); + ids.push_back(obj->getAttribute("id")); + } + } + sp_file_fix_lpe(doc); + doc->ensureUpToDate(); + SPLPEItem *lpeitem = dynamic_cast(doc->getRoot()); + sp_lpe_item_update_patheffect(lpeitem, true, true); + // we need to double update because clippaths or mask + if (doc->getObjectsByElement("clipPath").size() || doc->getObjectsByElement("mask").size()) { + sp_lpe_item_update_patheffect(lpeitem, true, true); + } + if (lpeitem->getAttribute("inkscape:test-threshold")) { + precission = helperfns_read_number(lpeitem->getAttribute("inkscape:test-threshold")); + } + size_t index = 0; + for (auto id : ids) { + SPObject *obj = doc->getObjectById(id); + if (obj) { + if (obj->getAttribute("inkscape:test-threshold")) { + precission = helperfns_read_number(obj->getAttribute("inkscape:test-threshold")); + } + if (!obj->getAttribute("inkscape:test-ignore")) { + pathCompare(ds[index], obj->getAttribute("d"), obj->getAttribute("id"), precission); + } else { + std::cout << "[ WARN ] Item with id:" << obj->getAttribute("id") << " ignored by inkscape:test-ignore" << std::endl; + } + } else { + std::cout << "[ WARN ] Item with id:" << id << " removed on apply LPE" << std::endl; + } + index++; + } + } + std::string svg = ""; + std::vector< const gchar *> failed; +}; + +/* + 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/rendering_tests/CMakeLists.txt b/testfiles/rendering_tests/CMakeLists.txt new file mode 100644 index 0000000..260dfa3 --- /dev/null +++ b/testfiles/rendering_tests/CMakeLists.txt @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Tests to run for 64-bit builds only. These fail in 32-bit builds (possibly due to rounding issues) +# TODO: Figure out actual cause and see if we can fix it +if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) + set(RENDERING_TESTS_64bit + test-rtl-vertical + + # .otf font with compressed SVG glyphs + text-gzipped-svg-glyph + ) +endif() + +#add your test here (do not put the .svg extension) +set(RENDERING_TESTS + # -- Generic tests -- + test-empty + test-dont-crash + test-use + + # -- Selector tests -- + selector-important-002 + selector-important-003 + + multi-style + style-parsing + + # -- 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 + + # 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 + ## Expected rendering generated with Pango 1.44. + + text-glyphs-vertical + ## Expected rendering generated with Pango 1.44. + + # -- LPE tests -- + test-powerstroke-join + + # geometric properties (SVG 2.0 feature) + symbol-svg2-geometry-properties + + ${RENDERING_TESTS_64bit} +) + + +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 .svg -d 96 -e expected_rendering/.png + - inkscape .svg -d 384 -e expected_rendering/-large.png + - 1.0: + - inkscape -d 96 --export-filename=expected_rendering/.png .svg + - inkscape -d 384 --export-filename=expected_rendering/-large.png .svg + - add the test in CMakeLists.txt + - use stable if possible to generate the reference png files + - git add .svg expected_rendering/-large.png expected_rendering/.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 new file mode 100644 index 0000000..7c7c2fb Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/multi-style.png differ diff --git a/testfiles/rendering_tests/expected_rendering/selector-important-002-large.png b/testfiles/rendering_tests/expected_rendering/selector-important-002-large.png new file mode 100644 index 0000000..e92eef0 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/selector-important-002-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/selector-important-002.png b/testfiles/rendering_tests/expected_rendering/selector-important-002.png new file mode 100644 index 0000000..b0af9bd Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/selector-important-002.png differ diff --git a/testfiles/rendering_tests/expected_rendering/selector-important-003-large.png b/testfiles/rendering_tests/expected_rendering/selector-important-003-large.png new file mode 100644 index 0000000..91cb3af Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/selector-important-003-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/selector-important-003.png b/testfiles/rendering_tests/expected_rendering/selector-important-003.png new file mode 100644 index 0000000..dfe3dbc Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/selector-important-003.png differ diff --git a/testfiles/rendering_tests/expected_rendering/style-parsing.png b/testfiles/rendering_tests/expected_rendering/style-parsing.png new file mode 100644 index 0000000..5b60834 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/style-parsing.png differ diff --git a/testfiles/rendering_tests/expected_rendering/symbol-svg2-geometry-properties.png b/testfiles/rendering_tests/expected_rendering/symbol-svg2-geometry-properties.png new file mode 100644 index 0000000..ca5e83e Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/symbol-svg2-geometry-properties.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-baseline-shift-large.png b/testfiles/rendering_tests/expected_rendering/test-baseline-shift-large.png new file mode 100644 index 0000000..29369a8 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-baseline-shift-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-baseline-shift.png b/testfiles/rendering_tests/expected_rendering/test-baseline-shift.png new file mode 100644 index 0000000..45aed90 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-baseline-shift.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-dont-crash.png b/testfiles/rendering_tests/expected_rendering/test-dont-crash.png new file mode 100644 index 0000000..a2d005e Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-dont-crash.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-empty-large.png b/testfiles/rendering_tests/expected_rendering/test-empty-large.png new file mode 100644 index 0000000..34acf1f Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-empty-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-empty.png b/testfiles/rendering_tests/expected_rendering/test-empty.png new file mode 100644 index 0000000..2e0a5fe Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-empty.png differ 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 new file mode 100644 index 0000000..57066fe Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos.png b/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos.png new file mode 100644 index 0000000..38c0117 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-glyph-y-pos.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-powerstroke-join-large.png b/testfiles/rendering_tests/expected_rendering/test-powerstroke-join-large.png new file mode 100644 index 0000000..72d8821 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-powerstroke-join-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-powerstroke-join.png b/testfiles/rendering_tests/expected_rendering/test-powerstroke-join.png new file mode 100644 index 0000000..1eeec07 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-powerstroke-join.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-rtl-vertical-large.png b/testfiles/rendering_tests/expected_rendering/test-rtl-vertical-large.png new file mode 100644 index 0000000..d473a59 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-rtl-vertical-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-rtl-vertical.png b/testfiles/rendering_tests/expected_rendering/test-rtl-vertical.png new file mode 100644 index 0000000..49db6cb Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-rtl-vertical.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-use-large.png b/testfiles/rendering_tests/expected_rendering/test-use-large.png new file mode 100644 index 0000000..c1f4597 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-use-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/test-use.png b/testfiles/rendering_tests/expected_rendering/test-use.png new file mode 100644 index 0000000..a995136 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/test-use.png differ diff --git a/testfiles/rendering_tests/expected_rendering/text-glyphs-combining-large.png b/testfiles/rendering_tests/expected_rendering/text-glyphs-combining-large.png new file mode 100644 index 0000000..5568888 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/text-glyphs-combining-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/text-glyphs-combining.png b/testfiles/rendering_tests/expected_rendering/text-glyphs-combining.png new file mode 100644 index 0000000..32a6781 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/text-glyphs-combining.png differ diff --git a/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical-large.png b/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical-large.png new file mode 100644 index 0000000..f49cbbd Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical.png b/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical.png new file mode 100644 index 0000000..cab1c0b Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/text-glyphs-vertical.png differ diff --git a/testfiles/rendering_tests/expected_rendering/text-gzipped-svg-glyph.png b/testfiles/rendering_tests/expected_rendering/text-gzipped-svg-glyph.png new file mode 100644 index 0000000..8e8a184 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/text-gzipped-svg-glyph.png differ diff --git a/testfiles/rendering_tests/expected_rendering/text-shaping-large.png b/testfiles/rendering_tests/expected_rendering/text-shaping-large.png new file mode 100644 index 0000000..e84ebf5 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/text-shaping-large.png differ diff --git a/testfiles/rendering_tests/expected_rendering/text-shaping.png b/testfiles/rendering_tests/expected_rendering/text-shaping.png new file mode 100644 index 0000000..346ab77 Binary files /dev/null and b/testfiles/rendering_tests/expected_rendering/text-shaping.png differ diff --git a/testfiles/rendering_tests/fonts/Estedad-Medium.ttf b/testfiles/rendering_tests/fonts/Estedad-Medium.ttf new file mode 100644 index 0000000..d4844c2 Binary files /dev/null and b/testfiles/rendering_tests/fonts/Estedad-Medium.ttf differ diff --git a/testfiles/rendering_tests/fonts/GeomTest-Regular.otf b/testfiles/rendering_tests/fonts/GeomTest-Regular.otf new file mode 100644 index 0000000..a008cbf Binary files /dev/null and b/testfiles/rendering_tests/fonts/GeomTest-Regular.otf differ diff --git a/testfiles/rendering_tests/fonts/GeomTest-gzipped-SVG-glyphs.otf b/testfiles/rendering_tests/fonts/GeomTest-gzipped-SVG-glyphs.otf new file mode 100755 index 0000000..d8a89e3 Binary files /dev/null and b/testfiles/rendering_tests/fonts/GeomTest-gzipped-SVG-glyphs.otf differ 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 new file mode 100644 index 0000000..3869703 Binary files /dev/null and b/testfiles/rendering_tests/fonts/Lohit-Telugu.ttf differ diff --git a/testfiles/rendering_tests/fonts/NotoSans-Regular.ttf b/testfiles/rendering_tests/fonts/NotoSans-Regular.ttf new file mode 100644 index 0000000..b031a49 Binary files /dev/null and b/testfiles/rendering_tests/fonts/NotoSans-Regular.ttf differ diff --git a/testfiles/rendering_tests/fonts/NotoSansCJKjp-Regular.otf b/testfiles/rendering_tests/fonts/NotoSansCJKjp-Regular.otf new file mode 100644 index 0000000..296fbeb Binary files /dev/null and b/testfiles/rendering_tests/fonts/NotoSansCJKjp-Regular.otf differ diff --git a/testfiles/rendering_tests/fonts/NotoSansHebrew-Regular.ttf b/testfiles/rendering_tests/fonts/NotoSansHebrew-Regular.ttf new file mode 100644 index 0000000..9bf03ab Binary files /dev/null and b/testfiles/rendering_tests/fonts/NotoSansHebrew-Regular.ttf differ diff --git a/testfiles/rendering_tests/multi-style-import-1.css b/testfiles/rendering_tests/multi-style-import-1.css new file mode 100644 index 0000000..e6fb1e0 --- /dev/null +++ b/testfiles/rendering_tests/multi-style-import-1.css @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* overwritten later */ +rect { fill: red; } +.c1 { fill: red; } + +/* not overwritten */ +#background { fill: white; } +.c5 { fill: #00ccff; } diff --git a/testfiles/rendering_tests/multi-style-import-2.css b/testfiles/rendering_tests/multi-style-import-2.css new file mode 100644 index 0000000..3e0dd9b --- /dev/null +++ b/testfiles/rendering_tests/multi-style-import-2.css @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +rect { fill: blue; } +.c1 { fill: #990099; } + +/* overwritten later */ +.c4 { fill: red; } diff --git a/testfiles/rendering_tests/multi-style.svg b/testfiles/rendering_tests/multi-style.svg new file mode 100644 index 0000000..842f946 --- /dev/null +++ b/testfiles/rendering_tests/multi-style.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + Style "!important" — 002 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + Style "!important" — 003 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testfiles/rendering_tests/style-parsing.svg b/testfiles/rendering_tests/style-parsing.svg new file mode 100644 index 0000000..33e32cb --- /dev/null +++ b/testfiles/rendering_tests/style-parsing.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/testfiles/rendering_tests/symbol-svg2-geometry-properties.svg b/testfiles/rendering_tests/symbol-svg2-geometry-properties.svg new file mode 100644 index 0000000..6eb87d3 --- /dev/null +++ b/testfiles/rendering_tests/symbol-svg2-geometry-properties.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testfiles/rendering_tests/test-baseline-shift.svg b/testfiles/rendering_tests/test-baseline-shift.svg new file mode 100644 index 0000000..7d20d22 --- /dev/null +++ b/testfiles/rendering_tests/test-baseline-shift.svg @@ -0,0 +1,33 @@ + + + + + + + subscript: H2O + superscript: m2 + subscript: H2O + superscript: m2 + + + Sub- and Superscript + + 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 @@ + + + + + + + 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 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + 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..6f44ef8 --- /dev/null +++ b/testfiles/rendering_tests/test-glyph-y-pos.svg @@ -0,0 +1,32 @@ + + + + + + + + G̃g̃X̃x̃ + G̃g̃X̃x̃ + G̃g̃X̃x̃ + + + Composed Glyphs + + 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 @@ + + + + + + diff --git a/testfiles/rendering_tests/test-rtl-vertical.svg b/testfiles/rendering_tests/test-rtl-vertical.svg new file mode 100644 index 0000000..aa6610b --- /dev/null +++ b/testfiles/rendering_tests/test-rtl-vertical.svg @@ -0,0 +1,39 @@ + + + + + + + + أبجد + أبجد + أبجد + + + RTL text in vertical mode + + diff --git a/testfiles/rendering_tests/test-use-ref.svg b/testfiles/rendering_tests/test-use-ref.svg new file mode 100644 index 0000000..0e6edf3 --- /dev/null +++ b/testfiles/rendering_tests/test-use-ref.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testfiles/rendering_tests/test-use.svg b/testfiles/rendering_tests/test-use.svg new file mode 100644 index 0000000..7e8a8ac --- /dev/null +++ b/testfiles/rendering_tests/test-use.svg @@ -0,0 +1,18 @@ + + + + + diff --git a/testfiles/rendering_tests/test.sh b/testfiles/rendering_tests/test.sh new file mode 100755 index 0000000..e31376d --- /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-png-use-dithering false --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-png-use-dithering false --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..646ee05 --- /dev/null +++ b/testfiles/rendering_tests/text-glyphs-combining.svg @@ -0,0 +1,36 @@ + + + + + + + + õoÌ‹oÌ“oÌ›oÌ£oÌ«o̳oÌ»o̓oÍ‹oÍ—oÍ¡ + õoÌ‹oÌ“oÌ›oÌ£oÌ«o̳oÌ»o̓oÍ‹oÍ—oÍ¡ + õoÌ‹oÌ“oÌ›oÌ£oÌ«o̳oÌ»o̓oÍ‹oÍ—oÍ¡ + õoÌ‹oÌ“oÌ›oÌ£oÌ«o̳oÌ»o̓oÍ‹oÍ—oÍ¡ + + + + + + + + diff --git a/testfiles/rendering_tests/text-glyphs-vertical.svg b/testfiles/rendering_tests/text-glyphs-vertical.svg new file mode 100644 index 0000000..585a404 --- /dev/null +++ b/testfiles/rendering_tests/text-glyphs-vertical.svg @@ -0,0 +1,53 @@ + + + + + + + + ㆕㆖㆘A回ーऄG̃g̃X̃x̃ + ㆕㆖㆘A回ーऄG̃g̃X̃x̃ + ㆕㆖㆘A回ーऄG̃g̃X̃x̃ + ㆕㆖㆘A回ーऄG̃g̃X̃x̃ + + + + + + + + diff --git a/testfiles/rendering_tests/text-gzipped-svg-glyph.svg b/testfiles/rendering_tests/text-gzipped-svg-glyph.svg new file mode 100644 index 0000000..88ba336 --- /dev/null +++ b/testfiles/rendering_tests/text-gzipped-svg-glyph.svg @@ -0,0 +1,25 @@ + + + + + + ABC + + 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 @@ + + + + + + + + + نیرو + + بÙسْم٠اللَّه٠الرَّحْمَن٠الرَّحÙيم٠+ + ש×Ö¸×œ×•Ö¹× + + חִירִיק + + â â̂ aÌ‚ aÌ‚Ì‚ + + a aÌ¥ Ä… ą + + ヘ ペ ペ + + తెలà±à°—à±à°²à±‹ + + + à°—à±à°°à°‚థాలయం + + + ఇంకà±â€Œà°¸à±à°•à±‡à°ªà± + + 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 + +#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..b1cb1fb --- /dev/null +++ b/testfiles/src/attributes-test.cpp @@ -0,0 +1,659 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Unit tests for attributes. + * + * Author: + * Jon A. Cruz + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include +#include +#include + +#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::iterator AttrItr; + +std::vector 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,,@,g' | + tr @ \\n | + sed 's,.*,,;s,^,,;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("inkscape:auto-region", 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("-inkscape-stroke", true), + AttributeInfo("id", true), + // AttributeInfo("inkscape:bbox-nodes", true), + // AttributeInfo("inkscape:bbox-paths", true), + AttributeInfo("inkscape:deskcolor", true), + AttributeInfo("inkscape:deskopacity", 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:rotation", 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-alignment", true), + // AttributeInfo("inkscape:snap-alignment-self", true), + // AttributeInfo("inkscape:snap-distribution", 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("inkscape:swatch", 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("alignmenttolerance", true), + AttributeInfo("distributiontolerance", 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), + + // don't know what that is + AttributeInfo("effect", true) + }; + + size_t count = sizeof(all_attrs) / sizeof(all_attrs[0]); + std::vector 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 getIdIds() +{ + std::vector ids; + std::vector 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 ((int)id >= ids.size()) { + ids.resize((int)id + 1); + } + ids[(int)id]++; + } + + return ids; +} + +// Ensure 'supported' value for each known attribute is correct. +TEST(AttributesTest, SupportedKnown) +{ + std::vector 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 != SPAttr::INVALID) << "Matching for attribute '" << it->attr << "'"; + } +} + +// Ensure names of known attributes are preserved when converted to id and back. +TEST(AttributesTest, NameRoundTrip) +{ + std::vector 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 ids = getIdIds(); + for (size_t i = FIRST_VALID_ID; i < ids.size(); ++i) { + if (!ids[i]) { + char const *name = sp_attribute_name((SPAttr)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 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((SPAttr)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/cairo-utils-test.cpp b/testfiles/src/cairo-utils-test.cpp new file mode 100644 index 0000000..3412c4a --- /dev/null +++ b/testfiles/src/cairo-utils-test.cpp @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Tests for classes like Pixbuf from cairo-utils + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include +#include +#include + + +class PixbufTest : public ::testing::Test { + public: + static std::string base64of(const std::string &s) + { + gchar *encoded = g_base64_encode(reinterpret_cast(s.c_str()), s.size()); + std::string r(encoded); + g_free(encoded); + return r; + } + + protected: + void SetUp() override + { + // setup hidden dependency + Inkscape::Application::create(false); + } +}; + +TEST_F(PixbufTest, creatingFromSvgBufferWithoutViewboxOrWidthAndHeightReturnsNull) +{ + std::string svg_buffer( + ""); + double default_dpi = 96.0; + std::string filename_with_svg_extension("malformed.svg"); + + ASSERT_EQ(Inkscape::Pixbuf::create_from_buffer(svg_buffer, default_dpi, filename_with_svg_extension), nullptr); +} + +TEST_F(PixbufTest, creatingFromSvgUriWithoutViewboxOrWidthAndHeightReturnsNull) +{ + std::string uri_data = "image/svg+xml;base64," + base64of(""); + double default_dpi = 96.0; + + ASSERT_EQ(Inkscape::Pixbuf::create_from_data_uri(uri_data.c_str(), default_dpi), nullptr); +} \ No newline at end of file diff --git a/testfiles/src/color-profile-test.cpp b/testfiles/src/color-profile-test.cpp new file mode 100644 index 0000000..b140b3c --- /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 + * + * 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.get(); + } + + 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( SPAttr::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( SPAttr::LOCAL, i); + ASSERT_TRUE( _prof->local != NULL ); + if ( _prof->local ) { + ASSERT_EQ( std::string(i), _prof->local ); + } + } + _prof->setKeyValue( SPAttr::LOCAL, NULL); + ASSERT_EQ( (gchar*)0, _prof->local ); +} + +TEST_F(ColorProfileTest, SetName) +{ + gchar const* cases[] = { + "name", + "something", + }; + + for (auto & i : cases) { + _prof->setKeyValue( SPAttr::NAME, i); + ASSERT_TRUE( _prof->name != NULL ); + if ( _prof->name ) { + ASSERT_EQ( std::string(i), _prof->name ); + } + } + _prof->setKeyValue( SPAttr::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..75c7b98 --- /dev/null +++ b/testfiles/src/curve-test.cpp @@ -0,0 +1,292 @@ +// 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 + +#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; + + static size_t get_refcount(SPCurve const *curve) { return curve->_refcount; } + + 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, testMoveSemantics) +{ + SPCurve c1; + c1.moveto(2, 3); + c1.lineto(4, 5); + + // move construction + SPCurve c2(std::move(c1)); + + ASSERT_EQ(c1.get_segment_count(), 0); + ASSERT_EQ(c2.get_segment_count(), 1); + + // move assignment + c1 = std::move(c2); + + ASSERT_EQ(c1.get_segment_count(), 1); + ASSERT_EQ(c2.get_segment_count(), 0); +} + +TEST_F(CurveTest, testRefCount) +{ + auto c1 = std::make_unique(); + ASSERT_EQ(get_refcount(c1.get()), 1); + { + auto c2 = c1->ref(); + ASSERT_EQ(c2.get(), c1.get()); + ASSERT_EQ(get_refcount(c1.get()), 2); + ASSERT_EQ(get_refcount(c2.get()), 2); + } + ASSERT_EQ(get_refcount(c1.get()), 1); +} + +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 + * + * Copyright (C) 2016 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include + +#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 +#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 + * + * Copyright (C) 2016 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include +#include "preferences.h" + +#include + +// 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(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..7846360 --- /dev/null +++ b/testfiles/src/cxxtests-to-migrate/sp-style-elem-test.h @@ -0,0 +1,166 @@ +// 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 + +#include "test-helpers.h" + +#include "sp-style-elem.h" +#include "xml/repr.h" + +class SPStyleElemTest : public CxxTest::TestSuite +{ +public: + std::unique_ptr _doc; + + SPStyleElemTest() = default; + + virtual ~SPStyleElemTest() = default; + + 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( createSuiteSubclass ); + } + + static void destroySuite( SPStyleElemTest *suite ) { delete suite; } + +// ------------------------------------------------------------------------- +// ------------------------------------------------------------------------- + + + void testSetType() + { + SPStyleElem *style_elem = new SPStyleElem(); + SP_OBJECT(style_elem)->document = _doc.get(); + + SP_OBJECT(style_elem)->setKeyValue( SPAttr::TYPE, "something unrecognized"); + TS_ASSERT( !style_elem->is_css ); + + SP_OBJECT(style_elem)->setKeyValue( SPAttr::TYPE, "text/css"); + TS_ASSERT( style_elem->is_css ); + + SP_OBJECT(style_elem)->setKeyValue( SPAttr::TYPE, "atext/css"); + TS_ASSERT( !style_elem->is_css ); + + SP_OBJECT(style_elem)->setKeyValue( SPAttr::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.get(); + + SP_OBJECT(style_elem)->setKeyValue( SPAttr::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.get(), 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.get(), 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..a6e49e5 --- /dev/null +++ b/testfiles/src/cxxtests-to-migrate/test-helpers.h @@ -0,0 +1,71 @@ +// 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 + +#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 +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); + } + + auto tmp = std::unique_ptr(SPDocument::createNewDoc(NULL, TRUE, true)); + if ( tmp ) { + fun( suite ); + if ( suite ) + { + suite->_doc = std::move(tmp); + } + } + + 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 + +#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(SP_VERB_LAST) ); + TS_ASSERT_EQUALS( static_cast(SP_VERB_LAST) + 1, TestHook::getInternalTableSize() ); + } + + void testEnumFixed() + { + TS_ASSERT_EQUALS( 0, static_cast(SP_VERB_INVALID) ); + TS_ASSERT_EQUALS( 1, static_cast(SP_VERB_NONE) ); + + TS_ASSERT_DIFFERS( 0, static_cast(SP_VERB_LAST) ); + TS_ASSERT_DIFFERS( 1, static_cast(SP_VERB_LAST) ); + } + + void testFetch() + { + for ( int i = 0; i < static_cast(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(i) ); + + if ( i != static_cast(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(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 + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtest/gtest.h" + +#include + +#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..faa3e0f --- /dev/null +++ b/testfiles/src/drag-and-drop-svgz.cpp @@ -0,0 +1,70 @@ +// 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 + +#include "extension/init.h" +#include "extension/db.h" +#include "extension/find_extension_by_mime.h" +#include "extension/internal/svgz.h" +#include "io/resource.h" +#include "path-prefix.h" +#include "preferences.h" + +#include "gtest/gtest.h" + +#include +class SvgzImportTest : public DocPerCaseTest { + public: + void TestBody() override + { + Inkscape::Extension::init(); + 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"); + if (!ext) { + std::cerr << "SvgzImportTest: Failed to find mime type!" << std::endl; + } + ext->set_gui(true); + + using namespace Inkscape::IO::Resource; + auto fn = get_path_string(SYSTEM, EXAMPLES, "tiger.svgz"); + + auto imod = dynamic_cast(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-test.cpp b/testfiles/src/lpe-test.cpp new file mode 100644 index 0000000..87d263f --- /dev/null +++ b/testfiles/src/lpe-test.cpp @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * LPE tests + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace Inkscape; +using namespace Inkscape::LivePathEffect; + +class LPETest : public LPESPathsTest { +public: + void run() { + testDoc(svg); + } +}; + +// A) FILE BASED TESTS +// TEST_F(LPETest, Bool_multi_px_1_1) { run(); } +// TEST_F(LPETest, Bool_multi_mm_1_1) { run(); } +TEST_F(LPETest, AttachPath_0_92_5_mixed) { run(); } +TEST_F(LPETest, AttachPath_mm_1_0_2) { run(); } +TEST_F(LPETest, AttachPath_px_1_0_2) { run(); } +TEST_F(LPETest, BoundingBox_mixed_0_92_5) { run(); } +TEST_F(LPETest, BoundingBox_mm_1_0_2) { run(); } +TEST_F(LPETest, BoundingBox_px_1_0_2) { run(); } +TEST_F(LPETest, CloneOriginal_mixed_0_92_5) { run(); } +// linked item is broken in 1.0.2 because group cliboard items, use same version of 1.1 but resaved in 1.2 to get comapat in 1.0.1 or before the group clipboard is added +TEST_F(LPETest, CloneOriginal_boken_1_0_2) { run(); } +TEST_F(LPETest, CloneOriginal_mixed_px_1_1) { run(); } +TEST_F(LPETest, CloneOriginal_mixed_mm_1_1) { run(); } +TEST_F(LPETest, ConstructGrid_mixed_0_92_5) { run(); } +TEST_F(LPETest, ConstructGrid_mm_1_0_2) { run(); } +TEST_F(LPETest, ConstructGrid_px_1_0_2) { run(); } +TEST_F(LPETest, Transform2Points_path_0_92_5) { run(); } +TEST_F(LPETest, Transform2Points_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Transform2Points_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, VonCoch_path_0_92_5) { run(); } +TEST_F(LPETest, VonCoch_multi_px_1_0_2) { run(); } +TEST_F(LPETest, VonCoch_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, StitchSubPaths_path_0_92_5) { run(); } +TEST_F(LPETest, StitchSubPaths_multi_px_1_0_2) { run(); } +TEST_F(LPETest, StitchSubPaths_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, Spiro_mixed_0_92_5) { run(); } +TEST_F(LPETest, Spiro_mm_1_0_2) { run(); } +TEST_F(LPETest, Spiro_px_1_0_2) { run(); } +TEST_F(LPETest, Slice_multi_px_1_1) { run(); } +TEST_F(LPETest, Slice_multi_mm_1_1) { run(); } +TEST_F(LPETest, Simplify_path_0_92_5) { run(); } +TEST_F(LPETest, Simplify_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Simplify_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, ShowHandles_path_0_92_5) { run(); } +TEST_F(LPETest, ShowHandles_multi_px_1_0_2) { run(); } +TEST_F(LPETest, ShowHandles_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, Ruler_path_0_92_5) { run(); } +TEST_F(LPETest, Ruler_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Ruler_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, RoughHatches_path_0_92_5) { run(); } +TEST_F(LPETest, RoughHatches_multi_px_1_0_2) { run(); } +TEST_F(LPETest, RoughHatches_multi_mm_1_0_2) { run(); } +// Rougen Test till 1.1 fail because wrong implementation of rand on the LPE +TEST_F(LPETest, Roughen_path_1_1) { run(); } +TEST_F(LPETest, EllipseFromPoints_multi_px_1_0_2) { run(); } +TEST_F(LPETest, EllipseFromPoints_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, PowerMask_multi_px_1_0_2) { run(); } +TEST_F(LPETest, PowerMask_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, PowerClip_multi_px_1_0_2) { run(); } +TEST_F(LPETest, PowerClip_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, PerspectiveEnvelope_mixed_0_92_5) { run(); } +TEST_F(LPETest, PerspectiveEnvelope_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, PerspectiveEnvelope_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Offset_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Offset_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, Offset_multi_px_1_1) { run(); } +TEST_F(LPETest, MirrorSymmetry_path_0_92_5) { run(); } +TEST_F(LPETest, MirrorSymmetry_multi_px_1_0_2) { run(); } +TEST_F(LPETest, MirrorSymmetry_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, MeasureSegments_multi_px_1_0_2) { run(); } +TEST_F(LPETest, MeasureSegments_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, Lattice2_path_0_92_5) { run(); } +TEST_F(LPETest, Lattice2_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Lattice2_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, Knot_path_0_92_5) { run(); } +TEST_F(LPETest, Knot_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Knot_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, JoinType_multi_px_1_0_2) { run(); } +TEST_F(LPETest, JoinType_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, Interpolate_path_0_92_5) { run(); } +TEST_F(LPETest, Interpolate_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Interpolate_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, InterpolatePoints_path_0_92_5) { run(); } +TEST_F(LPETest, InterpolatePoints_multi_px_1_0_2) { run(); } +TEST_F(LPETest, InterpolatePoints_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, Gears_path_0_92_5) { run(); } +TEST_F(LPETest, Gears_multi_px_1_0_2) { run(); } +TEST_F(LPETest, Gears_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, FilletChamfer_multi_px_1_0_2) { run(); } +TEST_F(LPETest, FilletChamfer_multi_mm_1_0_2) { run(); } +// NEED to test on 0.92 no working one here (gnome 40) +// TEST_F(LPETest, FillBetweenStrokes_path_0_92_5) { run(); } +TEST_F(LPETest, FillBetweenStrokes_path_multi_px_1_0_2) { run(); } +TEST_F(LPETest, FillBetweenStrokes_path_multi_mm_1_0_2) { run(); } +// NEED to test on 0.92 no working one here (gnome 40) +// TEST_F(LPETest, FillBetweenMany_multi_0_92_5) { run(); } +TEST_F(LPETest, FillBetweenMany_multi_px_1_0_2) { run(); } +TEST_F(LPETest, FillBetweenMany_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, Ellipse5pts_path_0_92_5) { run(); } +TEST_F(LPETest, Ellipse5pts_ellipse_px_1_0_2) { run(); } +TEST_F(LPETest, Ellipse5pts_ellipse_mm_1_0_2) { run(); } +TEST_F(LPETest, DashedStroke_multi_px_1_0_2) { run(); } +TEST_F(LPETest, DashedStroke_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, RotateCopies_multi_mm_1_0_2) { run(); } +TEST_F(LPETest, RotateCopies_multi_px_1_0_2) { run(); } +// B) CUSTOM TESTS +// BOOL LPE +TEST_F(LPETest, Bool_canBeApplyedToNonSiblingPaths) +{ + std::string svg("\ +\ + \ + \ + \ + \ + \ + \ + \ +"); + + SPDocument *doc = SPDocument::createNewDocFromMem(svg.c_str(), svg.size(), true); + doc->ensureUpToDate(); + + auto lpe_item = dynamic_cast(doc->getObjectById("rect1")); + ASSERT_TRUE(lpe_item != nullptr); + + auto lpe_bool_op_effect = dynamic_cast(lpe_item->getFirstPathEffectOfType(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(doc->getObjectById(operand_path.substr(1))); + ASSERT_TRUE(circle != nullptr); +} \ No newline at end of file diff --git a/testfiles/src/lpe64-test.cpp b/testfiles/src/lpe64-test.cpp new file mode 100644 index 0000000..91bf1c7 --- /dev/null +++ b/testfiles/src/lpe64-test.cpp @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * LPE 64B tests + * Because some issues rounding in 32B windows we move this tests only to 64B + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include +#include +#include + +using namespace Inkscape; +using namespace Inkscape::LivePathEffect; + +class LPE64Test : public LPESPathsTest { +public: + void run() { + testDoc(svg); + } +}; + + +// A) FILE BASED TESTS +TEST_F(LPE64Test, Bendpath_mixed_0_92_5) { run(); } +TEST_F(LPE64Test, Bendpath_shape_1_0_2) { run(); } +TEST_F(LPE64Test, Bendpath_shapeClipPath_1_0_2) { run(); } +TEST_F(LPE64Test, Bendpath_multiGroup_1_0_2) { run(); } +TEST_F(LPE64Test, Bendpath_stackNested_mm_1_0_2) { run(); } +TEST_F(LPE64Test, Bendpath_stackNested_px_1_0_2) { run(); } +TEST_F(LPE64Test, BSpline_mixed_0_92_5) { run(); } +TEST_F(LPE64Test, BSpline_mm_1_0_2) { run(); } +TEST_F(LPE64Test, BSpline_px_1_0_2) { run(); } +TEST_F(LPE64Test, TaperStroke_multi_px_1_0_2) { run(); } +TEST_F(LPE64Test, TaperStroke_multi_mm_1_0_2) { run(); } +TEST_F(LPE64Test, Sketch_path_0_92_5) { run(); } +TEST_F(LPE64Test, Sketch_multi_px_1_0_2) { run(); } +TEST_F(LPE64Test, Sketch_multi_mm_1_0_2) { run(); } +TEST_F(LPE64Test, PowerStroke_multi_mm_1_0_2) { run(); } +TEST_F(LPE64Test, PowerStroke_multi_px_1_0_2) { run(); } +TEST_F(LPE64Test, PatternAlongPath_mixed_0_92_5) { run(); } +TEST_F(LPE64Test, PatternAlongPath_shape_1_0_2) { run(); } +TEST_F(LPE64Test, PatternAlongPath_path_1_0_2) { run(); } +TEST_F(LPE64Test, PatternAlongPath_multiple_mm_1_0_2) { run(); } +TEST_F(LPE64Test, PatternAlongPath_multiple_px_1_0_2) { run(); } +TEST_F(LPE64Test, EnvelopeDeformation_multi_0_92_5) { run(); } +TEST_F(LPE64Test, EnvelopeDeformation_multi_px_1_0_2) { run(); } +TEST_F(LPE64Test, EnvelopeDeformation_multi_mm_1_0_2) { run(); } + +// B) CUSTOM TESTS \ 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..2112937 --- /dev/null +++ b/testfiles/src/object-set-test.cpp @@ -0,0 +1,706 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include <2geom/transforms.h> +using namespace Inkscape; +using namespace Inkscape::XML; + +class ObjectSetTest: public DocPerCaseTest { +public: + ObjectSetTest() { + auto *const _doc = this->_doc.get(); + N = _doc->getRoot()->children.size(); + + 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(_doc->getObjectByRepr(repr))); + repr = _doc->getReprDoc()->createElement("svg:rect"); + _doc->getRoot()->appendChild(repr); + r2.reset(dynamic_cast(_doc->getObjectByRepr(repr))); + repr = _doc->getReprDoc()->createElement("svg:rect"); + _doc->getRoot()->appendChild(repr); + r3.reset(dynamic_cast(_doc->getObjectByRepr(repr))); + EXPECT_EQ(N + 3, _doc->getRoot()->children.size());// 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 r1; + std::unique_ptr r2; + std::unique_ptr r3; + ObjectSet* set; + ObjectSet* set2; + int N; //!< Number of root children in default document +}; + +#define SP_IS_CLONE(obj) (dynamic_cast(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 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 list1 {A, B, C, D}; + std::vector 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 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.get()); + 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(N + 6, _doc->getRoot()->children.size());// 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(N + 1, _doc->getRoot()->children.size()); + EXPECT_EQ(1, set->size()); + set->ungroup(); + EXPECT_EQ(N + 3, _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(N + 6, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_NE(nullptr,dynamic_cast(*(set->items().begin()))); + EXPECT_EQ(nullptr,dynamic_cast(*(set->items().begin()))); + set->unlink(); + EXPECT_EQ(N + 6, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_EQ(nullptr,dynamic_cast(*(set->items().begin()))); + EXPECT_NE(nullptr,dynamic_cast(*(set->items().begin()))); + set->clone(); //creates 3 clones + set->clone(); //creates 3 clones of clones + EXPECT_EQ(N + 12, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_NE(nullptr,dynamic_cast( ((SPUse*)(*(set->items().begin())))->get_original()));//"original is a Use" + set->unlink(); //clone of clone of rect -> rect + EXPECT_EQ(nullptr,dynamic_cast(*(set->items().begin()))); + EXPECT_NE(nullptr,dynamic_cast(*(set->items().begin()))); + set->clone(); + set->set(*(set->items().begin())); + set->cloneOriginal();//get clone original + EXPECT_EQ(N + 15, _doc->getRoot()->children.size()); + EXPECT_EQ(1, set->size()); + EXPECT_NE(nullptr,dynamic_cast(*(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(N + 6, _doc->getRoot()->children.size());// 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(N + 1, _doc->getRoot()->children.size()); + EXPECT_EQ(1, set->size()); + set->ungroup(); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(N + 3, _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(N + 6, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_NE(nullptr, dynamic_cast(*(set->items().begin()))); + EXPECT_EQ(nullptr, dynamic_cast(*(set->items().begin()))); + set->unlinkRecursive(false, true); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(N + 6, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_EQ(nullptr, dynamic_cast(*(set->items().begin()))); + EXPECT_NE(nullptr, dynamic_cast(*(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(N + 12, _doc->getRoot()->children.size()); + EXPECT_EQ(3, set->size()); + EXPECT_NE(nullptr, dynamic_cast( ((SPUse*)(*(set->items().begin())))->get_original()));//"original is a Use" + set->unlinkRecursive(false, true); //clone of clone of rect -> rect + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(nullptr, dynamic_cast(*(set->items().begin()))); + EXPECT_NE(nullptr, dynamic_cast(*(set->items().begin()))); + set->clone(); + EXPECT_TRUE(containsClone(set)); + set->set(*(set->items().begin())); + set->cloneOriginal();//get clone original + EXPECT_EQ(N + 15, _doc->getRoot()->children.size()); + EXPECT_EQ(1, set->size()); + EXPECT_NE(nullptr, dynamic_cast(*(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(false, true); + EXPECT_FALSE(containsClone(set)); + EXPECT_EQ(2, set->size()); + + TearDownTestCase(); + SetUpTestCase(); +} + +TEST_F(ObjectSetTest, ZOrder) { + //sp_object_compare_position_bool == true iff "r1set(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(N + 2, _doc->getRoot()->children.size()); + set->breakApart(); + EXPECT_EQ(2, set->size()); + EXPECT_EQ(N + 3, _doc->getRoot()->children.size()); + set->deleteItems(); + set->set(r3.get()); + set->toCurves(); + r3.release(); + auto x = set->singleItem(); + EXPECT_NE(nullptr,dynamic_cast(x)); + EXPECT_EQ(nullptr,dynamic_cast(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(); +} + +TEST_F(ObjectSetTest, toMarker) { + r1->x = 12; + r1->y = 34; + r1->width = 56; + r1->height = 78; + r1->set_shape(); + r1->updateRepr(); + + r2->x = 6; + r2->y = 7; + r2->width = 8; + r2->height = 9; + r2->set_shape(); + r2->updateRepr(); + + r3->x = 10; + r3->y = 10; + r3->width = 10; + r3->height = 10; + r3->set_shape(); + r3->updateRepr(); + + // add rects to set in different order than they appear in the document, + // to verify selection order independence. + set->set(r1.get()); + set->add(r3.get()); + set->add(r2.get()); + set->toMarker(); + + // original items got deleted + r1.release(); + r2.release(); + r3.release(); + + auto markers = _doc->getObjectsByElement("marker"); + ASSERT_EQ(markers.size(), 1); + + auto marker = dynamic_cast(markers[0]); + ASSERT_NE(marker, nullptr); + + EXPECT_FLOAT_EQ(marker->refX.computed, 31); + EXPECT_FLOAT_EQ(marker->refY.computed, 52.5); + EXPECT_FLOAT_EQ(marker->markerWidth.computed, 62); + EXPECT_FLOAT_EQ(marker->markerHeight.computed, 105); + + auto markerchildren = marker->childList(false); + ASSERT_EQ(markerchildren.size(), 3); + + auto *markerrect1 = dynamic_cast(markerchildren[0]); + auto *markerrect2 = dynamic_cast(markerchildren[1]); + + ASSERT_NE(markerrect1, nullptr); + ASSERT_NE(markerrect2, nullptr); + + EXPECT_FLOAT_EQ(markerrect1->x.value, 6); + EXPECT_FLOAT_EQ(markerrect1->y.value, 27); + EXPECT_FLOAT_EQ(markerrect1->width.value, 56); + EXPECT_FLOAT_EQ(markerrect1->height.value, 78); + + EXPECT_FLOAT_EQ(markerrect2->x.value, 0); + EXPECT_FLOAT_EQ(markerrect2->y.value, 0); + EXPECT_FLOAT_EQ(markerrect2->width.value, 8); + EXPECT_FLOAT_EQ(markerrect2->height.value, 9); +} diff --git a/testfiles/src/object-style-test.cpp b/testfiles/src/object-style-test.cpp new file mode 100644 index 0000000..ff2118b --- /dev/null +++ b/testfiles/src/object-style-test.cpp @@ -0,0 +1,199 @@ +// 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 +#include + +#include +#include +#include + +using namespace Inkscape; +using namespace Inkscape::XML; + +class ObjectTest: public DocPerCaseTest { +public: + ObjectTest() { + char const *docString = "\ +\ +\ +\ + \ + \ + \ + \ + /\ + \ + \ + \ +\ +"; + doc.reset(SPDocument::createNewDocFromMem(docString, static_cast(strlen(docString)), false)); + doc->ensureUpToDate(); + } + + ~ObjectTest() override = default; + + std::unique_ptr 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(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(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(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(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(doc->getObjectById("one")); + ASSERT_TRUE(one != nullptr); + + EXPECT_EQ(one->style->fill.style_src, SPStyleSrc::STYLE_PROP); + EXPECT_EQ(one->style->stroke.style_src, SPStyleSrc::STYLE_PROP); + EXPECT_EQ(one->style->opacity.style_src, SPStyleSrc::STYLE_SHEET); + EXPECT_EQ(one->style->stroke_width.style_src, SPStyleSrc::STYLE_PROP); + + SPRect *two = dynamic_cast(doc->getObjectById("two")); + ASSERT_TRUE(two != nullptr); + + EXPECT_EQ(two->style->fill.style_src, SPStyleSrc::STYLE_SHEET); + EXPECT_EQ(two->style->stroke.style_src, SPStyleSrc::STYLE_PROP); + EXPECT_EQ(two->style->opacity.style_src, SPStyleSrc::STYLE_SHEET); + EXPECT_EQ(two->style->stroke_width.style_src, SPStyleSrc::STYLE_PROP); + + SPRect *three = dynamic_cast(doc->getObjectById("three")); + ASSERT_TRUE(three != nullptr); + + EXPECT_EQ(three->style->fill.style_src, SPStyleSrc::STYLE_PROP); + EXPECT_EQ(three->style->stroke.style_src, SPStyleSrc::STYLE_PROP); + EXPECT_EQ(three->style->opacity.style_src, SPStyleSrc::STYLE_SHEET); + EXPECT_EQ(three->style->stroke_width.style_src, SPStyleSrc::STYLE_PROP); + + SPRect *four = dynamic_cast(doc->getObjectById("four")); + ASSERT_TRUE(four != nullptr); + + EXPECT_EQ(four->style->fill.style_src, SPStyleSrc::STYLE_SHEET); + EXPECT_EQ(four->style->stroke.style_src, SPStyleSrc::STYLE_PROP); + EXPECT_EQ(four->style->opacity.style_src, SPStyleSrc::STYLE_SHEET); + EXPECT_EQ(four->style->stroke_width.style_src, SPStyleSrc::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(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(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(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(doc->getObjectById("eight")); + ASSERT_TRUE(eight != nullptr); + + EXPECT_EQ(eight->style->stroke_width.get_value(), Glib::ustring("50%")); + + // stroke-width in percent is relative to viewport size, which is 300x150 in this example. + // 50% is 118.59 == ((300^2 + 150^2) / 2)^0.5 * 0.5 + EXPECT_FLOAT_EQ(eight->style->stroke_width.computed, 118.58541); +} diff --git a/testfiles/src/object-test.cpp b/testfiles/src/object-test.cpp new file mode 100644 index 0000000..ded67f1 --- /dev/null +++ b/testfiles/src/object-test.cpp @@ -0,0 +1,204 @@ +// 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 +#include +#include +#include + +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 test + + + + + + + + + + + + + + + + + + + TEST + + + + + + + )A"; + doc.reset(SPDocument::createNewDocFromMem(docString, static_cast(strlen(docString)), false)); + } + + ~ObjectTest() override = default; + + std::unique_ptr 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(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 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(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 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(group->get_child_by_repr(new_group)); + ASSERT_TRUE(n_group != nullptr); + + std::vector 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(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.get(), 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/path-boolop-test.cpp b/testfiles/src/path-boolop-test.cpp new file mode 100644 index 0000000..cc71856 --- /dev/null +++ b/testfiles/src/path-boolop-test.cpp @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include +#include <2geom/svg-path-writer.h> + +class PathBoolopTest : public ::testing::Test +{ + public: + std::string rectangle_bigger = "M 0,0 L 0,2 L 2,2 L 2,0 z"; + std::string rectangle_smaller = "M 0.5,0.5 L 0.5,1.5 L 1.5,1.5 L 1.5,0.5 z"; + std::string rectangle_outside = "M 0,1.5 L 0.5,1.5 L 0.5,2.5 L 0,2.5 z"; + std::string rectangle_outside_union = "M 0,0 L 0,1.5 L 0,2 L 0,2.5 L 0.5,2.5 L 0.5,2 L 2,2 L 2,0 L 0,0 z"; + Geom::PathVector pvRectangleBigger; + Geom::PathVector pvRectangleSmaller; + Geom::PathVector pvRectangleOutside; + Geom::PathVector pvTargetUnion; + Geom::PathVector pvEmpty; + PathBoolopTest() { + pvRectangleBigger = sp_svg_read_pathv(rectangle_bigger.c_str()); + pvRectangleSmaller = sp_svg_read_pathv(rectangle_smaller.c_str()); + pvRectangleOutside = sp_svg_read_pathv(rectangle_outside.c_str()); + pvTargetUnion = sp_svg_read_pathv(rectangle_outside_union.c_str()); + pvEmpty = sp_svg_read_pathv(""); + } + void comparePaths(Geom::PathVector result, Geom::PathVector target){ + Geom::SVGPathWriter wr; + wr.feed(result); + std::string resultD = wr.str(); + wr.clear(); + wr.feed(target); + std::string targetD = wr.str(); + EXPECT_EQ(resultD, targetD); + EXPECT_EQ(result, target); + } +}; + +TEST_F(PathBoolopTest, UnionOutside){ + // test that the union of two objects where one is outside the other results in a new larger shape + Geom::PathVector pvRectangleUnion = sp_pathvector_boolop(pvRectangleBigger, pvRectangleOutside, bool_op_union, fill_oddEven, fill_oddEven); + comparePaths(pvRectangleUnion, pvTargetUnion); +} + +TEST_F(PathBoolopTest, UnionOutsideSwap){ + // test that the union of two objects where one is outside the other results in a new larger shape, even when the order is reversed + Geom::PathVector pvRectangleUnion = sp_pathvector_boolop(pvRectangleOutside, pvRectangleBigger, bool_op_union, fill_oddEven, fill_oddEven); + comparePaths(pvRectangleUnion, pvTargetUnion); +} + +TEST_F(PathBoolopTest, UnionInside){ + // test that the union of two objects where one is completely inside the other is the larger shape + Geom::PathVector pvRectangleUnion = sp_pathvector_boolop(pvRectangleBigger, pvRectangleSmaller, bool_op_union, fill_oddEven, fill_oddEven); + comparePaths(pvRectangleUnion, pvRectangleBigger); +} + +TEST_F(PathBoolopTest, UnionInsideSwap){ + // test that the union of two objects where one is completely inside the other is the larger shape, even when the order is swapped + Geom::PathVector pvRectangleUnion = sp_pathvector_boolop(pvRectangleSmaller, pvRectangleBigger, bool_op_union, fill_oddEven, fill_oddEven); + comparePaths(pvRectangleUnion, pvRectangleBigger); +} + +TEST_F(PathBoolopTest, IntersectionInside){ + // test that the intersection of two objects where one is completely inside the other is the smaller shape + Geom::PathVector pvRectangleIntersection = sp_pathvector_boolop(pvRectangleBigger, pvRectangleSmaller, bool_op_inters, fill_oddEven, fill_oddEven); + comparePaths(pvRectangleIntersection, pvRectangleSmaller); +} + +TEST_F(PathBoolopTest, DifferenceInside){ + // test that the difference of two objects where one is completely inside the other is an empty path + Geom::PathVector pvRectangleDifference = sp_pathvector_boolop(pvRectangleBigger, pvRectangleSmaller, bool_op_diff, fill_oddEven, fill_oddEven); + comparePaths(pvRectangleDifference, pvEmpty); +} + +TEST_F(PathBoolopTest, DifferenceOutside){ + // test that the difference of two objects where one is completely outside the other is multiple shapes + Geom::PathVector pvRectangleDifference = sp_pathvector_boolop(pvRectangleSmaller, pvRectangleBigger, bool_op_diff, fill_oddEven, fill_oddEven); + Geom::PathVector pvBothPaths = pvRectangleBigger; + + for(Geom::Path _path : pvRectangleSmaller){ + pvBothPaths.push_back(_path); + } + + comparePaths(pvRectangleDifference, pvBothPaths); +} + +// \ No newline at end of file diff --git a/testfiles/src/rebase-hrefs-test.cpp b/testfiles/src/rebase-hrefs-test.cpp new file mode 100644 index 0000000..e1c91fb --- /dev/null +++ b/testfiles/src/rebase-hrefs-test.cpp @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * Test rebasing URI attributes + */ +/* + * Authors: + * Thomas Holder + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "xml/rebase-hrefs.h" + +#include +#include + +#include "object/sp-object.h" + +using namespace Inkscape::XML; + +#ifdef _WIN32 +#define BASE_DIR_DIFFERENT_ROOT "D:\\foo\\bar" +#define BASE_DIR "C:\\foo\\bar" +#define BASE_URL "file:///C:/foo/bar" +#else +#define BASE_DIR_DIFFERENT_ROOT "/different/root" +#define BASE_DIR "/foo/bar" +#define BASE_URL "file://" BASE_DIR +#endif + +static char const *const docString = R"""( + + + + + + + + + + + + + + + + + + + + +)"""; + +class ObjectTest : public DocPerCaseTest +{ +public: + std::unique_ptr doc; + + ObjectTest() { doc.reset(SPDocument::createNewDocFromMem(docString, strlen(docString), false)); } + + void assert_nonfile_unchanged() const + { + ASSERT_STREQ(doc->getObjectById("img03")->getAttribute("xlink:href"), "http://host/a.png"); + ASSERT_STREQ(doc->getObjectById("img04")->getAttribute("xlink:href"), "data:text/plain,xxx"); + + ASSERT_STREQ(doc->getObjectById("img05")->getAttribute("xlink:href"), ""); + ASSERT_STREQ(doc->getObjectById("img06")->getAttribute("xlink:href"), "#fragment"); + ASSERT_STREQ(doc->getObjectById("img07")->getAttribute("xlink:href"), "?query"); + ASSERT_STREQ(doc->getObjectById("img08")->getAttribute("xlink:href"), "/absolute/path"); + ASSERT_STREQ(doc->getObjectById("img09")->getAttribute("xlink:href"), "//network/path"); + } +}; + +TEST_F(ObjectTest, RebaseHrefs) +{ + rebase_hrefs(doc.get(), BASE_DIR G_DIR_SEPARATOR_S "c", false); + assert_nonfile_unchanged(); + ASSERT_STREQ(doc->getObjectById("img01")->getAttribute("xlink:href"), "../a.png"); + ASSERT_STREQ(doc->getObjectById("img02")->getAttribute("xlink:href"), "b/a.png"); + + // no base + rebase_hrefs(doc.get(), nullptr, false); + assert_nonfile_unchanged(); + ASSERT_STREQ(doc->getObjectById("img01")->getAttribute("xlink:href"), BASE_URL "/a.png"); + ASSERT_STREQ(doc->getObjectById("img02")->getAttribute("xlink:href"), BASE_URL "/c/b/a.png"); + + rebase_hrefs(doc.get(), BASE_DIR, false); + assert_nonfile_unchanged(); + ASSERT_STREQ(doc->getObjectById("img01")->getAttribute("xlink:href"), "a.png"); + ASSERT_STREQ(doc->getObjectById("img02")->getAttribute("xlink:href"), "c/b/a.png"); + + // base with different root + rebase_hrefs(doc.get(), BASE_DIR_DIFFERENT_ROOT, false); + assert_nonfile_unchanged(); + ASSERT_STREQ(doc->getObjectById("img01")->getAttribute("xlink:href"), BASE_URL "/a.png"); + ASSERT_STREQ(doc->getObjectById("img02")->getAttribute("xlink:href"), BASE_URL "/c/b/a.png"); +} + +static std::map rebase_attrs_test_helper(SPDocument *doc, char const *id, + char const *old_base, char const *new_base) +{ + std::map attributemap; + auto attributes = rebase_href_attrs(old_base, new_base, doc->getObjectById(id)->getRepr()->attributeList()); + for (const auto &item : attributes) { + attributemap[g_quark_to_string(item.key)] = item.value.pointer(); + } + return attributemap; +} + +TEST_F(ObjectTest, RebaseHrefAttrs) +{ + std::map amap; + + amap = rebase_attrs_test_helper(doc.get(), "img01", BASE_DIR, BASE_DIR G_DIR_SEPARATOR_S "c"); + ASSERT_STREQ(amap["xlink:href"].c_str(), "../a.png"); + amap = rebase_attrs_test_helper(doc.get(), "img02", BASE_DIR, BASE_DIR G_DIR_SEPARATOR_S "c"); + ASSERT_STREQ(amap["xlink:href"].c_str(), "b/a.png"); + amap = rebase_attrs_test_helper(doc.get(), "img06", BASE_DIR, BASE_DIR G_DIR_SEPARATOR_S "c"); + ASSERT_STREQ(amap["xlink:href"].c_str(), "#fragment"); + amap = rebase_attrs_test_helper(doc.get(), "img10", BASE_DIR, BASE_DIR G_DIR_SEPARATOR_S "c"); + ASSERT_STREQ(amap["xlink:href"].c_str(), "../b/a.png"); + + amap = rebase_attrs_test_helper(doc.get(), "a01", BASE_DIR, BASE_DIR G_DIR_SEPARATOR_S "c"); + ASSERT_STREQ(amap["xlink:href"].c_str(), "../other.svg"); + amap = rebase_attrs_test_helper(doc.get(), "a02", BASE_DIR, BASE_DIR G_DIR_SEPARATOR_S "c"); + ASSERT_STREQ(amap["xlink:href"].c_str(), "http://host/other.svg"); + + amap = rebase_attrs_test_helper(doc.get(), "img01", BASE_DIR, BASE_DIR_DIFFERENT_ROOT); + ASSERT_STREQ(amap["xlink:href"].c_str(), BASE_URL "/a.png"); +} + +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/sp-glyph-kerning-test.cpp b/testfiles/src/sp-glyph-kerning-test.cpp new file mode 100644 index 0000000..2c737ee --- /dev/null +++ b/testfiles/src/sp-glyph-kerning-test.cpp @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * SPGlyphKerning test + *//* + * + * Authors: + * Cosmin Dancu + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include +#include + +TEST(SPGlyphKerningTest, EmptyGlyphNamesDoNotContainAnything) { + GlyphNames empty_glyph_names(nullptr); + ASSERT_FALSE(empty_glyph_names.contains("foo")); +} + +TEST(SPGlyphKerningTest, GlyphNamesContainEachName) { + GlyphNames glyph_names("name1 name2"); + ASSERT_TRUE(glyph_names.contains("name1")); + ASSERT_TRUE(glyph_names.contains("name2")); +} diff --git a/testfiles/src/sp-gradient-test.cpp b/testfiles/src/sp-gradient-test.cpp new file mode 100644 index 0000000..a4dd115 --- /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 +#include +#include +#include +#include <2geom/transforms.h> +#include +#include +#include + +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) { + gr->document = _doc.get(); + + gr->setKeyValue(SPAttr::GRADIENTTRANSFORM, "translate(5, 8)"); + EXPECT_TRUE(Geom::are_near(Geom::Affine(Geom::Translate(5.0, 8.0)), gr->gradientTransform)); + + gr->setKeyValue(SPAttr::GRADIENTTRANSFORM, ""); + EXPECT_TRUE(Geom::are_near(Geom::identity(), gr->gradientTransform)); + + gr->setKeyValue(SPAttr::GRADIENTTRANSFORM, "rotate(90)"); + EXPECT_TRUE(Geom::are_near(Geom::Affine(Geom::Rotate::from_degrees(90.0)), gr->gradientTransform)); +} + +TEST_F(SPGradientTest, Write) { + gr->document = _doc.get(); + + gr->setKeyValue(SPAttr::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"); + 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) { + gr->document = _doc.get(); + + 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)); + + gr->setKeyValue( SPAttr::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 +#include +#include +#include +#include + +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("\ +\ + \ + \ + \ + \ +"); + + SPDocument *doc = SPDocument::createNewDocFromMem(svg.c_str(), svg.size(), true); + + auto group = dynamic_cast(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..90a635d --- /dev/null +++ b/testfiles/src/sp-object-test.cpp @@ -0,0 +1,122 @@ +// 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 +#include +#include +#include +#include +#include +#include + +using namespace Inkscape; +using namespace Inkscape::XML; + +class SPObjectTest: public DocPerCaseTest { +public: + SPObjectTest() { + auto *const _doc = this->_doc.get(); + 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 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..edf448e --- /dev/null +++ b/testfiles/src/style-elem-test.cpp @@ -0,0 +1,71 @@ +// 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 +#include + +#include +#include +#include + +using namespace Inkscape; +using namespace Inkscape::XML; + +class ObjectTest: public DocPerCaseTest { +public: + ObjectTest() { + char const *docString = "\ +\ +\ +\ +"; + doc.reset(SPDocument::createNewDocFromMem(docString, static_cast(strlen(docString)), false)); + } + + ~ObjectTest() override = default; + + std::unique_ptr 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(doc->getObjectById("style01")); + ASSERT_TRUE(one != nullptr); + + for (auto &style : one->get_styles()) { + EXPECT_EQ(style->fill.get_value(), Glib::ustring("#ff0000")); + } + + SPStyleElem *two = dynamic_cast(doc->getObjectById("style02")); + ASSERT_TRUE(one != nullptr); + + for (auto &style : two->get_styles()) { + EXPECT_EQ(style->fill.get_value(), Glib::ustring("#008000")); + } +} diff --git a/testfiles/src/style-internal-test.cpp b/testfiles/src/style-internal-test.cpp new file mode 100644 index 0000000..cf14e6d --- /dev/null +++ b/testfiles/src/style-internal-test.cpp @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Tests for Style internal classes + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include +#include + +TEST(StyleInternalTest, testSPIDashArrayInequality) +{ + SPIDashArray array; + array.read("0 1 2 3"); + SPIDashArray subsetArray; + subsetArray.read("0 1"); + + ASSERT_FALSE(array == subsetArray); + ASSERT_FALSE(subsetArray == array); +} + +TEST(StyleInternalTest, testSPIDashArrayEquality) +{ + SPIDashArray anArray; + anArray.read("0 1 2 3"); + SPIDashArray sameArray; + sameArray.read("0 1 2 3"); + + ASSERT_TRUE(anArray == sameArray); + ASSERT_TRUE(sameArray == anArray); +} + +/* + 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/style-test.cpp b/testfiles/src/style-test.cpp new file mode 100644 index 0000000..f0f427f --- /dev/null +++ b/testfiles/src/style-test.cpp @@ -0,0 +1,604 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Unit test for style properties. + * + * Author: + * Tavmjong Bah + * + * Copyright (C) 2017 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include +#include +#include + +#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 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"), + StyleRead("font-variation-settings:\"wght\" 400", "font-variation-settings:'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 + // If only "text-decoration-line" is set but not "text-decoration", don't write "text-decoration" (changed in 1.1) + StyleRead("text-decoration-line:underline", "text-decoration-line:underline"), + // "text-decoration" overwrites "text-decoration-line" and vice versa, last one counts + StyleRead("text-decoration-line:overline;text-decoration:underline", + "text-decoration:underline;text-decoration-line:underline"), + StyleRead("text-decoration:underline;text-decoration-line:overline", + "text-decoration:overline;text-decoration-line:overline"), + + // 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 vect(all_style_data, all_style_data + count); + return vect; +} + +TEST(StyleTest, Read) { + std::vector 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 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 vect(all_style_data, all_style_data + count); + return vect; +} + +TEST(StyleTest, Match) { + std::vector 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 ) << "|" <result == this->parent ? "" : this->result); + } + + std::string parent; + std::string child; + std::string result; + std::string diff; + +}; + +std::vector 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", "opacity:0.3" ), + StyleCascade("opacity:0.3", "opacity:0.6", "opacity:0.6" ), + // 'opacity' does not inherit + StyleCascade("opacity:0.3", "", "opacity:1" ), + StyleCascade("", "opacity:0.3", "opacity:0.3" ), + StyleCascade("opacity:0.5", "opacity:inherit", "opacity:0.5", "opacity:0.5" ), + StyleCascade("", "", "opacity:1" ), + + // 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"), + + StyleCascade("font-variant-ligatures:no-common-ligatures", "", "font-variant-ligatures:no-common-ligatures"), + StyleCascade("font-variant-ligatures:no-common-ligatures", "inherit", "font-variant-ligatures:no-common-ligatures"), + StyleCascade("font-variant-ligatures:normal", "font-variant-ligatures:no-common-ligatures", "font-variant-ligatures:no-common-ligatures"), + StyleCascade("", "font-variant-ligatures:no-common-ligatures", "font-variant-ligatures:no-common-ligatures"), + + // SPIPaint + + // SPIPaintOrder + + // SPIDashArray + + // SPIFilter + + // SPIFontSize + + // SPIBaselineShift + + + // SPITextDecorationLine + StyleCascade("text-decoration-line:overline", "text-decoration-line:underline", + "text-decoration-line:underline" ), + StyleCascade("text-decoration:overline", + "text-decoration:underline", + "text-decoration:underline;text-decoration-line:underline"), + StyleCascade("text-decoration:underline", + "text-decoration:underline", + "text-decoration:underline;text-decoration-line:underline", + ""), + StyleCascade("text-decoration:overline;text-decoration-line:underline", + "text-decoration:overline", + "text-decoration:overline;text-decoration-line:overline"), + StyleCascade("text-decoration:overline;text-decoration-line:underline", + "text-decoration:underline", + "text-decoration:underline;text-decoration-line:underline", + ""), + + // SPITextDecorationStyle + + // SPITextDecoration + }; + + size_t count = sizeof(all_style_data) / sizeof(all_style_data[0]); + std::vector vect(all_style_data, all_style_data + count); + return vect; + +} + +TEST(StyleTest, Cascade) { + std::vector 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 ); + + // if diff + EXPECT_STREQ(style_result.writeIfDiff(nullptr).c_str(), i.result.c_str()); + EXPECT_STREQ(style_result.writeIfDiff(&style_parent).c_str(), i.diff.c_str()); + } +} + + +} // 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-affine-test.cpp b/testfiles/src/svg-affine-test.cpp new file mode 100644 index 0000000..300242d --- /dev/null +++ b/testfiles/src/svg-affine-test.cpp @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Test for SVG colors + *//* + * Authors: see git history + * + * Copyright (C) 2010 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include +#include +#include +#include + +#include "svg/svg.h" +#include <2geom/affine.h> + + +struct test_t +{ + char const *str; + Geom::Affine matrix; +}; + +static double const DEGREE = M_PI / 180.; + +test_t const read_matrix_tests[5] = {{"matrix(0,0,0,0,0,0)", Geom::Affine(0, 0, 0, 0, 0, 0)}, + {" matrix(1,2,3,4,5,6)", Geom::Affine(1, 2, 3, 4, 5, 6)}, + {"matrix (1 2 -3,-4,5e6,-6e-7)", Geom::Affine(1, 2, -3, -4, 5e6, -6e-7)}, + {"matrix(1,2,3,4,5e6-3)", Geom::Affine(1, 2, 3, 4, 5e6, -3)}, + {"matrix(1,2,3,4,5e6.3)", Geom::Affine(1, 2, 3, 4, 5e6, 0.3)}}; +test_t const read_translate_tests[3] = {{"translate(1)", Geom::Affine(1, 0, 0, 1, 1, 0)}, + {"translate(1,1)", Geom::Affine(1, 0, 0, 1, 1, 1)}, + {"translate(-1e3 .123e2)", Geom::Affine(1, 0, 0, 1, -1e3, .123e2)}}; +test_t const read_scale_tests[3] = {{"scale(2)", Geom::Affine(2, 0, 0, 2, 0, 0)}, + {"scale(2,3)", Geom::Affine(2, 0, 0, 3, 0, 0)}, + {"scale(0.1e-2 -.475e0)", Geom::Affine(0.1e-2, 0, 0, -.475e0, 0, 0)}}; +test_t const read_rotate_tests[4] = { + {"rotate(13 )", Geom::Affine(cos(13. * DEGREE), sin(13. * DEGREE), -sin(13. * DEGREE), cos(13. * DEGREE), 0, 0)}, + {"rotate(-13)", + Geom::Affine(cos(-13. * DEGREE), sin(-13. * DEGREE), -sin(-13. * DEGREE), cos(-13. * DEGREE), 0, 0)}, + {"rotate(373)", Geom::Affine(cos(13. * DEGREE), sin(13. * DEGREE), -sin(13. * DEGREE), cos(13. * DEGREE), 0, 0)}, + {"rotate(13,7,11)", Geom::Affine(cos(13. * DEGREE), sin(13. * DEGREE), -sin(13. * DEGREE), cos(13. * DEGREE), + (1 - cos(13. * DEGREE)) * 7 + sin(13. * DEGREE) * 11, + (1 - cos(13. * DEGREE)) * 11 - sin(13. * DEGREE) * 7)}}; +test_t const read_skew_tests[3] = {{"skewX( 30)", Geom::Affine(1, 0, tan(30. * DEGREE), 1, 0, 0)}, + {"skewX(-30)", Geom::Affine(1, 0, tan(-30. * DEGREE), 1, 0, 0)}, + {"skewY(390)", Geom::Affine(1, tan(30. * DEGREE), 0, 1, 0, 0)}}; +char const *const read_fail_tests[25] = { + "matrix((1,2,3,4,5,6)", + "matrix((1,2,3,4,5,6))", + "matrix(1,2,3,4,5,6))", + "matrix(,1,2,3,4,5,6)", + "matrix(1,2,3,4,5,6,)", + "matrix(1,2,3,4,5,)", + "matrix(1,2,3,4,5)", + "translate()", + "translate(,)", + "translate(1,)", + "translate(1,6,)", + "translate(1,6,0)", + "scale()", + "scale(1,6,2)", + "rotate()", + "rotate(1,6)", + "rotate(1,6,)", + "rotate(1,6,3,4)", + "skewX()", + "skewX(-)", + "skewX(.)", + "skewY(,)", + "skewY(1,2)"}; +test_t const write_matrix_tests[2] = { + {"matrix(1,2,3,4,5,6)", Geom::Affine(1, 2, 3, 4, 5, 6)}, + {"matrix(-1,2123,3,0.4,1e-8,1e20)", Geom::Affine(-1, 2.123e3, 3 + 1e-14, 0.4, 1e-8, 1e20)}}; +test_t const write_translate_tests[3] = {{"translate(1,1)", Geom::Affine(1, 0, 0, 1, 1, 1)}, + {"translate(1)", Geom::Affine(1, 0, 0, 1, 1, 0)}, + {"translate(-1345,0.123)", Geom::Affine(1, 0, 0, 1, -1.345e3, .123)}}; +test_t const write_scale_tests[3] = {{"scale(0)", Geom::Affine(0, 0, 0, 0, 0, 0)}, + {"scale(7)", Geom::Affine(7, 0, 0, 7, 0, 0)}, + {"scale(2,3)", Geom::Affine(2, 0, 0, 3, 0, 0)}}; +test_t const write_rotate_tests[3] = { + {"rotate(13)", Geom::Affine(cos(13. * DEGREE), sin(13. * DEGREE), -sin(13. * DEGREE), cos(13. * DEGREE), 0, 0)}, + {"rotate(-13,7,11)", Geom::Affine(cos(-13. * DEGREE), sin(-13. * DEGREE), -sin(-13. * DEGREE), cos(-13. * DEGREE), + (1 - cos(-13. * DEGREE)) * 7 + sin(-13. * DEGREE) * 11, + (1 - cos(-13. * DEGREE)) * 11 - sin(-13. * DEGREE) * 7)}, + {"rotate(-34.5,6.7,89)", + Geom::Affine(cos(-34.5 * DEGREE), sin(-34.5 * DEGREE), -sin(-34.5 * DEGREE), cos(-34.5 * DEGREE), + (1 - cos(-34.5 * DEGREE)) * 6.7 + sin(-34.5 * DEGREE) * 89, + (1 - cos(-34.5 * DEGREE)) * 89 - sin(-34.5 * DEGREE) * 6.7)}}; +test_t const write_skew_tests[3] = {{"skewX(30)", Geom::Affine(1, 0, tan(30. * DEGREE), 1, 0, 0)}, + {"skewX(-30)", Geom::Affine(1, 0, tan(-30. * DEGREE), 1, 0, 0)}, + {"skewY(30)", Geom::Affine(1, tan(30. * DEGREE), 0, 1, 0, 0)}}; + +bool approx_equal_pred(Geom::Affine const &ref, Geom::Affine const &cm) +{ + double maxabsdiff = 0; + for (size_t i = 0; i < 6; i++) { + maxabsdiff = std::max(std::abs(ref[i] - cm[i]), maxabsdiff); + } + return maxabsdiff < 1e-14; +} + +TEST(SvgAffineTest, testReadIdentity) +{ + char const *strs[] = {// 0, + " ", "", "matrix(1,0,0,1,0,0)", "translate(0,0)", "scale(1,1)", "rotate(0,0,0)", "skewX(0)", + "skewY(0)"}; + size_t n = G_N_ELEMENTS(strs); + for (size_t i = 0; i < n; i++) { + Geom::Affine cm; + EXPECT_TRUE(sp_svg_transform_read(strs[i], &cm)) << i; + ASSERT_EQ(Geom::identity(), cm) << strs[i]; + } +} + +TEST(SvgAffineTest, testWriteIdentity) +{ + auto str = sp_svg_transform_write(Geom::identity()); + ASSERT_TRUE(str == ""); +} + +TEST(SvgAffineTest, testReadMatrix) +{ + for (size_t i = 0; i < G_N_ELEMENTS(read_matrix_tests); i++) { + Geom::Affine cm; + ASSERT_TRUE(sp_svg_transform_read(read_matrix_tests[i].str, &cm)) << read_matrix_tests[i].str; + ASSERT_TRUE(approx_equal_pred(read_matrix_tests[i].matrix, cm)) << read_matrix_tests[i].str; + } +} + +TEST(SvgAffineTest, testReadTranslate) +{ + for (size_t i = 0; i < G_N_ELEMENTS(read_translate_tests); i++) { + Geom::Affine cm; + ASSERT_TRUE(sp_svg_transform_read(read_translate_tests[i].str, &cm)) << read_translate_tests[i].str; + ASSERT_TRUE(approx_equal_pred(read_translate_tests[i].matrix, cm)) << read_translate_tests[i].str; + } +} + +TEST(SvgAffineTest, testReadScale) +{ + for (size_t i = 0; i < G_N_ELEMENTS(read_scale_tests); i++) { + Geom::Affine cm; + ASSERT_TRUE(sp_svg_transform_read(read_scale_tests[i].str, &cm)) << read_scale_tests[i].str; + ASSERT_TRUE(approx_equal_pred(read_scale_tests[i].matrix, cm)) << read_scale_tests[i].str; + } +} + +TEST(SvgAffineTest, testReadRotate) +{ + for (size_t i = 0; i < G_N_ELEMENTS(read_rotate_tests); i++) { + Geom::Affine cm; + ASSERT_TRUE(sp_svg_transform_read(read_rotate_tests[i].str, &cm)) << read_rotate_tests[i].str; + ASSERT_TRUE(approx_equal_pred(read_rotate_tests[i].matrix, cm)) << read_rotate_tests[i].str; + } +} + +TEST(SvgAffineTest, testReadSkew) +{ + for (size_t i = 0; i < G_N_ELEMENTS(read_skew_tests); i++) { + Geom::Affine cm; + ASSERT_TRUE(sp_svg_transform_read(read_skew_tests[i].str, &cm)) << read_skew_tests[i].str; + ASSERT_TRUE(approx_equal_pred(read_skew_tests[i].matrix, cm)) << read_skew_tests[i].str; + } +} + +TEST(SvgAffineTest, testWriteMatrix) +{ + for (size_t i = 0; i < G_N_ELEMENTS(write_matrix_tests); i++) { + auto str = sp_svg_transform_write(write_matrix_tests[i].matrix); + ASSERT_TRUE(!strcmp(str.c_str(), write_matrix_tests[i].str)); + } +} + +TEST(SvgAffineTest, testWriteTranslate) +{ + for (size_t i = 0; i < G_N_ELEMENTS(write_translate_tests); i++) { + auto str = sp_svg_transform_write(write_translate_tests[i].matrix); + ASSERT_TRUE(!strcmp(str.c_str(), write_translate_tests[i].str)); + } +} + +TEST(SvgAffineTest, testWriteScale) +{ + for (size_t i = 0; i < G_N_ELEMENTS(write_scale_tests); i++) { + auto str = sp_svg_transform_write(write_scale_tests[i].matrix); + ASSERT_TRUE(!strcmp(str.c_str(), write_scale_tests[i].str)); + } +} + +TEST(SvgAffineTest, testWriteRotate) +{ + for (size_t i = 0; i < G_N_ELEMENTS(write_rotate_tests); i++) { + auto str = sp_svg_transform_write(write_rotate_tests[i].matrix); + ASSERT_TRUE(!strcmp(str.c_str(), write_rotate_tests[i].str)); + } +} + +TEST(SvgAffineTest, testWriteSkew) +{ + for (size_t i = 0; i < G_N_ELEMENTS(write_skew_tests); i++) { + auto str = sp_svg_transform_write(write_skew_tests[i].matrix); + ASSERT_TRUE(!strcmp(str.c_str(), write_skew_tests[i].str)); + } +} + +TEST(SvgAffineTest, testReadConcatenation) +{ + char const *str = "skewY(17)skewX(9)translate(7,13)scale(2)rotate(13)translate(3,5)"; + Geom::Affine ref(2.0199976232558053, 1.0674773585906016, -0.14125199392774669, 1.9055550612095459, + 14.412730624347654, 28.499820929377454); // Precomputed using Mathematica + Geom::Affine cm; + ASSERT_TRUE(sp_svg_transform_read(str, &cm)); + ASSERT_TRUE(approx_equal_pred(ref, cm)); +} + +TEST(SvgAffineTest, testReadFailures) +{ + for (size_t i = 0; i < G_N_ELEMENTS(read_fail_tests); i++) { + Geom::Affine cm; + EXPECT_FALSE(sp_svg_transform_read(read_fail_tests[i], &cm)) << read_fail_tests[i]; + } +} + +// vim: filetype=cpp:expandtab:shiftwidth=4:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/svg-color-test.cpp b/testfiles/src/svg-color-test.cpp new file mode 100644 index 0000000..c4e9379 --- /dev/null +++ b/testfiles/src/svg-color-test.cpp @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Test for SVG colors + *//* + * Authors: see git history + * + * Copyright (C) 2010 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include "svg/svg-color.h" + +#include +#include + +#include "preferences.h" +#include "svg/svg-icc-color.h" + +static void check_rgb24(unsigned const rgb24) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + char css[8]; + + prefs->setBool("/options/svgoutput/usenamedcolors", false); + sp_svg_write_color(css, sizeof(css), rgb24 << 8); + ASSERT_EQ(sp_svg_read_color(css, 0xff), rgb24 << 8); + + prefs->setBool("/options/svgoutput/usenamedcolors", true); + sp_svg_write_color(css, sizeof(css), rgb24 << 8); + ASSERT_EQ(sp_svg_read_color(css, 0xff), rgb24 << 8); +} + +TEST(SvgColorTest, testWrite) +{ + unsigned const components[] = {0, 0x80, 0xff, 0xc0, 0x77}; + unsigned const nc = G_N_ELEMENTS(components); + for (unsigned i = nc * nc * nc; i--;) { + unsigned tmp = i; + unsigned rgb24 = 0; + for (unsigned c = 0; c < 3; ++c) { + unsigned const component = components[tmp % nc]; + rgb24 = (rgb24 << 8) | component; + tmp /= nc; + } + ASSERT_TRUE(tmp == 0); + check_rgb24(rgb24); + } + + /* And a few completely random ones. */ + for (unsigned i = 500; i--;) { /* Arbitrary number of iterations. */ + unsigned const rgb24 = (std::rand() >> 4) & 0xffffff; + check_rgb24(rgb24); + } +} + +TEST(SvgColorTest, testReadColor) +{ + gchar const *val[] = {"#f0f", "#ff00ff", "rgb(255,0,255)", "fuchsia"}; + size_t const n = sizeof(val) / sizeof(*val); + for (size_t i = 0; i < n; i++) { + gchar const *end = 0; + guint32 result = sp_svg_read_color(val[i], &end, 0x3); + ASSERT_EQ(result, 0xff00ff00); + ASSERT_LT(val[i], end); + } +} + +TEST(SvgColorTest, testIccColor) +{ + struct + { + unsigned numEntries; + bool shouldPass; + char const *name; + char const *str; + } cases[] = { + {1, true, "named", "icc-color(named, 3)"}, + {0, false, "", "foodle"}, + {1, true, "a", "icc-color(a, 3)"}, + {4, true, "named", "icc-color(named, 3, 0, 0.1, 2.5)"}, + {0, false, "", "icc-color(named, 3"}, + {0, false, "", "icc-color(space named, 3)"}, + {0, false, "", "icc-color(tab\tnamed, 3)"}, + {0, false, "", "icc-color(0name, 3)"}, + {0, false, "", "icc-color(-name, 3)"}, + {1, true, "positive", "icc-color(positive, +3)"}, + {1, true, "negative", "icc-color(negative, -3)"}, + {1, true, "positive", "icc-color(positive, +0.1)"}, + {1, true, "negative", "icc-color(negative, -0.1)"}, + {0, false, "", "icc-color(named, value)"}, + {1, true, "hyphen-name", "icc-color(hyphen-name, 1)"}, + {1, true, "under_name", "icc-color(under_name, 1)"}, + }; + + for (size_t i = 0; i < G_N_ELEMENTS(cases); i++) { + SVGICCColor tmp; + char const *str = cases[i].str; + char const *result = nullptr; + + bool parseRet = sp_svg_read_icc_color(str, &result, &tmp); + ASSERT_EQ(parseRet, cases[i].shouldPass) << str; + ASSERT_EQ(tmp.colors.size(), cases[i].numEntries) << str; + if (cases[i].shouldPass) { + ASSERT_STRNE(str, result); + ASSERT_EQ(tmp.colorProfile, cases[i].name) << str; + } else { + ASSERT_STREQ(str, result); + ASSERT_TRUE(tmp.colorProfile.empty()); + } + } +} + +// vim: filetype=cpp:expandtab:shiftwidth=4:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/svg-extension-test.cpp b/testfiles/src/svg-extension-test.cpp new file mode 100644 index 0000000..e650d24 --- /dev/null +++ b/testfiles/src/svg-extension-test.cpp @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * SVG Extension 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 + +#include +#include +#include +#include + +#include + +using namespace Inkscape; +using namespace Inkscape::Extension; +using namespace Inkscape::Extension::Internal; + +class SvgExtensionTest : public ::testing::Test { + public: + static std::string create_file(const std::string &filename, const std::string &content) + { + std::stringstream path_builder; + path_builder << "SvgExtensionTest_" << _files.size() << "_" << filename; + std::string path = path_builder.str(); + GError *error = nullptr; + if (!g_file_set_contents(path.c_str(), content.c_str(), content.size(), &error)) { + std::stringstream msg; + msg << "SvgExtensionTest::create_file failed: GError(" << error->domain << ", " << error->code << ", " + << error->message << ")"; + g_error_free(error); + throw std::runtime_error(msg.str()); + } + _files.insert(path); + return path; + } + + static std::set _files; + + protected: + void SetUp() override + { + // setup hidden dependency + Application::create(false); + } + + static void TearDownTestCase() + { + for (auto file : _files) { + if (g_remove(file.c_str())) { + std::cout << "SvgExtensionTest was unable to remove file: " << file << std::endl; + } + } + } +}; + +std::set SvgExtensionTest::_files; + +TEST_F(SvgExtensionTest, openingAsLinkInImageASizelessSvgFileReturnsNull) +{ + std::string sizeless_svg_file = + create_file("sizeless.svg", + ""); + + Svg::init(); + Input *svg_input_extension(dynamic_cast(db.get(SP_MODULE_KEY_INPUT_SVG))); + + Preferences *prefs = Preferences::get(); + prefs->setBool("/options/onimport", true); + prefs->setBool("/dialogs/import/ask_svg", false); + prefs->setString("/dialogs/import/import_mode_svg", "link"); + + ASSERT_EQ(svg_input_extension->open(sizeless_svg_file.c_str()), nullptr); +} \ No newline at end of file diff --git a/testfiles/src/svg-length-test.cpp b/testfiles/src/svg-length-test.cpp new file mode 100644 index 0000000..b96ee14 --- /dev/null +++ b/testfiles/src/svg-length-test.cpp @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Test for SVG colors + *//* + * Authors: see git history + * + * Copyright (C) 2010 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include "svg/svg-length.h" +#include "svg/svg.h" + +#include +#include +#include + +struct test_t +{ + char const *str; + SVGLength::Unit unit; + float value; + float computed; +}; + +test_t absolute_tests[12] = { + // clang-format off + {"0", SVGLength::NONE, 0 , 0}, + {"1", SVGLength::NONE, 1 , 1}, + {"1.00001", SVGLength::NONE, 1.00001 , 1.00001}, + {"1px", SVGLength::PX , 1 , 1}, + {".1px", SVGLength::PX , 0.1 , 0.1}, + {"100pt", SVGLength::PT , 100 , 400.0/3.0}, + {"1e2pt", SVGLength::PT , 100 , 400.0/3.0}, + {"3pc", SVGLength::PC , 3 , 48}, + {"-3.5pc", SVGLength::PC , -3.5 , -3.5*16.0}, + {"1.2345678mm", SVGLength::MM , 1.2345678, 1.2345678f*96.0/25.4}, // TODO: More precise constants? (a 7 digit constant when the default precision is 8 digits?) + {"123.45678cm", SVGLength::CM , 123.45678 , 123.45678f*96.0/2.54}, // Note that svg_length_read is casting the result from g_ascii_strtod to float. + {"73.162987in", SVGLength::INCH, 73.162987 , 73.162987f*96.0/1.00}}; +test_t relative_tests[3] = { + {"123em", SVGLength::EM, 123, 123. * 7.}, + {"123ex", SVGLength::EX, 123, 123. * 13.}, + {"123%", SVGLength::PERCENT, 1.23, 1.23 * 19.}}; +const char* fail_tests[8] = { + "123 px", + "123e", + "123e+m", + "123ec", + "123pxt", + "--123", + "", + "px"}; +// clang-format on + +TEST(SvgLengthTest, testRead) +{ + for (size_t i = 0; i < G_N_ELEMENTS(absolute_tests); i++) { + SVGLength len; + ASSERT_TRUE( len.read(absolute_tests[i].str)) << absolute_tests[i].str; + ASSERT_EQ( len.unit, absolute_tests[i].unit) << absolute_tests[i].str; + ASSERT_EQ( len.value, absolute_tests[i].value) << absolute_tests[i].str; + ASSERT_EQ( len.computed, absolute_tests[i].computed) << absolute_tests[i].str; + } + for (size_t i = 0; i < G_N_ELEMENTS(relative_tests); i++) { + SVGLength len; + ASSERT_TRUE( len.read(relative_tests[i].str)) << relative_tests[i].str; + len.update(7, 13, 19); + ASSERT_EQ( len.unit, relative_tests[i].unit) << relative_tests[i].str; + ASSERT_EQ( len.value, relative_tests[i].value) << relative_tests[i].str; + ASSERT_EQ( len.computed, relative_tests[i].computed) << relative_tests[i].str; + } + for (size_t i = 0; i < G_N_ELEMENTS(fail_tests); i++) { + SVGLength len; + ASSERT_TRUE( !len.read(fail_tests[i])) << fail_tests[i]; + } +} + +TEST(SvgLengthTest, testReadOrUnset) +{ + for (size_t i = 0; i < G_N_ELEMENTS(absolute_tests); i++) { + SVGLength len; + len.readOrUnset(absolute_tests[i].str); + ASSERT_EQ( len.unit, absolute_tests[i].unit) << absolute_tests[i].str; + ASSERT_EQ( len.value, absolute_tests[i].value) << absolute_tests[i].str; + ASSERT_EQ( len.computed, absolute_tests[i].computed) << absolute_tests[i].str; + } + for (size_t i = 0; i < G_N_ELEMENTS(relative_tests); i++) { + SVGLength len; + len.readOrUnset(relative_tests[i].str); + len.update(7, 13, 19); + ASSERT_EQ( len.unit, relative_tests[i].unit) << relative_tests[i].str; + ASSERT_EQ( len.value, relative_tests[i].value) << relative_tests[i].str; + ASSERT_EQ( len.computed, relative_tests[i].computed) << relative_tests[i].str; + } + for (size_t i = 0; i < G_N_ELEMENTS(fail_tests); i++) { + SVGLength len; + len.readOrUnset(fail_tests[i], SVGLength::INCH, 123, 456); + ASSERT_EQ( len.unit, SVGLength::INCH) << fail_tests[i]; + ASSERT_EQ( len.value, 123) << fail_tests[i]; + ASSERT_EQ( len.computed, 456) << fail_tests[i]; + } +} + +TEST(SvgLengthTest, testReadAbsolute) +{ + for (size_t i = 0; i < G_N_ELEMENTS(absolute_tests); i++) { + SVGLength len; + ASSERT_TRUE( len.readAbsolute(absolute_tests[i].str)) << absolute_tests[i].str; + ASSERT_EQ( len.unit, absolute_tests[i].unit) << absolute_tests[i].str; + ASSERT_EQ( len.value, absolute_tests[i].value) << absolute_tests[i].str; + ASSERT_EQ( len.computed, absolute_tests[i].computed) << absolute_tests[i].str; + } + for (size_t i = 0; i < G_N_ELEMENTS(relative_tests); i++) { + SVGLength len; + ASSERT_TRUE( !len.readAbsolute(relative_tests[i].str)) << relative_tests[i].str; + } + for (size_t i = 0; i < G_N_ELEMENTS(fail_tests); i++) { + SVGLength len; + ASSERT_TRUE( !len.readAbsolute(fail_tests[i])) << fail_tests[i]; + } +} + +TEST(SvgLengthTest, testEnumMappedToString) +{ + for (int i = (static_cast(SVGLength::NONE) + 1); i <= static_cast(SVGLength::LAST_UNIT); i++) { + SVGLength::Unit target = static_cast(i); + // PX is a special case where we don't have a unit string + if ((target != SVGLength::PX)) { + gchar const *val = sp_svg_length_get_css_units(target); + ASSERT_NE(val, "") << i; + } + } +} + +TEST(SvgLengthTest, testStringsAreValidSVG) +{ + gchar const *valid[] = {"", "em", "ex", "px", "pt", "pc", "cm", "mm", "in", "%"}; + std::set validStrings(valid, valid + G_N_ELEMENTS(valid)); + for (int i = (static_cast(SVGLength::NONE) + 1); i <= static_cast(SVGLength::LAST_UNIT); i++) { + SVGLength::Unit target = static_cast(i); + gchar const *val = sp_svg_length_get_css_units(target); + ASSERT_TRUE( validStrings.find(std::string(val)) != validStrings.end()) << i; + } +} + +TEST(SvgLengthTest, testValidSVGStringsSupported) +{ + // Note that "px" is omitted from the list, as it will be assumed to be so if not explicitly set. + gchar const *valid[] = {"em", "ex", "pt", "pc", "cm", "mm", "in", "%"}; + std::set validStrings(valid, valid + G_N_ELEMENTS(valid)); + for (int i = (static_cast(SVGLength::NONE) + 1); i <= static_cast(SVGLength::LAST_UNIT); i++) { + SVGLength::Unit target = static_cast(i); + gchar const *val = sp_svg_length_get_css_units(target); + std::set::iterator iter = validStrings.find(std::string(val)); + if (iter != validStrings.end()) { + validStrings.erase(iter); + } + } + ASSERT_EQ(validStrings.size(), 0u) << validStrings.size(); +} + +TEST(SvgLengthTest, testPlaces) +{ + struct testd_t + { + char const *str; + double val; + int prec; + int minexp; + }; + + testd_t const precTests[] = { + {"760", 761.92918978947023, 2, -8}, + {"761.9", 761.92918978947023, 4, -8}, + }; + + for (size_t i = 0; i < G_N_ELEMENTS(precTests); i++) { + std::string buf; + buf.append(sp_svg_number_write_de(precTests[i].val, precTests[i].prec, precTests[i].minexp)); + unsigned int retval = buf.length(); + ASSERT_EQ( retval, strlen(precTests[i].str)) << "Number of chars written"; + ASSERT_EQ( std::string(buf), std::string(precTests[i].str)) << "Numeric string written"; + } +} + +// TODO: More tests + +// vim: filetype=cpp:expandtab:shiftwidth=4:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/svg-path-geom-test.cpp b/testfiles/src/svg-path-geom-test.cpp new file mode 100644 index 0000000..7fa7a21 --- /dev/null +++ b/testfiles/src/svg-path-geom-test.cpp @@ -0,0 +1,499 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * Test for SVG colors + *//* + * Authors: see git history + * + * Copyright (C) 2010 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include <2geom/coord.h> +#include <2geom/curves.h> +#include <2geom/pathvector.h> +#include +#include +#include + +#include "preferences.h" +#include "svg/svg.h" + +class SvgPathGeomTest : public ::testing::Test +{ +public: + std::vector rectanglesAbsoluteClosed = {"M 1,2 L 4,2 L 4,8 L 1,8 z", "M 1,2 4,2 4,8 1,8 z", + "M 1,2 H 4 V 8 H 1 z"}; + std::vector rectanglesRelativeClosed = {"m 1,2 l 3,0 l 0,6 l -3,0 z", "m 1,2 3,0 0,6 -3,0 z", + "m 1,2 h 3 v 6 h -3 z"}; + std::vector rectanglesAbsoluteOpen = {"M 1,2 L 4,2 L 4,8 L 1,8 L 1,2", "M 1,2 4,2 4,8 1,8 1,2", + "M 1,2 H 4 V 8 H 1 V 2"}; + std::vector rectanglesRelativeOpen = {"m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6", "m 1,2 3,0 0,6 -3,0 0,-6", + "m 1,2 h 3 v 6 h -3 v -6"}; + std::vector rectanglesAbsoluteClosed2 = {"M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 z", "M 1,2 4,2 4,8 1,8 1,2 z", + "M 1,2 H 4 V 8 H 1 V 2 z"}; + std::vector rectanglesRelativeClosed2{"m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6 z", "m 1,2 3,0 0,6 -3,0 0,-6 z", + "m 1,2 h 3 v 6 h -3 v -6 z"}; + Geom::PathVector rectanglepvopen; + Geom::PathVector rectanglepvclosed; + Geom::PathVector rectanglepvclosed2; + + void SetUp() override + { + rectanglepvopen.clear(); + rectanglepvopen.push_back(Geom::Path(Geom::Point(1, 2))); + rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(1, 2), Geom::Point(4, 2))); + rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(4, 2), Geom::Point(4, 8))); + rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(4, 8), Geom::Point(1, 8))); + rectanglepvopen.back().append(Geom::LineSegment(Geom::Point(1, 8), Geom::Point(1, 2))); + rectanglepvclosed.clear(); + rectanglepvclosed.push_back(Geom::Path(Geom::Point(1, 2))); + rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(1, 2), Geom::Point(4, 2))); + rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(4, 2), Geom::Point(4, 8))); + rectanglepvclosed.back().append(Geom::LineSegment(Geom::Point(4, 8), Geom::Point(1, 8))); + rectanglepvclosed.back().close(); + rectanglepvclosed2.clear(); + rectanglepvclosed2.push_back(Geom::Path(Geom::Point(1, 2))); + rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(1, 2), Geom::Point(4, 2))); + rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(4, 2), Geom::Point(4, 8))); + rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(4, 8), Geom::Point(1, 8))); + rectanglepvclosed2.back().append(Geom::LineSegment(Geom::Point(1, 8), Geom::Point(1, 2))); + rectanglepvclosed2.back().close(); + } + + bool bpathEqual(Geom::PathVector const &a, Geom::PathVector const &b, double eps = 1e-16) + { + if (a.size() != b.size()) { + printf("PathVectors not the same size: %u != %u", static_cast(a.size()), + static_cast(b.size())); + return false; + } + for (size_t i = 0; i < a.size(); i++) { + Geom::Path const &pa = a[i]; + Geom::Path const &pb = b[i]; + if (pa.closed() && !pb.closed()) { + printf("Left subpath is closed, right subpath is open. Subpath: %u", static_cast(i)); + return false; + } + if (!pa.closed() && pb.closed()) { + printf("Right subpath is closed, left subpath is open. Subpath: %u", static_cast(i)); + return false; + } + if (pa.size() != pb.size()) { + printf("Not the same number of segments: %u != %u, subpath: %u", static_cast(pa.size()), + static_cast(pb.size()), static_cast(i)); + return false; + } + for (size_t j = 0; j < pa.size(); j++) { + Geom::Curve const *ca = &pa[j]; + Geom::Curve const *cb = &pb[j]; + if (typeid(*ca) == typeid(*cb)) { + if (Geom::LineSegment const *la = dynamic_cast(ca)) { + Geom::LineSegment const *lb = dynamic_cast(cb); + if (!Geom::are_near((*la)[0], (*lb)[0], eps)) { + printf("Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", + (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y], + static_cast(i), static_cast(j)); + return false; + } + if (!Geom::are_near((*la)[1], (*lb)[1], eps)) { + printf("Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", + (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y], + static_cast(i), static_cast(j)); + return false; + } + } else if (Geom::CubicBezier const *la = dynamic_cast(ca)) { + Geom::CubicBezier const *lb = dynamic_cast(cb); + if (!Geom::are_near((*la)[0], (*lb)[0], eps)) { + printf("Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", + (*la)[0][Geom::X], (*la)[0][Geom::Y], (*lb)[0][Geom::X], (*lb)[0][Geom::Y], + static_cast(i), static_cast(j)); + return false; + } + if (!Geom::are_near((*la)[1], (*lb)[1], eps)) { + printf("Different 1st control point: (%g,%g) != (%g,%g), subpath: %u, segment: %u", + (*la)[1][Geom::X], (*la)[1][Geom::Y], (*lb)[1][Geom::X], (*lb)[1][Geom::Y], + static_cast(i), static_cast(j)); + return false; + } + if (!Geom::are_near((*la)[2], (*lb)[2], eps)) { + printf("Different 2nd control point: (%g,%g) != (%g,%g), subpath: %u, segment: %u", + (*la)[2][Geom::X], (*la)[2][Geom::Y], (*lb)[2][Geom::X], (*lb)[2][Geom::Y], + static_cast(i), static_cast(j)); + return false; + } + if (!Geom::are_near((*la)[3], (*lb)[3], eps)) { + printf("Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", + (*la)[3][Geom::X], (*la)[3][Geom::Y], (*lb)[3][Geom::X], (*lb)[3][Geom::Y], + static_cast(i), static_cast(j)); + return false; + } + } else { + printf("Unknown curve type: %s, subpath: %u, segment: %u", typeid(*ca).name(), + static_cast(i), static_cast(j)); + return false; + } + } else // not same type + { + printf("Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), + typeid(*cb).name(), static_cast(i), static_cast(j)); + return false; + } + } + } + return true; + } +}; + +TEST_F(SvgPathGeomTest, testReadRectanglesAbsoluteClosed) +{ + for (size_t i = 0; i < rectanglesAbsoluteClosed.size(); i++) { + Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed[i].c_str()); + EXPECT_TRUE(bpathEqual(pv, rectanglepvclosed)) << rectanglesAbsoluteClosed[i].c_str(); + } +} + +TEST_F(SvgPathGeomTest, testReadRectanglesRelativeClosed) +{ + for (size_t i = 0; i < rectanglesRelativeClosed.size(); i++) { + Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed[i].c_str()); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << rectanglesRelativeClosed[i].c_str(); + } +} + +TEST_F(SvgPathGeomTest, testReadRectanglesAbsoluteOpen) +{ + for (size_t i = 0; i < rectanglesAbsoluteOpen.size(); i++) { + Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteOpen[i].c_str()); + ASSERT_TRUE(bpathEqual(pv, rectanglepvopen)) << rectanglesAbsoluteOpen[i].c_str(); + } +} + +TEST_F(SvgPathGeomTest, testReadRectanglesRelativeOpen) +{ + for (size_t i = 0; i < rectanglesRelativeOpen.size(); i++) { + Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeOpen[i].c_str()); + ASSERT_TRUE(bpathEqual(pv, rectanglepvopen)) << rectanglesRelativeOpen[i].c_str(); + } +} + +TEST_F(SvgPathGeomTest, testReadRectanglesAbsoluteClosed2) +{ + for (size_t i = 0; i < rectanglesAbsoluteClosed2.size(); i++) { + Geom::PathVector pv = sp_svg_read_pathv(rectanglesAbsoluteClosed2[i].c_str()); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed2)) << rectanglesAbsoluteClosed2[i].c_str(); + } +} + +TEST_F(SvgPathGeomTest, testReadRectanglesRelativeClosed2) +{ + for (size_t i = 0; i < rectanglesRelativeClosed2.size(); i++) { + Geom::PathVector pv = sp_svg_read_pathv(rectanglesRelativeClosed2[i].c_str()); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed2)) << rectanglesRelativeClosed2[i].c_str(); + } +} + +TEST_F(SvgPathGeomTest, testReadConcatenatedPaths) +{ + // Note that finalPoint doesn't actually return the final point of the path, just the last given point... (but since + // this might be intentional and we're not testing lib2geom here, we just specify the final point explicitly + Geom::PathVector pv_good; + pv_good.push_back(rectanglepvclosed.back()); + pv_good.push_back(rectanglepvopen.back() * Geom::Translate(1, 2) /* * Geom::Translate(pv_good[0].finalPoint())*/); + pv_good.push_back(rectanglepvclosed.back() * Geom::Translate(2, 4) /* *Geom::Translate(pv_good[1].finalPoint())*/); + pv_good.push_back(rectanglepvopen.back()); + pv_good[0].close(); + pv_good[1].close(false); + pv_good[2].close(); + pv_good[3].close(false); + std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + + rectanglesAbsoluteOpen[0]; + Geom::PathVector pv = sp_svg_read_pathv(path_str.c_str()); + ASSERT_TRUE(bpathEqual(pv, pv_good)); +} + +TEST_F(SvgPathGeomTest, testReadZeroLengthSubpaths) +{ + // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant + Geom::PathVector pv_good; + pv_good.push_back(Geom::Path(Geom::Point(0, 0))); + pv_good.push_back(Geom::Path(Geom::Point(1, 1))); + pv_good.back().append(Geom::LineSegment(Geom::Point(1, 1), Geom::Point(2, 2))); + pv_good.push_back(Geom::Path(Geom::Point(3, 3))); + pv_good.back().close(); + pv_good.push_back(Geom::Path(Geom::Point(4, 4))); + pv_good.back().append(Geom::LineSegment(Geom::Point(4, 4), Geom::Point(5, 5))); + pv_good.back().close(); + pv_good.push_back(Geom::Path(Geom::Point(6, 6))); + { // Test absolute version + char const *path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6"; + Geom::PathVector pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, pv_good)) << path_str; + } + { // Test relative version + char const *path_str = "m 0,0 m 1,1 l 1,1 m 1,1 z m 1,1 l 1,1 z m 2,2"; + Geom::PathVector pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, pv_good)) << path_str; + } +} + +TEST_F(SvgPathGeomTest, testReadImplicitMoveto) +{ + g_warning("Currently lib2geom (/libnr) has no way of specifying the difference between 'M 0,0 ... z M 0,0 L 1,0' " + "and 'M 0,0 ... z L 1,0', the SVG specification does state that these should be handled differently with " + "respect to markers however, see the description of the 'orient' attribute of the 'marker' element."); + Geom::PathVector pv_good; + pv_good.push_back(Geom::Path(Geom::Point(1, 1))); + pv_good.back().append(Geom::LineSegment(Geom::Point(1, 1), Geom::Point(2, 2))); + pv_good.back().close(); + pv_good.push_back(Geom::Path(Geom::Point(1, 1))); + pv_good.back().append(Geom::LineSegment(Geom::Point(1, 1), Geom::Point(3, 3))); + pv_good.back().close(); + { // Test absolute version + char const *path_str = "M 1,1 L 2,2 z L 3,3 z"; + Geom::PathVector pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, pv_good)) << path_str; + } + { // Test relative version + char const *path_str = "M 1,1 l 1,1 z l 2,2 z"; + Geom::PathVector pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, pv_good)) << path_str; + } +} + +TEST_F(SvgPathGeomTest, testReadFloatingPoint) +{ + Geom::PathVector pv_good1; + pv_good1.push_back(Geom::Path(Geom::Point(.01, .02))); + pv_good1.back().append(Geom::LineSegment(Geom::Point(.01, .02), Geom::Point(.04, .02))); + pv_good1.back().append(Geom::LineSegment(Geom::Point(.04, .02), Geom::Point(1.5, 1.6))); + pv_good1.back().append(Geom::LineSegment(Geom::Point(1.5, 1.6), Geom::Point(.01, .08))); + pv_good1.back().append(Geom::LineSegment(Geom::Point(.01, .08), Geom::Point(.01, .02))); + pv_good1.back().close(); + { // Test decimals + char const *path_str = "M .01,.02 L.04.02 L1.5,1.6L0.01,0.08 .01.02 z"; + Geom::PathVector pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, pv_good1)) << path_str; + } + Geom::PathVector pv_good2; + pv_good2.push_back(Geom::Path(Geom::Point(.01, .02))); + pv_good2.back().append(Geom::LineSegment(Geom::Point(.01, .02), Geom::Point(.04, .02))); + pv_good2.back().append(Geom::LineSegment(Geom::Point(.04, .02), Geom::Point(1.5, 1.6))); + pv_good2.back().append(Geom::LineSegment(Geom::Point(1.5, 1.6), Geom::Point(.01, .08))); + pv_good2.back().close(); + { // Test exponent + char const *path_str = "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L0150E-2,1.6e0L1.0e-2,80e-3 z"; + Geom::PathVector pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, pv_good2)) << path_str; + } +} + +TEST_F(SvgPathGeomTest, testReadImplicitSeparation) +{ + // Coordinates need not be separated by whitespace if they can still be read unambiguously + Geom::PathVector pv_good; + pv_good.push_back(Geom::Path(Geom::Point(.1, .2))); + pv_good.back().append(Geom::LineSegment(Geom::Point(.1, .2), Geom::Point(.4, .2))); + pv_good.back().append(Geom::LineSegment(Geom::Point(.4, .2), Geom::Point(.4, .8))); + pv_good.back().append(Geom::LineSegment(Geom::Point(.4, .8), Geom::Point(.1, .8))); + pv_good.back().close(); + { // Test absolute + char const *path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z"; + Geom::PathVector pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, pv_good)) << path_str; + } + { // Test relative + char const *path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z"; + Geom::PathVector pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, pv_good)) << path_str; + } +} + +TEST_F(SvgPathGeomTest, testReadErrorMisplacedCharacter) +{ + + char const *path_str; + Geom::PathVector pv; + // Comma in the wrong place (commas may only appear between parameters) + path_str = "M 1,2 4,2 4,8 1,8 z , m 13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Comma in the wrong place (commas may only appear between parameters) + path_str = "M 1,2 4,2 4,8 1,8 z m,13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Period in the wrong place (no numbers after a 'z') + path_str = "M 1,2 4,2 4,8 1,8 z . m 13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Sign in the wrong place (no numbers after a 'z') + path_str = "M 1,2 4,2 4,8 1,8 z + - m 13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Digit in the wrong place (no numbers after a 'z') + path_str = "M 1,2 4,2 4,8 1,8 z 9809 m 13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Digit in the wrong place (no numbers after a 'z') + path_str = "M 1,2 4,2 4,8 1,8 z 9809 876 m 13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; +} +/*FAIL ?? +TEST_F(SvgPathGeomTest, testReadErrorUnrecognizedCharacter) +{ + char const *path_str; + Geom::PathVector pv; + // Unrecognized character + path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Unrecognized character + path_str = "M 1,2 4,2 4,8 1,8 z m &13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; +} + +TEST_F(SvgPathGeomTest, testReadErrorTypo) +{ + char const *path_str; + Geom::PathVector pv; + // Typo + path_str = "M 1,2 4,2 4,8 1,8 z j 13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + + // Typo + path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvopen)) << path_str; +} +*/ +TEST_F(SvgPathGeomTest, testReadErrorIllformedNumbers) +{ + char const *path_str; + Geom::PathVector pv; + // Double exponent + path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Double sign + path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Double sign + path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // No digit + path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // No digit + path_str = "M 1,2 4,2 4,8 1,8 z m .,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // No digit + path_str = "M 1,2 4,2 4,8 1,8 z m +,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // No digit + path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; +} + +TEST_F(SvgPathGeomTest, testReadErrorJunk) +{ + char const *path_str; + Geom::PathVector pv; + // Junk + path_str = "M 1,2 4,2 4,8 1,8 z j 357 hkjh.,34e34 90ih6kj4 h5k6vlh4N.,6,45wikuyi3yere..3487 m 13,23"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; +} +/* FAIL ??? +TEST_F(SvgPathGeomTest, testReadErrorStopReading) +{ + char const *path_str; + Geom::PathVector pv; + // Unrecognized parameter + path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Invalid parameter + path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + // Illformed parameter + path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvclosed)) << path_str; + + // "Third" parameter + path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23"; + pv = sp_svg_read_pathv(path_str); + ASSERT_TRUE(bpathEqual(pv, rectanglepvopen)) << path_str; +} +*/ + +TEST_F(SvgPathGeomTest, testRoundTrip) +{ + // This is the easiest way to (also) test writing path data, as a path can be written in more than one way. + Geom::PathVector pv; + Geom::PathVector new_pv; + std::string org_path_str; + std::string path_str; + // Rectangle (closed) + org_path_str = rectanglesAbsoluteClosed[0]; + pv = sp_svg_read_pathv(org_path_str.c_str()); + path_str = sp_svg_write_path(pv); + new_pv = sp_svg_read_pathv(path_str.c_str()); + ASSERT_TRUE(bpathEqual(pv, new_pv)) << org_path_str.c_str(); + // Rectangle (open) + org_path_str = rectanglesAbsoluteOpen[0]; + pv = sp_svg_read_pathv(org_path_str.c_str()); + path_str = sp_svg_write_path(pv); + new_pv = sp_svg_read_pathv(path_str.c_str()); + ASSERT_TRUE(bpathEqual(pv, new_pv)) << org_path_str.c_str(); + // Concatenated rectangles + org_path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + + rectanglesAbsoluteOpen[0]; + pv = sp_svg_read_pathv(org_path_str.c_str()); + path_str = sp_svg_write_path(pv); + new_pv = sp_svg_read_pathv(path_str.c_str()); + ASSERT_TRUE(bpathEqual(pv, new_pv)) << org_path_str.c_str(); + // Zero-length subpaths + org_path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6"; + pv = sp_svg_read_pathv(org_path_str.c_str()); + path_str = sp_svg_write_path(pv); + new_pv = sp_svg_read_pathv(path_str.c_str()); + ASSERT_TRUE(bpathEqual(pv, new_pv)) << org_path_str.c_str(); + // Floating-point + org_path_str = "M .01,.02 L 0.04,0.02 L.04,.08L0.01,0.08 z" + "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L04E-2,.08e0L1.0e-2,80e-3 z"; + pv = sp_svg_read_pathv(org_path_str.c_str()); + path_str = sp_svg_write_path(pv); + new_pv = sp_svg_read_pathv(path_str.c_str()); + ASSERT_TRUE(bpathEqual(pv, new_pv, 1e-17)) << org_path_str.c_str(); +} + +/* + * Please do not change my prefs or put them back after :( + * also, fails. + +TEST_F(SvgPathGeomTest, testMinexpPrecision) +{ + Geom::PathVector pv; + char *path_str; + // Default values + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/options/svgoutput/allowrelativecoordinates", true); + prefs->setBool("/options/svgoutput/forcerepeatcommands", false); + prefs->setInt("/options/svgoutput/numericprecision", 8); + prefs->setInt("/options/svgoutput/minimumexponent", -8); + pv = sp_svg_read_pathv("M 123456781,1.23456781e-8 L 123456782,1.23456782e-8 L 123456785,1.23456785e-8 L +10123456400,1.23456785e-8 L 123456789,1.23456789e-8 L 123456789,101.234564e-8 L 123456789,1.23456789e-8"); path_str = +sp_svg_write_path(pv); ASSERT_FALSE( strcmp("m 123456780,1.2345678e-8 0,0 10,1e-15 9999999210,0 -9999999210,0 +0,9.99999921e-7 0,-9.99999921e-7" , path_str )); g_free(path_str); +}*/ + +// vim: filetype=cpp:expandtab:shiftwidth=4:softtabstop=4:fileencoding=utf-8:textwidth=99 : 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 + +template +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 & " + +template +void test_tostring() +{ + assert_tostring_eq('A', "A"); + assert_tostring_eq('A', "A"); + assert_tostring_eq('A', "A"); + + assert_tostring_eq(0x7FFF, "32767"); + assert_tostring_eq(-30000, "-30000"); + assert_tostring_eq(0xFFFFu, "65535"); + assert_tostring_eq(0x7FFFFFFF, "2147483647"); + assert_tostring_eq(-2000000000, "-2000000000"); + assert_tostring_eq(0xFFFFFFFFu, "4294967295"); + + // long is 32bit on Windows, 64bit on Linux + assert_tostring_eq(0x7FFFFFFFL, "2147483647"); + assert_tostring_eq(-2000000000L, "-2000000000"); + assert_tostring_eq(0xFFFFFFFFuL, "4294967295"); + + assert_tostring_eq((char const *)TEST_STRING, TEST_STRING); + assert_tostring_eq((signed char const *)TEST_STRING, TEST_STRING); + assert_tostring_eq((unsigned char const *)TEST_STRING, TEST_STRING); + assert_tostring_eq(TEST_STRING, TEST_STRING); + assert_tostring_eq(TEST_STRING, TEST_STRING); +} + +TEST(CSSOStringStreamTest, tostring) +{ + using S = Inkscape::CSSOStringStream; + + test_tostring(); + + // float has 6 significant digits + assert_tostring_eq(0.0, "0"); + assert_tostring_eq(4.5, "4.5"); + assert_tostring_eq(-4.0, "-4"); + assert_tostring_eq(0.001, "0.001"); + assert_tostring_eq(0.00123456, "0.00123456"); + assert_tostring_eq(-0.00123456, "-0.00123456"); + assert_tostring_eq(-1234560.0, "-1234560"); + + // double has 15 significant digits + assert_tostring_eq(0.0, "0"); + assert_tostring_eq(4.5, "4.5"); + assert_tostring_eq(-4.0, "-4"); + assert_tostring_eq(0.001, "0.001"); + + // 9 significant digits + assert_tostring_eq(1.23456789, "1.23456789"); + assert_tostring_eq(-1.23456789, "-1.23456789"); + assert_tostring_eq(12345678.9, "12345678.9"); + assert_tostring_eq(-12345678.9, "-12345678.9"); + + assert_tostring_eq(1.234e-12, "0"); + assert_tostring_eq(3e9, "3000000000"); + assert_tostring_eq(-3.5e9, "-3500000000"); +} + +TEST(SVGOStringStreamTest, tostring) +{ + using S = Inkscape::SVGOStringStream; + + test_tostring(); + + assert_tostring_eq(Geom::Point(12, 3.4), "12,3.4"); + + // float has 6 significant digits + assert_tostring_eq(0.0, "0"); + assert_tostring_eq(4.5, "4.5"); + assert_tostring_eq(-4.0, "-4"); + assert_tostring_eq(0.001, "0.001"); + assert_tostring_eq(0.00123456, "0.00123456"); + assert_tostring_eq(-0.00123456, "-0.00123456"); + assert_tostring_eq(-1234560.0, "-1234560"); + + // double has 15 significant digits + assert_tostring_eq(0.0, "0"); + assert_tostring_eq(4.5, "4.5"); + assert_tostring_eq(-4.0, "-4"); + assert_tostring_eq(0.001, "0.001"); + + // 8 significant digits + assert_tostring_eq(1.23456789, "1.2345679"); + assert_tostring_eq(-1.23456789, "-1.2345679"); + assert_tostring_eq(12345678.9, "12345679"); + assert_tostring_eq(-12345678.9, "-12345679"); + + assert_tostring_eq(1.234e-12, "1.234e-12"); + assert_tostring_eq(3e9, "3e+09"); + assert_tostring_eq(-3.5e9, "-3.5e+09"); +} + +template +void test_concat() +{ + S s; + s << "hello, "; + s << -53.5; + ASSERT_EQ(s.str(), std::string("hello, -53.5")); +} + +TEST(CSSOStringStreamTest, concat) +{ // + test_concat(); +} + +TEST(SVGOStringStreamTest, concat) +{ // + test_concat(); +} + +/* + 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/src/util-test.cpp b/testfiles/src/util-test.cpp new file mode 100644 index 0000000..785e3d3 --- /dev/null +++ b/testfiles/src/util-test.cpp @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * Test utilities from src/util + */ +/* + * Authors: + * Thomas Holder + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtest/gtest.h" +#include "util/longest-common-suffix.h" + +TEST(UtilTest, NearestCommonAncestor) +{ +#define nearest_common_ancestor(a, b, c) \ + Inkscape::Algorithms::nearest_common_ancestor(a, b, c) + + // simple node with a parent + struct Node + { + Node const *parent; + Node(Node const *p) : parent(p){}; + Node(Node const &other) = delete; + }; + + // iterator which traverses towards the root node + struct iter + { + Node const *node; + iter(Node const &n) : node(&n) {} + bool operator==(iter const &rhs) const { return node == rhs.node; } + bool operator!=(iter const &rhs) const { return node != rhs.node; } + iter &operator++() + { + node = node->parent; + return *this; + } + + // TODO remove, the implementation should not require this + Node const &operator*() const { return *node; } + }; + + // construct a tree + auto const node0 = Node(nullptr); + auto const node1 = Node(&node0); + auto const node2 = Node(&node1); + auto const node3a = Node(&node2); + auto const node4a = Node(&node3a); + auto const node5a = Node(&node4a); + auto const node3b = Node(&node2); + auto const node4b = Node(&node3b); + auto const node5b = Node(&node4b); + + // start at each node from 5a to 0 (first argument) + ASSERT_EQ(nearest_common_ancestor(iter(node5a), iter(node5b), iter(node0)), iter(node2)); + ASSERT_EQ(nearest_common_ancestor(iter(node4a), iter(node5b), iter(node0)), iter(node2)); + ASSERT_EQ(nearest_common_ancestor(iter(node3a), iter(node5b), iter(node0)), iter(node2)); + ASSERT_EQ(nearest_common_ancestor(iter(node2), iter(node5b), iter(node0)), iter(node2)); + ASSERT_EQ(nearest_common_ancestor(iter(node1), iter(node5b), iter(node0)), iter(node1)); + ASSERT_EQ(nearest_common_ancestor(iter(node0), iter(node5b), iter(node0)), iter(node0)); + + // start at each node from 5b to 0 (second argument) + ASSERT_EQ(nearest_common_ancestor(iter(node5a), iter(node5b), iter(node0)), iter(node2)); + ASSERT_EQ(nearest_common_ancestor(iter(node5a), iter(node4b), iter(node0)), iter(node2)); + ASSERT_EQ(nearest_common_ancestor(iter(node5a), iter(node3b), iter(node0)), iter(node2)); + ASSERT_EQ(nearest_common_ancestor(iter(node5a), iter(node2), iter(node0)), iter(node2)); + ASSERT_EQ(nearest_common_ancestor(iter(node5a), iter(node1), iter(node0)), iter(node1)); + ASSERT_EQ(nearest_common_ancestor(iter(node5a), iter(node0), iter(node0)), iter(node0)); + + // identity (special case in implementation) + ASSERT_EQ(nearest_common_ancestor(iter(node5a), iter(node5a), iter(node0)), iter(node5a)); + + // identical parents (special case in implementation) + ASSERT_EQ(nearest_common_ancestor(iter(node3a), iter(node3b), iter(node0)), iter(node2)); +} + +// vim: filetype=cpp:expandtab:shiftwidth=4:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/testfiles/src/xml-test.cpp b/testfiles/src/xml-test.cpp new file mode 100644 index 0000000..dee272d --- /dev/null +++ b/testfiles/src/xml-test.cpp @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * Test xml node + */ +/* + * Authors: + * Ted Gould + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtest/gtest.h" +#include "xml/repr.h" + +TEST(XmlTest, nodeiter) +{ + auto testdoc = std::shared_ptr(sp_repr_read_buf("", SP_SVG_NS_URI)); + ASSERT_TRUE(testdoc); + + auto count = 0; + for (auto &child : *testdoc->root()) { + ASSERT_STREQ(child.name(), "svg:g"); + count++; + } + ASSERT_EQ(count, 1); + + testdoc = + std::shared_ptr(sp_repr_read_buf("", SP_SVG_NS_URI)); + ASSERT_TRUE(testdoc); + + count = 0; + for (auto &child : *testdoc->root()) { + ASSERT_STREQ(child.name(), "svg:g"); + count++; + } + ASSERT_EQ(count, 3); + + testdoc = std::shared_ptr(sp_repr_read_buf(R"""( + + + + + + + + + + + + +)""", SP_SVG_NS_URI)); + ASSERT_TRUE(testdoc); + + auto path = std::list{"svg:g", "svg:path"}; + auto found = testdoc->root()->findChildPath(path); + ASSERT_NE(found, nullptr); + ASSERT_STREQ(found->attribute("id"), "b"); + + // no such second element + path = {"svg:g", "svg:g"}; + ASSERT_EQ(testdoc->root()->findChildPath(path), nullptr); + + // no such first element + path = {"svg:symbol", "svg:path"}; + ASSERT_EQ(testdoc->root()->findChildPath(path), nullptr); + + // root with no children + testdoc = std::shared_ptr(sp_repr_read_buf("", SP_SVG_NS_URI)); + ASSERT_EQ(testdoc->root()->findChildPath(path), nullptr); +} + +/* + 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..cee75be --- /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 + * + * Copyright (C) 2015 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "gtest/gtest.h" + +#include + +#include "inkgc/gc-core.h" +#include "inkscape.h" + +#include + +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 + + Gio::init(); + + 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 : -- cgit v1.2.3