From 8233c6362bbe2ca2ac4d3ef3cfc79f15ee79bc40 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Fri, 24 Jun 2022 06:44:30 +0930 Subject: [PATCH] ft-svg-render test --- test/cairo-svg-test-doc.ttx | 689 ++++++++++++++++++ test/cairo-svg-test-fill.ttx | 365 ++++++++++ test/cairo-svg-test-gradient.ttx | 441 +++++++++++ test/cairo-svg-test-path.ttx | 281 +++++++ test/cairo-svg-test-shapes.ttx | 333 +++++++++ test/cairo-svg-test-stroke.ttx | 608 ++++++++++++++++ test/cairo-svg-test-transform.ttx | 403 ++++++++++ test/ft-svg-render.c | 159 ++++ test/meson.build | 14 + test/reference/ft-svg-render-doc.ref.png | Bin 0 -> 11069 bytes test/reference/ft-svg-render-fill.ref.png | Bin 0 -> 1641 bytes test/reference/ft-svg-render-gradient.ref.png | Bin 0 -> 9156 bytes test/reference/ft-svg-render-path.ref.png | Bin 0 -> 2570 bytes test/reference/ft-svg-render-shapes.ref.png | Bin 0 -> 3073 bytes test/reference/ft-svg-render-stroke.ref.png | Bin 0 -> 2224 bytes .../reference/ft-svg-render-transform.ref.png | Bin 0 -> 4248 bytes test/svg/README | 22 + test/svg/build_ttx_fonts.py | 161 ++++ test/svg/doc.0.viewBox1.svg | 4 + test/svg/doc.1.viewBox2.svg | 4 + test/svg/doc.2.image.svg | 121 +++ test/svg/doc.3.image-transform.svg | 122 ++++ test/svg/doc.4.clip-user.svg | 9 + test/svg/doc.5.clip-object.svg | 10 + test/svg/doc.6.clip-user2.svg | 10 + test/svg/doc.7.clip-object2.svg | 11 + test/svg/doc.8.clip-user3.svg | 15 + test/svg/doc.9.clip-object3.svg | 15 + test/svg/doc.A.g.svg | 14 + test/svg/fill.0.name.svg | 4 + test/svg/fill.1.hex6.svg | 4 + test/svg/fill.2.hex3.svg | 4 + test/svg/fill.3.rgb.svg | 4 + test/svg/fill.4.current-color.svg | 4 + test/svg/fill.5.palette.svg | 4 + test/svg/fill.6.opacity.svg | 4 + test/svg/fill.7.color.svg | 5 + test/svg/fill.8.rule.svg | 8 + test/svg/gradient.0.lin-pad.svg | 10 + test/svg/gradient.1.lin-reflect.svg | 11 + test/svg/gradient.2.lin-repeat.svg | 11 + test/svg/gradient.3.lin-user.svg | 11 + test/svg/gradient.4.lin-transform.svg | 10 + test/svg/gradient.5.rad-pad.svg | 10 + test/svg/gradient.6.rad-reflect.svg | 11 + test/svg/gradient.7.rad-repeat.svg | 11 + test/svg/gradient.8.rad-user.svg | 11 + test/svg/gradient.9.rad-transform.svg | 11 + test/svg/meson.build | 5 + test/svg/path.0.line.svg | 8 + test/svg/path.1.curve.svg | 9 + test/svg/path.2.quad.svg | 8 + test/svg/path.3.arc.svg | 7 + test/svg/shapes.0.rect.svg | 3 + test/svg/shapes.1.rounded-rect.svg | 3 + test/svg/shapes.2.circle.svg | 3 + test/svg/shapes.3.ellipse.svg | 3 + test/svg/shapes.4.line.svg | 3 + test/svg/shapes.5.polyline.svg | 12 + test/svg/shapes.6.polygon.svg | 12 + test/svg/stroke.0.name.svg | 6 + test/svg/stroke.1.hex6.svg | 6 + test/svg/stroke.2.hex3.svg | 6 + test/svg/stroke.3.rgb.svg | 6 + test/svg/stroke.4.current-color.svg | 6 + test/svg/stroke.5.palette.svg | 6 + test/svg/stroke.6.opacity.svg | 6 + test/svg/stroke.7.color.svg | 7 + test/svg/stroke.8.width.svg | 14 + test/svg/stroke.9.cap.svg | 17 + test/svg/stroke.A.dash.svg | 27 + test/svg/stroke.B.dash-offset.svg | 31 + test/svg/stroke.C.miter.svg | 10 + test/svg/stroke.D.round.svg | 10 + test/svg/stroke.E.bevel.svg | 10 + test/svg/stroke.F.miter-limit.svg | 11 + test/svg/svg-font-template.ttx | 190 +++++ test/svg/svg-render.c | 308 ++++++++ test/svg/transform.0.translate.svg | 8 + test/svg/transform.1.scale.svg | 10 + test/svg/transform.2.rotate.svg | 10 + test/svg/transform.3.skewX.svg | 10 + test/svg/transform.4.skewY.svg | 10 + test/svg/transform.5.matrix.svg | 10 + test/svg/transform.6.multiple.svg | 16 + test/svg/transform.7.stroke.svg | 20 + 86 files changed, 4806 insertions(+) create mode 100644 test/cairo-svg-test-doc.ttx create mode 100644 test/cairo-svg-test-fill.ttx create mode 100644 test/cairo-svg-test-gradient.ttx create mode 100644 test/cairo-svg-test-path.ttx create mode 100644 test/cairo-svg-test-shapes.ttx create mode 100644 test/cairo-svg-test-stroke.ttx create mode 100644 test/cairo-svg-test-transform.ttx create mode 100644 test/ft-svg-render.c create mode 100644 test/reference/ft-svg-render-doc.ref.png create mode 100644 test/reference/ft-svg-render-fill.ref.png create mode 100644 test/reference/ft-svg-render-gradient.ref.png create mode 100644 test/reference/ft-svg-render-path.ref.png create mode 100644 test/reference/ft-svg-render-shapes.ref.png create mode 100644 test/reference/ft-svg-render-stroke.ref.png create mode 100644 test/reference/ft-svg-render-transform.ref.png create mode 100644 test/svg/README create mode 100755 test/svg/build_ttx_fonts.py create mode 100644 test/svg/doc.0.viewBox1.svg create mode 100644 test/svg/doc.1.viewBox2.svg create mode 100644 test/svg/doc.2.image.svg create mode 100644 test/svg/doc.3.image-transform.svg create mode 100644 test/svg/doc.4.clip-user.svg create mode 100644 test/svg/doc.5.clip-object.svg create mode 100644 test/svg/doc.6.clip-user2.svg create mode 100644 test/svg/doc.7.clip-object2.svg create mode 100644 test/svg/doc.8.clip-user3.svg create mode 100644 test/svg/doc.9.clip-object3.svg create mode 100644 test/svg/doc.A.g.svg create mode 100644 test/svg/fill.0.name.svg create mode 100644 test/svg/fill.1.hex6.svg create mode 100644 test/svg/fill.2.hex3.svg create mode 100644 test/svg/fill.3.rgb.svg create mode 100644 test/svg/fill.4.current-color.svg create mode 100644 test/svg/fill.5.palette.svg create mode 100644 test/svg/fill.6.opacity.svg create mode 100644 test/svg/fill.7.color.svg create mode 100644 test/svg/fill.8.rule.svg create mode 100644 test/svg/gradient.0.lin-pad.svg create mode 100644 test/svg/gradient.1.lin-reflect.svg create mode 100644 test/svg/gradient.2.lin-repeat.svg create mode 100644 test/svg/gradient.3.lin-user.svg create mode 100644 test/svg/gradient.4.lin-transform.svg create mode 100644 test/svg/gradient.5.rad-pad.svg create mode 100644 test/svg/gradient.6.rad-reflect.svg create mode 100644 test/svg/gradient.7.rad-repeat.svg create mode 100644 test/svg/gradient.8.rad-user.svg create mode 100644 test/svg/gradient.9.rad-transform.svg create mode 100644 test/svg/meson.build create mode 100644 test/svg/path.0.line.svg create mode 100644 test/svg/path.1.curve.svg create mode 100644 test/svg/path.2.quad.svg create mode 100644 test/svg/path.3.arc.svg create mode 100644 test/svg/shapes.0.rect.svg create mode 100644 test/svg/shapes.1.rounded-rect.svg create mode 100644 test/svg/shapes.2.circle.svg create mode 100644 test/svg/shapes.3.ellipse.svg create mode 100644 test/svg/shapes.4.line.svg create mode 100644 test/svg/shapes.5.polyline.svg create mode 100644 test/svg/shapes.6.polygon.svg create mode 100644 test/svg/stroke.0.name.svg create mode 100644 test/svg/stroke.1.hex6.svg create mode 100644 test/svg/stroke.2.hex3.svg create mode 100644 test/svg/stroke.3.rgb.svg create mode 100644 test/svg/stroke.4.current-color.svg create mode 100644 test/svg/stroke.5.palette.svg create mode 100644 test/svg/stroke.6.opacity.svg create mode 100644 test/svg/stroke.7.color.svg create mode 100644 test/svg/stroke.8.width.svg create mode 100644 test/svg/stroke.9.cap.svg create mode 100644 test/svg/stroke.A.dash.svg create mode 100644 test/svg/stroke.B.dash-offset.svg create mode 100644 test/svg/stroke.C.miter.svg create mode 100644 test/svg/stroke.D.round.svg create mode 100644 test/svg/stroke.E.bevel.svg create mode 100644 test/svg/stroke.F.miter-limit.svg create mode 100644 test/svg/svg-font-template.ttx create mode 100644 test/svg/svg-render.c create mode 100644 test/svg/transform.0.translate.svg create mode 100644 test/svg/transform.1.scale.svg create mode 100644 test/svg/transform.2.rotate.svg create mode 100644 test/svg/transform.3.skewX.svg create mode 100644 test/svg/transform.4.skewY.svg create mode 100644 test/svg/transform.5.matrix.svg create mode 100644 test/svg/transform.6.multiple.svg create mode 100644 test/svg/transform.7.stroke.svg diff --git a/test/cairo-svg-test-doc.ttx b/test/cairo-svg-test-doc.ttx new file mode 100644 index 000000000..c2cdb2817 --- /dev/null +++ b/test/cairo-svg-test-doc.ttx @@ -0,0 +1,689 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Svg Test Doc + + + Regular + + + Cairo Svg Test Doc Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> + <rect x="10" y="-90" width="80" height="80" + fill="none" stroke="black" stroke-width="10"/> +</svg> + + + <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg"> + <rect x="-4" y="-14" width="8" height="8" + fill="none" stroke="black" stroke-width="1"/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <image x="0" y="-1000" width="1000" height="1000" + xlink:href="data:image/png;base64, +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 +BNcsrHnv+f9Qc51Rfhz5VAAAAABJRU5ErkJggg=="/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <image x="0" y="-1000" width="1000" height="1000" + transform="scale(0.5) rotate(-45),translate(800,500)" + xlink:href="data:image/png;base64, +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 +BNcsrHnv+f9Qc51Rfhz5VAAAAABJRU5ErkJggg=="/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000"> + <clipPath id="clip" clipPathUnits="userSpaceOnUse" > + <circle cx="500" cy="-500" r="400" /> + </clipPath> + + <rect x="100" y="-900" width="800" height="800" + stroke="green" stroke-width="100" + clip-path="url(#clip)" /> +</svg> + + + <svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000"> + <clipPath id="clip" clipPathUnits="objectBoundingBox"> + <circle cx=".5" cy=".5" r=".5" /> + </clipPath> + + <rect x="100" y="-900" width="800" height="800" + stroke="green" stroke-width="100" + clip-path="url(#clip)" /> + +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000"> + <clipPath id="clip" clipPathUnits="userSpaceOnUse" > + <circle cx="500" cy="-500" r="400" /> + <rect x="100" y="-900" width="800" height="400"/> + </clipPath> + + <rect x="100" y="-900" width="800" height="800" + stroke="green" stroke-width="100" + clip-path="url(#clip)" /> +</svg> + + + <svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000"> + <clipPath id="clip" clipPathUnits="objectBoundingBox"> + <circle cx=".5" cy=".5" r=".5" /> + <rect x="0" y="0" width="1" height="0.5"/> + </clipPath> + + <rect x="100" y="-900" width="800" height="800" + stroke="green" stroke-width="100" + clip-path="url(#clip)" /> + +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000"> + <clipPath id="clip" clipPathUnits="userSpaceOnUse" > + <circle cx="500" cy="-500" r="400" /> + </clipPath> + + <clipPath id="clip2" clipPathUnits="userSpaceOnUse" > + <rect x="100" y="-900" width="800" height="400"/> + </clipPath> + + <g clip-path="url(#clip)"> + <rect x="100" y="-900" width="800" height="800" + stroke="green" stroke-width="100" + clip-path="url(#clip2)" /> + </g> +</svg> + + + <svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000"> + <clipPath id="clip" clipPathUnits="objectBoundingBox"> + <circle cx=".5" cy=".5" r=".5" /> + </clipPath> + + <clipPath id="clip2" clipPathUnits="objectBoundingBox"> + <rect x="0" y="0" width="1" height="0.5"/> + </clipPath> + + <g clip-path="url(#clip)"> + <rect x="100" y="-900" width="800" height="800" + stroke="green" stroke-width="100" + clip-path="url(#clip2)" /> + </g> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" > + <defs> + <circle id="circle" + cx="0" cy="0" r="250" /> + </defs> + + <g opacity="0.5"> + <use xlink:href="#circle" x="330" y="-500" + fill="red" /> + <use xlink:href="#circle" x="670" y="-500" + fill="green" /> + </g> +</svg> + + + + diff --git a/test/cairo-svg-test-fill.ttx b/test/cairo-svg-test-fill.ttx new file mode 100644 index 000000000..b6867ec8f --- /dev/null +++ b/test/cairo-svg-test-fill.ttx @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Svg Test Fill + + + Regular + + + Cairo Svg Test Fill Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" + fill="indigo" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" + fill="#AA55AA" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" + fill="#A5A" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" + fill="rgb (75, 0 , 130)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" + fill="currentColor" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" + fill="var(--color1, red)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" + fill="magenta" fill-opacity="0.5" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + color="green" > + <rect x="100" y="-750" width="800" height="500" + fill="currentColor" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <g transform="scale(5,5) translate(0,-150)"> + <polygon fill-rule="nonzero" + points="50,0 21,90 98,35 2,35 79,90"/> + <polygon fill-rule="evenodd" + points="150,0 121,90 198,35 102,35 179,90"/> + </g> +</svg> + + + + diff --git a/test/cairo-svg-test-gradient.ttx b/test/cairo-svg-test-gradient.ttx new file mode 100644 index 000000000..4a7a22175 --- /dev/null +++ b/test/cairo-svg-test-gradient.ttx @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Svg Test Gradient + + + Regular + + + Cairo Svg Test Gradient Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <linearGradient id="grad" x1="33%" x21="66%"> + <stop offset="0%" stop-color="blue" stop-opacity="1" /> + <stop offset="100%" stop-color="red" stop-opacity="0.5" /> + </linearGradient> + </defs> + <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <linearGradient id="grad" x1="33%" x2="66%" + spreadMethod="reflect"> + <stop offset="0%" stop-color="blue" stop-opacity="1" /> + <stop offset="100%" stop-color="red" stop-opacity="1" /> + </linearGradient> + </defs> + <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <linearGradient id="grad" x1="33%" x2="66%" + spreadMethod="repeat"> + <stop offset="0%" stop-color="blue" stop-opacity="1" /> + <stop offset="100%" stop-color="red" stop-opacity="1" /> + </linearGradient> + </defs> + <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <linearGradient id="grad" x1="300" y1="-500" x2="600" y2="-500" + gradientUnits="userSpaceOnUse"> + <stop offset="0%" stop-color="blue" stop-opacity="1" /> + <stop offset="100%" stop-color="red" stop-opacity="1" /> + </linearGradient> + </defs> + <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <linearGradient id="grad" gradientTransform="rotate(45)"> + <stop offset="0%" stop-color="blue" stop-opacity="1" /> + <stop offset="100%" stop-color="red" stop-opacity="1" /> + </linearGradient> + </defs> + <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <radialGradient id="grad" cx="50%" cy="50%" + fx="0.75" fy="0.35" r="0.5"> + <stop offset="0%" stop-color="white" stop-opacity="1" /> + <stop offset="100%" stop-color="green" stop-opacity="1" /> + </radialGradient> + </defs> + <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <radialGradient id="grad" cx="75%" cy="25%" r="33%" + fx="0.64" fy="0.18" fr="0.17" + spreadMethod="reflect" > + <stop offset="0%" stop-color="white" stop-opacity="1" /> + <stop offset="100%" stop-color="green" stop-opacity="1" /> + </radialGradient> + </defs> + <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <radialGradient id="grad" cx="75%" cy="25%" r="33%" + fx="0.64" fy="0.18" fr="0.17" + spreadMethod="repeat" > + <stop offset="0%" stop-color="white" stop-opacity="1" /> + <stop offset="100%" stop-color="green" stop-opacity="1" /> + </radialGradient> + </defs> + <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <radialGradient id="grad" cx="450" cy="-550" r="400" + fx="600" fy="-400" fr="10" + gradientUnits="userSpaceOnUse" > + <stop offset="0%" stop-color="red" stop-opacity="1" /> + <stop offset="100%" stop-color="green" stop-opacity="0.5" /> + </radialGradient> + </defs> + <rect x="0" y="-1000" width="1000" height="1000" fill="url(#grad)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <defs> + <radialGradient id="grad" cx="50%" cy="25%" + fx="0.75" fy="0.35" r="0.5" + gradientTransform="scale(1, 2)"> + <stop offset="0%" stop-color="red" stop-opacity="1" /> + <stop offset="100%" stop-color="green" stop-opacity="1" /> + </radialGradient> + </defs> + <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" /> +</svg> + + + + diff --git a/test/cairo-svg-test-path.ttx b/test/cairo-svg-test-path.ttx new file mode 100644 index 000000000..9173a537d --- /dev/null +++ b/test/cairo-svg-test-path.ttx @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Svg Test Path + + + Regular + + + Cairo Svg Test Path Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <path fill="none" stroke="black" stroke-width="20" + d="M 200 -200 + L 500 -500 + H 800 + V -200 + " /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <path fill="none" stroke="black" stroke-width="20" + d="M200,-400 + C200,-200 + 500,-200 + 500,-400 + S800,-600 + 800,-400" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <path fill="none" stroke="black" stroke-width="20" + d="M200,-300 + Q400,-50 + 600,-300 + T1000,-300" + /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <path fill="none" stroke="black" stroke-width="20" + d="M500,-500 + L 712 -712 + A300,300 0 1,0 712, -288 z" + /> +</svg> + + + + diff --git a/test/cairo-svg-test-shapes.ttx b/test/cairo-svg-test-shapes.ttx new file mode 100644 index 000000000..15a573a64 --- /dev/null +++ b/test/cairo-svg-test-shapes.ttx @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Svg Test Shapes + + + Regular + + + Cairo Svg Test Shapes Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500"/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" rx="100" ry="100"/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <circle cx="500" cy="-500" r="400"/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <ellipse cx="500" cy="-500" rx="400" ry="200"/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="200" y1="-200" x2="800" y2="-800" stroke="black" stroke-width="20"/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <polyline fill="none" stroke="black" stroke-width="20" + points="100, -100, + 300, -100, + 300, -300, + 500, -300, + 500, -500, + 700, -500 + 700, -700 + 900, -700 + 900, -900" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="500" height="500"> +<polygon points="350, -75 + 379, -161 + 469, -161 + 397, -215 + 423, -301 + 350, -250 + 277, -301 + 303, -215 + 231, -161 + 321, -161" /> +</svg> + + + + diff --git a/test/cairo-svg-test-stroke.ttx b/test/cairo-svg-test-stroke.ttx new file mode 100644 index 000000000..a403da928 --- /dev/null +++ b/test/cairo-svg-test-stroke.ttx @@ -0,0 +1,608 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Svg Test Stroke + + + Regular + + + Cairo Svg Test Stroke Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="100" + stroke="indigo" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="100" + stroke="#AA55AA" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="100" + stroke="#A5A" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="100" + stroke="rgb(75,0,130)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="100" + stroke="currentColor" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="100" + stroke="var(--color1, red)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="100" + stroke="magenta" stroke-opacity="0.5" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + color="green" > + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="100" + stroke="currentColor" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-900" x2="900" y2="-900" + fill="none" + stroke-width="100" + stroke="black" /> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="200" + stroke="black" /> + <line x1="100" y1="-100" x2="900" y2="-100" + fill="none" + stroke-width="300" + stroke="black" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-900" x2="900" y2="-900" + fill="none" + stroke-width="200" + stroke-linecap="butt" + stroke="black" /> + <line x1="100" y1="-500" x2="900" y2="-500" + fill="none" + stroke-width="200" + stroke-linecap="round" + stroke="black" /> + <line x1="100" y1="-100" x2="900" y2="-100" + fill="none" + stroke-width="200" + stroke-linecap="square" + stroke="black" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-950" x2="900" y2="-950" + fill="none" + stroke-width="100" + stroke-dasharray="none" + stroke="black" /> + <line x1="100" y1="-750" x2="900" y2="-750" + fill="none" + stroke-width="100" + stroke-dasharray="200" + stroke="black" /> + <line x1="100" y1="-550" x2="900" y2="-550" + fill="none" + stroke-width="100" + stroke-dasharray="200 50" + stroke="black" /> + <line x1="100" y1="-350" x2="900" y2="-350" + fill="none" + stroke-width="100" + stroke-dasharray="200 50 100" + stroke="black" /> + <line x1="100" y1="-150" x2="900" y2="-150" + fill="none" + stroke-width="100" + stroke-dasharray="200 50 100 150" + stroke="black" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <line x1="100" y1="-950" x2="900" y2="-950" + fill="none" + stroke-width="100" + stroke-dasharray="none" + stroke="black" /> + <line x1="100" y1="-750" x2="900" y2="-750" + fill="none" + stroke-width="100" + stroke-dasharray="200" + stroke-dashoffset="100" + stroke="black" /> + <line x1="100" y1="-550" x2="900" y2="-550" + fill="none" + stroke-width="100" + stroke-dasharray="200 50" + stroke-dashoffset="100" + stroke="black" /> + <line x1="100" y1="-350" x2="900" y2="-350" + fill="none" + stroke-width="100" + stroke-dasharray="200 50 100" + stroke-dashoffset="100" + stroke="black" /> + <line x1="100" y1="-150" x2="900" y2="-150" + fill="none" + stroke-width="100" + stroke-dasharray="200 50 100 150" + stroke-dashoffset="100" + stroke="black" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <polyline + points="100, -200 + 900, -400 + 100, -700" + fill="none" + stroke-width="200" + stroke-linejoin="miter" + stroke="black" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <polyline + points="100, -200 + 900, -400 + 100, -700" + fill="none" + stroke-width="200" + stroke-linejoin="round" + stroke="black" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <polyline + points="100, -200 + 900, -400 + 100, -700" + fill="none" + stroke-width="200" + stroke-linejoin="bevel" + stroke="black" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <polyline + points="100, -200 + 900, -400 + 100, -700" + fill="none" + stroke-width="200" + stroke-linejoin="miter" + stroke-miterlimit="2" + stroke="black" /> +</svg> + + + + diff --git a/test/cairo-svg-test-transform.ttx b/test/cairo-svg-test-transform.ttx new file mode 100644 index 000000000..1f07c05ad --- /dev/null +++ b/test/cairo-svg-test-transform.ttx @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Svg Test Transform + + + Regular + + + Cairo Svg Test Transform Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <rect id="square" width="300" height="300"/> + </defs> + <use xlink:href="#square" transform="translate(100, -900)"/> + <use xlink:href="#square" transform="translate(600, -400)"/> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <rect id="square" width="300" height="300"/> + </defs> + <use xlink:href="#square" transform="translate(100, -900)"/> + <g transform="translate(400, -400)"> + <use xlink:href="#square" transform="scale(1.5, 0.5)"/> + </g> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <rect id="square" width="300" height="300"/> + </defs> + <use xlink:href="#square" transform="translate(100, -900)"/> + <g transform="translate(600, -600)"> + <use xlink:href="#square" transform="rotate(30)"/> + </g> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <rect id="square" width="300" height="300"/> + </defs> + <use xlink:href="#square" transform="translate(100, -900)"/> + <g transform="translate(400, -400)"> + <use xlink:href="#square" transform="skewX(30)"/> + </g> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <rect id="square" width="300" height="300"/> + </defs> + <use xlink:href="#square" transform="translate(100, -900)"/> + <g transform="translate(400, -500)"> + <use xlink:href="#square" transform="skewY(30)"/> + </g> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <rect id="square" width="300" height="300"/> + </defs> + <use xlink:href="#square" transform="translate(100, -900)"/> + <g transform="translate(600, -600)"> + <use xlink:href="#square" transform="matrix(1, 0.4, -0.6, 1.1, 50, -70)"/> + </g> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <path id="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" /> + </defs> + <use xlink:href="#heart" + transform="translate(10, -650) + rotate(-10 50 100) + translate(-166 125.5) + skewX(40) + scale(1 0.5),scale(8, 8)" + fill="grey"/> + <use xlink:href="#heart" + transform="translate(300, -800),scale(6, 6)" + fill="none" stroke="red" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <circle id="c1" + cx="100" cy="100" r="80" + fill="none" + stroke="black" + stroke-width="20" /> + <circle id="c2" + cx="100" cy="100" r="80" + fill="none" + stroke="black" + stroke-width="20" + transform="scale(3,3)" /> + </defs> + + <use xlink:href="#c1" x="100" y="-900"/> + <use xlink:href="#c2" x="300" y="-700"/> + +</svg> + + + + diff --git a/test/ft-svg-render.c b/test/ft-svg-render.c new file mode 100644 index 000000000..9b0351b10 --- /dev/null +++ b/test/ft-svg-render.c @@ -0,0 +1,159 @@ +/* + * Copyright © 2022 Adrian Johnson + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Author: Adrian Johnson + */ + +#include "cairo-test.h" +#include + +#define GLYPH_SIZE 50 +#define PAD 5 +#define WIDTH (4*(GLYPH_SIZE + PAD) + PAD) +#define HEIGHT WIDTH + +//#define CLIP 1 +#define LOG_EXTENTS 1 + +static cairo_test_status_t +draw_font (cairo_t *cr, int width, int height, const char *font_file) +{ + cairo_test_status_t result; + char buf[10]; + cairo_text_extents_t extents; + cairo_font_options_t *font_options; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + result = cairo_test_ft_select_font_from_file (cr, font_file); + if (result) + return result; + + font_options = cairo_font_options_create (); + cairo_font_options_set_color_mode (font_options, CAIRO_COLOR_MODE_NO_COLOR); +// cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + cairo_set_font_size (cr, GLYPH_SIZE); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + int x = j * (GLYPH_SIZE + PAD) + PAD; + int y = i * (GLYPH_SIZE + PAD) + PAD; + int glyph_number = 4*i + j; + buf[0] = glyph_number < 10 ? '0' + glyph_number : 'A' + glyph_number - 10; + buf[1] = 0; + cairo_save (cr); + cairo_text_extents (cr, buf, &extents); +#if LOG_EXTENTS + cairo_test_log (cairo_test_get_context (cr), + "Char '%c' extents: x_bearing: %f y_bearing: %f width: %f height: %f x_advance: %f y_advance: %f\n", + buf[0], + extents.x_bearing, + extents.y_bearing, + extents.width, + extents.height, + extents.x_advance, + extents.y_advance); +#endif +#if CLIP + cairo_rectangle (cr, x, y, GLYPH_SIZE, GLYPH_SIZE); + cairo_clip (cr); +#endif + cairo_move_to (cr, x, y + GLYPH_SIZE); + cairo_show_text (cr, buf); + cairo_restore (cr); + if (cairo_status (cr)) { + cairo_test_log (cairo_test_get_context (cr), + "cairo_show_text() failed with \"%s\"\n", + buf); + return CAIRO_TEST_FAILURE; + } + } + } + + return CAIRO_TEST_SUCCESS; +} + +#define DRAW_FUNC(name) \ +static cairo_test_status_t \ +draw_##name (cairo_t *cr, int width, int height) { \ + return draw_font (cr, width, height, "cairo-svg-test-" #name ".ttf"); \ +} + +DRAW_FUNC(doc) +CAIRO_TEST (ft_svg_render_doc, + "Test SVG glyph render", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_doc) + +DRAW_FUNC(fill) +CAIRO_TEST (ft_svg_render_fill, + "Test SVG glyph render", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_fill) + +DRAW_FUNC(gradient) +CAIRO_TEST (ft_svg_render_gradient, + "Test SVG glyph render", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_gradient) + +DRAW_FUNC(path) +CAIRO_TEST (ft_svg_render_path, + "Test SVG glyph render", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_path) + +DRAW_FUNC(shapes) +CAIRO_TEST (ft_svg_render_shapes, + "Test SVG glyph render", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_shapes) + +DRAW_FUNC(stroke) +CAIRO_TEST (ft_svg_render_stroke, + "Test SVG glyph render", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_stroke) + +DRAW_FUNC(transform) +CAIRO_TEST (ft_svg_render_transform, + "Test SVG glyph render", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_transform) diff --git a/test/meson.build b/test/meson.build index 3071ac6ca..3606bfc27 100644 --- a/test/meson.build +++ b/test/meson.build @@ -431,6 +431,7 @@ test_ft_svg_font_sources = [ test_ft_svg_ttx_font_sources = [ 'ft-svg-cairo-logo.c', + 'ft-svg-render.c' ] test_gl_sources = [ @@ -525,6 +526,13 @@ ps2png_sources = [ test_ttx_fonts = [ 'cairo-logo-font.ttx', + 'cairo-svg-test-doc.ttx', + 'cairo-svg-test-fill.ttx', + 'cairo-svg-test-gradient.ttx', + 'cairo-svg-test-path.ttx', + 'cairo-svg-test-shapes.ttx', + 'cairo-svg-test-stroke.ttx', + 'cairo-svg-test-transform.ttx', ] build_any2ppm = false @@ -681,3 +689,9 @@ test('cairo', exe, suite: ['cairo-test-suite', 'slow'], workdir: meson.current_build_dir(), depends: test_depends) + +# The SVG renderer debug tools can only be built if the _cairo_debug_svg_render() +# function has been exposed by defining DEBUG_SVG_RENDER +if conf.get('HAVE_FT_SVG_DOCUMENT', 0) == 1 and cc.get_define('DEBUG_SVG_RENDER') != '' + subdir('svg') +endif diff --git a/test/reference/ft-svg-render-doc.ref.png b/test/reference/ft-svg-render-doc.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ecf7f1a758b1783456920132571cb086faf2c9 GIT binary patch literal 11069 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ͻ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 HtBC&v*|Zi( literal 0 HcmV?d00001 diff --git a/test/reference/ft-svg-render-fill.ref.png b/test/reference/ft-svg-render-fill.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..a72cdd1f29f1791043e2b0264358fe2ee942ee30 GIT binary patch literal 1641 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 Nds`=)GHdVH{{le$;AsE= literal 0 HcmV?d00001 diff --git a/test/reference/ft-svg-render-shapes.ref.png b/test/reference/ft-svg-render-shapes.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..209e0ddb3c859c218b206c9d547f50b313465524 GIT binary patch literal 3073 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 P=^6BOOtfn>9i#sWem~xC literal 0 HcmV?d00001 diff --git a/test/reference/ft-svg-render-stroke.ref.png b/test/reference/ft-svg-render-stroke.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..86f1ab9b6790a863ab116109e22e0be00837888e GIT binary patch literal 2224 zcmd5;dr%Tu9%gGpqwH~0QxlyVYg#5wYD$PQK0?zHGfhiLGvCkgEt;BIxi7-AVt#wm;$Je^_m4H`!hY>{m^{`zCxxd&@IBr9E!DV)p9g{s?v}Bz*8X+|L71 zZT_}vksVfN;L$f^y0JfKM2l`GGz3PLm7$gnmVGSjQMW4Y`8-Y*sZepN#0YYQH@QqJe?x0 zo;VdXF(H`CkT1{vkliknyW-fL9cL!(z<65)$h}s6IKd}n=2uPi4AF+IRUsu9apM~` zvcRc-jY}~fj+;5vP!lWObQV3-$Zy~Bq*rFQ{dl7h9yQ?gj&VyUd=RR~Px(!dxa3jy z69uvW-Z`pgRT8I0HiPjPGKKm0c!U%V>q<(WF zhPTv3uWEch&epW2AEf_>xwvNzv17FVEnw$8;-{KOQ&ZEa2ugW5*h>?<)qB zd0Trf93w3*E_UH#Adk+;<910j#jtS=9{Q&pP8>ZA2xR8sTe zX$x~!herZ_FOPe%S@m}x%aQ+l6zg#91zTyf)3_UK((W228qvIQqAAEc+Ly+&gePDM zum#d0s&`;l%?WLXG6L#1K=T`{cC`$Re8KM2>Wxud2>BOmrDO`iGW7U1S=4+7E(cq) z|9AcHQ6<)CDg04#OUr59H)c2@#efhm%m1sGKSuX<?6*nVFwIf5zigEJ}>#O;OWF zVXQJHy2N^Uwqu?DG*A1?gJB-0D{XPi+Cn2V_mg7|O2v1g$f+`Fu4_{&4$io1@;uN1 zZkF<)@29Kft;dU1H8hurPf>H7*c;bmO{Fd%98TtVsaz342hobO;^n|VUhR~CMx)L5 z<{Z(WGD=80Al}yl7${vt^7zV!5^Rc_Uw|P_!NDJ~sKs%JE>-&a`ktPiM)kppbu%lS zv~?k-+I>MNq`;_DYFbE$K#_{#0@A@Zr+)GeFolrkf~Tjaulo3Orf+_eZ+5P zyTrFtJ!792eo0TpAd%+nMykQ}3VQ~zKxZ7E>A24%JY$}0VF)oniW|dAL@EiT?q*E zx%PI;`*~&@m96lP%`C6c>m<=}ZEY>UgkIt=jKT$Y*0gbkhQ1l@XB#SL5F!YT7hrf%os7azHqpm2*lH+T;`{$3n{^(jb zM*sPhqj!J<{N@-YDQP`tzwV4L8QB`7rYIsf>*gb{re=&OySypS8HbZ7>PEz&8k*!2 zjVxL7dW|Kz<$sQq#AFjGA%u82hnIWUSO=MoAPufbBw8HNZgoiHLG8h$Y&-DW6d=J2 e^xv_y<0v=fz$5+MUld;uz`3(7_Vu=YS$_vSHCfjH literal 0 HcmV?d00001 diff --git a/test/reference/ft-svg-render-transform.ref.png b/test/reference/ft-svg-render-transform.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..dcc372aacd4cc46791a77a8a39e6f049e08337c6 GIT binary patch literal 4248 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 literal 0 HcmV?d00001 diff --git a/test/svg/README b/test/svg/README new file mode 100644 index 000000000..c4504dc9b --- /dev/null +++ b/test/svg/README @@ -0,0 +1,22 @@ +build_ttx_fonts.py +================== +Is used to create the test/*.ttx files used for testing the SVG glyph renderer. + +build_ttx_fonts.py will look for files of the form + +...svg + +in the input directory, and using svg-font-template.ttx, create .ttx +files that contain one glyph for each svg file. Each .ttx will contain +a glyph for each svg with the matching prefix. Each glyphs will be mapped +to the i nthe svg filename. The must be one of 0-9,A-F. + +svg-render.c +============ +svg-render renders SVG files using both librsvg and cairo-svg-glyph-render.c. +It is used for testing cairo-svg-glyph-render.c during development. + +To use svg-render, cairo must be built with CFLAGS="-DDEBUG_SVG_RENDER" to enable the +_cairo_debug_svg_render() function. + + diff --git a/test/svg/build_ttx_fonts.py b/test/svg/build_ttx_fonts.py new file mode 100755 index 000000000..d7e7f5b8f --- /dev/null +++ b/test/svg/build_ttx_fonts.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 + +# Build the ttx cairo svg test fonts from svg files +# The svg files use the naming convention +# ...svg +# eg "circle.A.cx_cy_r.svg" +# +# is use to create the name of the ttx font. +# is a ascii hex character (uppercase) that the font fill map to the SVG description. +# is a descriptive name of the SVG file and is not used to build the font… +# +# This script looks for all files matching the above pattern and +# creates one ttx font for each unique . Each font will +# contain up to 16 characters. The SVG description of each character +# and the character that maps to the SVG description is obtained from +# the SVG file beginning with .. + +import argparse +import os +import re +import sys +import xml.dom.minidom + +TEMPLATE_FILE="svg-font-template.ttx" + +glyph_names = { + '0': 'zero', + '1': 'one', + '2': 'two', + '3': 'three', + '4': 'four', + '5': 'five', + '6': 'six', + '7': 'seven', + '8': 'eight', + '9': 'nine', + 'A': 'A', + 'B': 'B', + 'C': 'C', + 'D': 'D', + 'E': 'E', + 'F': 'F' +} + +# files is list of (char, filename) +def build_font(font_name, files, in_dir, out_dir, no_reformat): + name = "cairo-svg-test-" + font_name + doc = xml.dom.minidom.parse(os.path.join(in_dir, TEMPLATE_FILE)) + glyph_id = 1 + text_nl = doc.createTextNode('\n\n') + for f in sorted(files): + glyph_name = glyph_names[f[0]] + + glyph_order = doc.getElementsByTagName('GlyphOrder')[0] + glyph_id_elem = doc.createElement('GlyphID') + glyph_id_elem.setAttribute('id', str(glyph_id)) + glyph_id_elem.setAttribute('name', glyph_name) + glyph_order.appendChild(glyph_id_elem) + glyph_order.appendChild(text_nl) + + hmtx = doc.getElementsByTagName('hmtx')[0] + mtx = doc.createElement('mtx') + mtx.setAttribute('name', glyph_name) + mtx.setAttribute('width', '1100') + mtx.setAttribute('lsb', '0') + hmtx.appendChild(mtx) + + cmap_format = doc.getElementsByTagName('cmap_format_4')[0] + map = doc.createElement('map') + map.setAttribute('code', hex(ord(f[0]))) + map.setAttribute('name', glyph_name) + cmap_format.appendChild(map) + + glyf = doc.getElementsByTagName('glyf')[0] + tt_glyph = doc.createElement('TTGlyph') + tt_glyph.setAttribute('name', glyph_name) + glyf.appendChild(tt_glyph) + contour = doc.createElement('contour') + tt_glyph.appendChild(contour) + pt = doc.createElement('pt') + pt.setAttribute('x', "0") + pt.setAttribute('y', "0") + pt.setAttribute('on', "1") + contour.appendChild(pt) + pt = doc.createElement('pt') + pt.setAttribute('x', "0") + pt.setAttribute('y', "1000") + pt.setAttribute('on', "1") + contour.appendChild(pt) + pt = doc.createElement('pt') + pt.setAttribute('x', "1000") + pt.setAttribute('y', "1000") + pt.setAttribute('on', "1") + contour.appendChild(pt) + pt = doc.createElement('pt') + pt.setAttribute('x', "1000") + pt.setAttribute('y', "0") + pt.setAttribute('on', "1") + contour.appendChild(pt) + instructions = doc.createElement('instructions') + tt_glyph.appendChild(instructions) + + svg = doc.getElementsByTagName('SVG')[0] + svgdoc = doc.createElement('svgDoc') + svgdoc.setAttribute('startGlyphID', str(glyph_id)) + svgdoc.setAttribute('endGlyphID', str(glyph_id)) + with open(os.path.join(in_dir, f[1]), 'r') as svg_file: + svg_data = svg_file.read() + cdata = doc.createCDATASection(svg_data) + svgdoc.appendChild(cdata) + svg.appendChild(svgdoc) + glyph_id += 1 + + name_record = doc.getElementsByTagName('namerecord')[0] + name_record.firstChild.replaceWholeText(name.replace("-", " ").title()) + name_record = doc.getElementsByTagName('namerecord')[2] + name_record.firstChild.replaceWholeText(name.replace("-", " ").title() + " Regular") + + ttx_filename = os.path.join(out_dir, name + '.ttx') + ttf_filename = os.path.join(out_dir, name + '.ttf') + with open(ttx_filename, 'w') as ttx_file: + doc.writexml(ttx_file) + + if not no_reformat: + # Convert to ttf and back to ttx. This reformats the ttx file + # which allows better quality diffs. + if os.path.exists(ttf_filename): + os.remove(ttf_filename) + os.system("ttx " + ttx_filename) + os.remove(ttx_filename) + os.system("ttx " + ttf_filename) + os.remove(ttf_filename) + +def build_file_list(in_dir): + dict = {} + regex_prog = re.compile(r"([^\.]+)\.(.)\.[^\.]+\.svg", re.ASCII) + files = os.listdir(in_dir) + for f in files: + match = regex_prog.fullmatch(f) + if match: + fontname = match.group(1) + character = match.group(2) + if (fontname not in dict): + dict[fontname] = [(character, f)]; + else: + dict[fontname].append((character, f)) + return dict + +if __name__=='__main__': + parser = argparse.ArgumentParser(description='Build ttx fonts.') + parser.add_argument("-i", nargs=1, metavar="indir", default=["."], help="Input directory") + parser.add_argument("-o", nargs=1, metavar="outdir", default=["."], help="Output directory") + parser.add_argument("-n", action='store_true', help="Don't reformat the output.") + args = parser.parse_args() + in_dir = args.i[0] + out_dir = args.o[0] + no_reformat = args.n + file_list = build_file_list(in_dir) + font_name = None + for key, value in file_list.items(): + build_font(key, value, in_dir, out_dir, no_reformat) diff --git a/test/svg/doc.0.viewBox1.svg b/test/svg/doc.0.viewBox1.svg new file mode 100644 index 000000000..c1f55a4eb --- /dev/null +++ b/test/svg/doc.0.viewBox1.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/doc.1.viewBox2.svg b/test/svg/doc.1.viewBox2.svg new file mode 100644 index 000000000..b8f976ba9 --- /dev/null +++ b/test/svg/doc.1.viewBox2.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/doc.2.image.svg b/test/svg/doc.2.image.svg new file mode 100644 index 000000000..1d03842a9 --- /dev/null +++ b/test/svg/doc.2.image.svg @@ -0,0 +1,121 @@ + + + diff --git a/test/svg/doc.3.image-transform.svg b/test/svg/doc.3.image-transform.svg new file mode 100644 index 000000000..90e5ecb1a --- /dev/null +++ b/test/svg/doc.3.image-transform.svg @@ -0,0 +1,122 @@ + + + diff --git a/test/svg/doc.4.clip-user.svg b/test/svg/doc.4.clip-user.svg new file mode 100644 index 000000000..26cdd818a --- /dev/null +++ b/test/svg/doc.4.clip-user.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/test/svg/doc.5.clip-object.svg b/test/svg/doc.5.clip-object.svg new file mode 100644 index 000000000..732911590 --- /dev/null +++ b/test/svg/doc.5.clip-object.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/test/svg/doc.6.clip-user2.svg b/test/svg/doc.6.clip-user2.svg new file mode 100644 index 000000000..a68c1c42f --- /dev/null +++ b/test/svg/doc.6.clip-user2.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/test/svg/doc.7.clip-object2.svg b/test/svg/doc.7.clip-object2.svg new file mode 100644 index 000000000..f5c153dd1 --- /dev/null +++ b/test/svg/doc.7.clip-object2.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/test/svg/doc.8.clip-user3.svg b/test/svg/doc.8.clip-user3.svg new file mode 100644 index 000000000..8ff61d593 --- /dev/null +++ b/test/svg/doc.8.clip-user3.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/test/svg/doc.9.clip-object3.svg b/test/svg/doc.9.clip-object3.svg new file mode 100644 index 000000000..b291df79f --- /dev/null +++ b/test/svg/doc.9.clip-object3.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/test/svg/doc.A.g.svg b/test/svg/doc.A.g.svg new file mode 100644 index 000000000..bdaade725 --- /dev/null +++ b/test/svg/doc.A.g.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/test/svg/fill.0.name.svg b/test/svg/fill.0.name.svg new file mode 100644 index 000000000..e377b8827 --- /dev/null +++ b/test/svg/fill.0.name.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/fill.1.hex6.svg b/test/svg/fill.1.hex6.svg new file mode 100644 index 000000000..04759d78a --- /dev/null +++ b/test/svg/fill.1.hex6.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/fill.2.hex3.svg b/test/svg/fill.2.hex3.svg new file mode 100644 index 000000000..9f9bce580 --- /dev/null +++ b/test/svg/fill.2.hex3.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/fill.3.rgb.svg b/test/svg/fill.3.rgb.svg new file mode 100644 index 000000000..c18b03bb5 --- /dev/null +++ b/test/svg/fill.3.rgb.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/fill.4.current-color.svg b/test/svg/fill.4.current-color.svg new file mode 100644 index 000000000..cf77d65a6 --- /dev/null +++ b/test/svg/fill.4.current-color.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/fill.5.palette.svg b/test/svg/fill.5.palette.svg new file mode 100644 index 000000000..53ea97512 --- /dev/null +++ b/test/svg/fill.5.palette.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/fill.6.opacity.svg b/test/svg/fill.6.opacity.svg new file mode 100644 index 000000000..59b4eb41f --- /dev/null +++ b/test/svg/fill.6.opacity.svg @@ -0,0 +1,4 @@ + + + diff --git a/test/svg/fill.7.color.svg b/test/svg/fill.7.color.svg new file mode 100644 index 000000000..745b2e881 --- /dev/null +++ b/test/svg/fill.7.color.svg @@ -0,0 +1,5 @@ + + + diff --git a/test/svg/fill.8.rule.svg b/test/svg/fill.8.rule.svg new file mode 100644 index 000000000..366ff6760 --- /dev/null +++ b/test/svg/fill.8.rule.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/test/svg/gradient.0.lin-pad.svg b/test/svg/gradient.0.lin-pad.svg new file mode 100644 index 000000000..0ec54092f --- /dev/null +++ b/test/svg/gradient.0.lin-pad.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/svg/gradient.1.lin-reflect.svg b/test/svg/gradient.1.lin-reflect.svg new file mode 100644 index 000000000..9e3e50cb9 --- /dev/null +++ b/test/svg/gradient.1.lin-reflect.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/test/svg/gradient.2.lin-repeat.svg b/test/svg/gradient.2.lin-repeat.svg new file mode 100644 index 000000000..1f023f5e1 --- /dev/null +++ b/test/svg/gradient.2.lin-repeat.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/test/svg/gradient.3.lin-user.svg b/test/svg/gradient.3.lin-user.svg new file mode 100644 index 000000000..fc90328f0 --- /dev/null +++ b/test/svg/gradient.3.lin-user.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/test/svg/gradient.4.lin-transform.svg b/test/svg/gradient.4.lin-transform.svg new file mode 100644 index 000000000..bc8f5b622 --- /dev/null +++ b/test/svg/gradient.4.lin-transform.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/svg/gradient.5.rad-pad.svg b/test/svg/gradient.5.rad-pad.svg new file mode 100644 index 000000000..b631ddc73 --- /dev/null +++ b/test/svg/gradient.5.rad-pad.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/test/svg/gradient.6.rad-reflect.svg b/test/svg/gradient.6.rad-reflect.svg new file mode 100644 index 000000000..b6fea76be --- /dev/null +++ b/test/svg/gradient.6.rad-reflect.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/test/svg/gradient.7.rad-repeat.svg b/test/svg/gradient.7.rad-repeat.svg new file mode 100644 index 000000000..63d138d2a --- /dev/null +++ b/test/svg/gradient.7.rad-repeat.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/test/svg/gradient.8.rad-user.svg b/test/svg/gradient.8.rad-user.svg new file mode 100644 index 000000000..e1d9c61f0 --- /dev/null +++ b/test/svg/gradient.8.rad-user.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/test/svg/gradient.9.rad-transform.svg b/test/svg/gradient.9.rad-transform.svg new file mode 100644 index 000000000..4b90aaaf6 --- /dev/null +++ b/test/svg/gradient.9.rad-transform.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/test/svg/meson.build b/test/svg/meson.build new file mode 100644 index 000000000..b2b017d79 --- /dev/null +++ b/test/svg/meson.build @@ -0,0 +1,5 @@ +if librsvg_dep.found() + executable('svg-render', + 'svg-render.c', + dependencies: [libcairo_dep, librsvg_dep]) +endif diff --git a/test/svg/path.0.line.svg b/test/svg/path.0.line.svg new file mode 100644 index 000000000..19d50914a --- /dev/null +++ b/test/svg/path.0.line.svg @@ -0,0 +1,8 @@ + + + diff --git a/test/svg/path.1.curve.svg b/test/svg/path.1.curve.svg new file mode 100644 index 000000000..49c252ac8 --- /dev/null +++ b/test/svg/path.1.curve.svg @@ -0,0 +1,9 @@ + + + diff --git a/test/svg/path.2.quad.svg b/test/svg/path.2.quad.svg new file mode 100644 index 000000000..00a0dde57 --- /dev/null +++ b/test/svg/path.2.quad.svg @@ -0,0 +1,8 @@ + + + diff --git a/test/svg/path.3.arc.svg b/test/svg/path.3.arc.svg new file mode 100644 index 000000000..f177a72af --- /dev/null +++ b/test/svg/path.3.arc.svg @@ -0,0 +1,7 @@ + + + diff --git a/test/svg/shapes.0.rect.svg b/test/svg/shapes.0.rect.svg new file mode 100644 index 000000000..17db34649 --- /dev/null +++ b/test/svg/shapes.0.rect.svg @@ -0,0 +1,3 @@ + + + diff --git a/test/svg/shapes.1.rounded-rect.svg b/test/svg/shapes.1.rounded-rect.svg new file mode 100644 index 000000000..717470bee --- /dev/null +++ b/test/svg/shapes.1.rounded-rect.svg @@ -0,0 +1,3 @@ + + + diff --git a/test/svg/shapes.2.circle.svg b/test/svg/shapes.2.circle.svg new file mode 100644 index 000000000..3c07bad83 --- /dev/null +++ b/test/svg/shapes.2.circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/test/svg/shapes.3.ellipse.svg b/test/svg/shapes.3.ellipse.svg new file mode 100644 index 000000000..67260a404 --- /dev/null +++ b/test/svg/shapes.3.ellipse.svg @@ -0,0 +1,3 @@ + + + diff --git a/test/svg/shapes.4.line.svg b/test/svg/shapes.4.line.svg new file mode 100644 index 000000000..58de42947 --- /dev/null +++ b/test/svg/shapes.4.line.svg @@ -0,0 +1,3 @@ + + + diff --git a/test/svg/shapes.5.polyline.svg b/test/svg/shapes.5.polyline.svg new file mode 100644 index 000000000..0cc5c383c --- /dev/null +++ b/test/svg/shapes.5.polyline.svg @@ -0,0 +1,12 @@ + + + diff --git a/test/svg/shapes.6.polygon.svg b/test/svg/shapes.6.polygon.svg new file mode 100644 index 000000000..56bda0705 --- /dev/null +++ b/test/svg/shapes.6.polygon.svg @@ -0,0 +1,12 @@ + + + diff --git a/test/svg/stroke.0.name.svg b/test/svg/stroke.0.name.svg new file mode 100644 index 000000000..f2a926475 --- /dev/null +++ b/test/svg/stroke.0.name.svg @@ -0,0 +1,6 @@ + + + diff --git a/test/svg/stroke.1.hex6.svg b/test/svg/stroke.1.hex6.svg new file mode 100644 index 000000000..89f2b1b38 --- /dev/null +++ b/test/svg/stroke.1.hex6.svg @@ -0,0 +1,6 @@ + + + diff --git a/test/svg/stroke.2.hex3.svg b/test/svg/stroke.2.hex3.svg new file mode 100644 index 000000000..a8565a7b6 --- /dev/null +++ b/test/svg/stroke.2.hex3.svg @@ -0,0 +1,6 @@ + + + diff --git a/test/svg/stroke.3.rgb.svg b/test/svg/stroke.3.rgb.svg new file mode 100644 index 000000000..42e7514e4 --- /dev/null +++ b/test/svg/stroke.3.rgb.svg @@ -0,0 +1,6 @@ + + + diff --git a/test/svg/stroke.4.current-color.svg b/test/svg/stroke.4.current-color.svg new file mode 100644 index 000000000..9d645b881 --- /dev/null +++ b/test/svg/stroke.4.current-color.svg @@ -0,0 +1,6 @@ + + + diff --git a/test/svg/stroke.5.palette.svg b/test/svg/stroke.5.palette.svg new file mode 100644 index 000000000..1262a7ba0 --- /dev/null +++ b/test/svg/stroke.5.palette.svg @@ -0,0 +1,6 @@ + + + diff --git a/test/svg/stroke.6.opacity.svg b/test/svg/stroke.6.opacity.svg new file mode 100644 index 000000000..b84d1bdc9 --- /dev/null +++ b/test/svg/stroke.6.opacity.svg @@ -0,0 +1,6 @@ + + + diff --git a/test/svg/stroke.7.color.svg b/test/svg/stroke.7.color.svg new file mode 100644 index 000000000..952f48261 --- /dev/null +++ b/test/svg/stroke.7.color.svg @@ -0,0 +1,7 @@ + + + diff --git a/test/svg/stroke.8.width.svg b/test/svg/stroke.8.width.svg new file mode 100644 index 000000000..bb9edea90 --- /dev/null +++ b/test/svg/stroke.8.width.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/test/svg/stroke.9.cap.svg b/test/svg/stroke.9.cap.svg new file mode 100644 index 000000000..35046446c --- /dev/null +++ b/test/svg/stroke.9.cap.svg @@ -0,0 +1,17 @@ + + + + + diff --git a/test/svg/stroke.A.dash.svg b/test/svg/stroke.A.dash.svg new file mode 100644 index 000000000..2be5a1d90 --- /dev/null +++ b/test/svg/stroke.A.dash.svg @@ -0,0 +1,27 @@ + + + + + + + diff --git a/test/svg/stroke.B.dash-offset.svg b/test/svg/stroke.B.dash-offset.svg new file mode 100644 index 000000000..f7623ea84 --- /dev/null +++ b/test/svg/stroke.B.dash-offset.svg @@ -0,0 +1,31 @@ + + + + + + + diff --git a/test/svg/stroke.C.miter.svg b/test/svg/stroke.C.miter.svg new file mode 100644 index 000000000..1dc4ee6a7 --- /dev/null +++ b/test/svg/stroke.C.miter.svg @@ -0,0 +1,10 @@ + + + diff --git a/test/svg/stroke.D.round.svg b/test/svg/stroke.D.round.svg new file mode 100644 index 000000000..3e4c6236f --- /dev/null +++ b/test/svg/stroke.D.round.svg @@ -0,0 +1,10 @@ + + + diff --git a/test/svg/stroke.E.bevel.svg b/test/svg/stroke.E.bevel.svg new file mode 100644 index 000000000..25d9e3803 --- /dev/null +++ b/test/svg/stroke.E.bevel.svg @@ -0,0 +1,10 @@ + + + diff --git a/test/svg/stroke.F.miter-limit.svg b/test/svg/stroke.F.miter-limit.svg new file mode 100644 index 000000000..14357f0b4 --- /dev/null +++ b/test/svg/stroke.F.miter-limit.svg @@ -0,0 +1,11 @@ + + + diff --git a/test/svg/svg-font-template.ttx b/test/svg/svg-font-template.ttx new file mode 100644 index 000000000..715074dda --- /dev/null +++ b/test/svg/svg-font-template.ttx @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Font Template + + + Regular + + + Cairo Font Template Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + + + + diff --git a/test/svg/svg-render.c b/test/svg/svg-render.c new file mode 100644 index 000000000..8f67ebdc2 --- /dev/null +++ b/test/svg/svg-render.c @@ -0,0 +1,308 @@ +/* + * Copyright © 2016 Adrian Johnson + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Author: Adrian Johnson + */ + +/* Compilation: + * Build cairo with -DDEBUG_SVG_RENDER + * gcc -o svg-render svg-render.c `pkg-config --cflags --libs cairo librsvg` + */ + +/* svg-render - render SVG files using both the cairo glyph renderer and librsvg. + * + * This allows testing the cairo SVG test cases before assembling them into an SVG font. + * Usage: + * svg-render [-b] [-s] [-g ] [-e ] input.svg + * + * Output is written to input.cairo.png and input.rsvg.png. + * + * -b print bounding box. + * -s Use standard SVG viewport. See below. + * -g render glyph with id + * -e set the EM size. The default is 1000. + * + * SVG Glyphs are assumed to be wholely within the view port. + */ + +#include +#include +#include +#include + +typedef enum { CAIRO_SVG, LIBRSVG } svg_renderer_t; + +/* output image size */ +#define WIDTH 1000 +#define HEIGHT 1000 + +static cairo_bool_t bbox = FALSE; +static cairo_bool_t standard_svg = FALSE; +static const char *glyph_id = NULL; +static int em_size = 1000; + +cairo_bool_t +_cairo_debug_svg_render (cairo_t *cr, + const char *svg_document, + const char *element, + double units_per_em, + int debug_level); + +static void +cairo_render (const char *svg_document, cairo_t *cr) +{ + if (!_cairo_debug_svg_render (cr, svg_document, glyph_id, em_size, 2)) + printf("_cairo_debug_svg_render() failed\n"); +} + +static void +librsvg_render (const char *svg_document, cairo_t *cr) +{ + gboolean has_width; + gboolean has_height; + gboolean has_viewbox; + RsvgLength svg_width; + RsvgLength svg_height; + RsvgRectangle svg_viewbox; + RsvgRectangle viewport; + double width, height; + GError *error = NULL; + + RsvgHandle *handle = rsvg_handle_new_from_data ((guint8 *)svg_document, + strlen(svg_document), + &error); + if (!handle) { + printf ("Could not load: %s", error->message); + return; + } + + /* Default width if not specified is EM Square */ + width = em_size; + height = em_size; + + /* Get width/height if specified. */ + rsvg_handle_get_intrinsic_dimensions(handle, + &has_width, + &svg_width, + &has_height, + &svg_height, + &has_viewbox, + &svg_viewbox); + if (has_width) + width = svg_width.length; + + if (has_height) + height = svg_height.length; + + /* We set the viewport for the call rsvg_handle_render_layer() to + * width/height. That way if either dimension is not specified in + * the SVG it will be inherited from the viewport we provide. + * + * As this scales up the rendered dimensions by width/height we + * need to undo this scaling to get a unit square scale that + * matches the cairo SVG renderer scale. The OpenType SVG spec + * does not say what to do if width != height. In this case we + * will just use a uniform scale that ensures the viewport fits in + * the unit square and also center it. + */ + + if (width > height) { + cairo_scale (cr, 1.0/width, 1.0/width); + cairo_translate (cr, 0, (width - height)/2.0); + } else { + cairo_scale (cr, 1.0/height, 1.0/height); + cairo_translate (cr, (height - width)/2.0, 0); + } + + viewport.x = 0; + viewport.y = 0; + viewport.width = width; + viewport.height = height; + if (!rsvg_handle_render_layer (handle, cr, glyph_id, &viewport, &error)) { + printf ("librsvg render failed: %s", error->message); + return; + } +} + +static void +render_svg (const char *svg_document, svg_renderer_t renderer, const char* out_file) +{ + double x, y, w, h; + + cairo_surface_t *recording = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + cairo_t *cr = cairo_create (recording); + + /* Scale up to image size when recording to reduce rounding errors + * in cairo_recording_surface_ink_extents() + */ + cairo_scale (cr, WIDTH, HEIGHT); + + if (renderer == CAIRO_SVG) { + cairo_render (svg_document, cr); + } else { + librsvg_render (svg_document, cr); + } + cairo_destroy (cr); + + if (bbox) { + cairo_recording_surface_ink_extents (recording, &x, &y, &w, &h); + if (renderer == CAIRO_SVG) + printf("cairo "); + else + printf("librsvg"); + + printf(" bbox left: %d right: %d top: %d bottom: %d\n", + (int)floor(x), + (int)ceil(x + w), + (int)floor(y), + (int)ceil(y + h)); + } + + cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT); + cr = cairo_create (surface); + + /* If rendering a glyph need to translate base line to bottom of image */ + if (standard_svg) + cairo_set_source_surface (cr, recording, 0, 0); + else + cairo_set_source_surface (cr, recording, 0, HEIGHT); + + cairo_paint (cr); + + cairo_surface_write_to_png (surface, out_file); + cairo_surface_destroy (surface); +} + +static char * +create_output_name (const char *svg_file, svg_renderer_t renderer) +{ + char buf[1000]; + int len; + + strcpy (buf, svg_file); + len = strlen (buf); + + if (strlen (buf) > 5 && strcmp (buf + len - 4, ".svg") == 0) + buf[len - 4] = 0; + + if (renderer == CAIRO_SVG) + strcat (buf, ".cairo.png"); + else + strcat (buf, ".rsvg.png"); + + return strdup (buf); +} + +static char * +read_file(const char *filename) +{ + FILE *fp; + int len; + char *data; + + fp = fopen (filename, "r"); + if (fp == NULL) + return NULL; + + fseek (fp, 0, SEEK_END); + len = ftell(fp); + rewind (fp); + data = malloc (len + 1); + if (fread(data, len, 1, fp) != 1) + return NULL; + data[len] = 0; + fclose(fp); + return data; +} + +static void +usage_and_exit() +{ + printf ("svg-render [-b] [-s] [-g ] [-e ] input.svg\n"); + exit (1); +} + +int +main(int argc, char **argv) +{ + const char *input_file = NULL; + char *svg_document; + char *output_file; + + argc--; + argv++; + while (argc > 0) { + if (strcmp (argv[0], "-b") == 0) { + bbox = TRUE; + argc--; + argv++; + } else if (strcmp (argv[0], "-s") == 0) { + standard_svg = TRUE; + argc--; + argv++; + } else if (strcmp (argv[0], "-g") == 0) { + if (argc > 1) { + glyph_id = argv[1]; + argc -= 2; + argv += 2; + } else { + usage_and_exit(); + } + } else if (strcmp (argv[0], "-e") == 0) { + if (argc > 1) { + em_size = atoi (argv[1]); + if (em_size <= 0) { + usage_and_exit(); + } + argc -= 2; + argv += 2; + } else { + usage_and_exit(); + } + } else { + input_file = argv[0]; + argc--; + argv++; + } + } + if (!input_file) + usage_and_exit(); + + svg_document = read_file (input_file); + if (!svg_document) { + printf("error reading file %s\n", input_file); + exit (1); + } + + output_file = create_output_name (input_file, CAIRO_SVG); + render_svg (svg_document, CAIRO_SVG, output_file); + free (output_file); + + output_file = create_output_name (input_file, LIBRSVG); + render_svg (svg_document, LIBRSVG, output_file); + free (output_file); + + free (svg_document); + + return 0; +} diff --git a/test/svg/transform.0.translate.svg b/test/svg/transform.0.translate.svg new file mode 100644 index 000000000..5d9555673 --- /dev/null +++ b/test/svg/transform.0.translate.svg @@ -0,0 +1,8 @@ + + + + + + + diff --git a/test/svg/transform.1.scale.svg b/test/svg/transform.1.scale.svg new file mode 100644 index 000000000..b7742fc80 --- /dev/null +++ b/test/svg/transform.1.scale.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/test/svg/transform.2.rotate.svg b/test/svg/transform.2.rotate.svg new file mode 100644 index 000000000..926ae63fc --- /dev/null +++ b/test/svg/transform.2.rotate.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/test/svg/transform.3.skewX.svg b/test/svg/transform.3.skewX.svg new file mode 100644 index 000000000..f7555534d --- /dev/null +++ b/test/svg/transform.3.skewX.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/test/svg/transform.4.skewY.svg b/test/svg/transform.4.skewY.svg new file mode 100644 index 000000000..cd62c8a8a --- /dev/null +++ b/test/svg/transform.4.skewY.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/test/svg/transform.5.matrix.svg b/test/svg/transform.5.matrix.svg new file mode 100644 index 000000000..643fbe36b --- /dev/null +++ b/test/svg/transform.5.matrix.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/test/svg/transform.6.multiple.svg b/test/svg/transform.6.multiple.svg new file mode 100644 index 000000000..90c7b3054 --- /dev/null +++ b/test/svg/transform.6.multiple.svg @@ -0,0 +1,16 @@ + + + + + + + diff --git a/test/svg/transform.7.stroke.svg b/test/svg/transform.7.stroke.svg new file mode 100644 index 000000000..f56b24dfe --- /dev/null +++ b/test/svg/transform.7.stroke.svg @@ -0,0 +1,20 @@ + + + + + + + + + +